OutlookExpressをプログラムから扱うメモ

この手の情報が全然無いので、試行錯誤しながらやってみた。

まず必要なのは imnact.idl(古いバージョンだと、imnact.h?.idlファイルはmidlコマンドで適当なヘッダを生成するためのファイル、ととらえたらいいのかな?)だけど、システムとかVisualStudioのPlatformSDKを探しても見つからない。なんでやーと思いつつ、Yahooでファイル名を頼りに検索してみると、やっぱPlatformSDKにあるらしい。ちなみに、Google先生で検索すると、プログラミング時に発生するエラーがらみの情報で、ファイルに関する情報は出なかった。Yahooもたまには使えるな、とちょっと見直す。でも、VS付属のPlatformSDKにはファイルが無いから、ダウンロードせねば。
で、PlatformSDKを探してみる。DownloadCenterからPlatformSDKを探してみるけど、for XPなんて言うXP専用のやつはもうなくて、WindowsServer2003R2のやつと統合されてるっぽい。最初探したけど見あたらなくてびっくりした。

それから、面倒なので全部インストール。

ようやく、ヘッダファイルが手に入る。だけど使い方がわからんなぁ。

とりあえず、VSでC++コマンドラインプログラムのプロジェクトを新しく作り、ヘッダーファイルのペインに、imnact.idlを追加して、main関数にHello World!を書いてビルドしてみると、プロジェクトのフォルダにimnact_h.h/imnact_i.c/imnact_p.cというファイルが生成される。こいつらは、ビルドごとに新しく生成されてウザイので、ヘッダーファイルからimnact.idlを削除して、imnact_h.hを追加する。


マイクロソフトのページhttp://msdn2.microsoft.com/en-us/library/ms712735.aspxを参照すると、このImnAccountManagerを最初に作るらしい。っていうので、ページに書いてあるとおり、CoCreateInstanceをしてみる。

#include "stdafx.h"
#include "imnact_h.h"

int _tmain(int argc, _TCHAR* argv[])
{
	HRESULT hr;
	hr = CoCreateInstance(	CLSID_ImnAccountManager, NULL, CLSCTX_INPROC_SERVER,
				IID_IImnAccountManager, (LPVOID *)&pAccountManager);

	printf("Result: %x\n", hr);

	printf("Hello world!");
	
	return 0;
}

ビルドすると・・・

mailchk.obj : error LNK2001: 外部シンボル "_CLSID_ImnAccountManager" は未解決です。
mailchk.obj : error LNK2001: 外部シンボル "_IID_IImnAccountManager" は未解決です。
Debug/mailchk.exe : fatal error LNK1120: 外部参照 2 が未解決です。

ぬはっ。
まだ何か足りないらしい。よく分からないので、さっき生成されたimnact_i.cを見てみると、なにやらプログラムの中でIID_IImnAccountManagerを定義しているみたいだ。うーん、ヘッダの中でも定義されてたハズだけど・・・と思いつつ、プログラム側にimnact_i.cのソースをそのまま持ってくる。

#include "stdafx.h"
#include "imnact_h.h"

/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */

/* link this file in with the server and any clients */


 /* File created by MIDL compiler version 6.00.0361 */
/* at Mon Aug 13 01:21:08 2007
 */
/* Compiler settings for .\imnact.idl:
    Oicf, W1, Zp8, env=Win32 (32b run)
    protocol : dce , ms_ext, c_ext, robust
    error checks: allocation ref bounds_check enum stub_data 
    VC __declspec() decoration level: 
         __declspec(uuid()), __declspec(selectany), __declspec(novtable)
         DECLSPEC_UUID(), MIDL_INTERFACE()
*1186983637*/
//@@MIDL_FILE_HEADING(  )

#if !defined(_M_IA64) && !defined(_M_AMD64)


#pragma warning( disable: 4049 )  /* more than 64k source lines */


#ifdef __cplusplus
extern "C"{
#endif 


#include <rpc.h>
#include <rpcndr.h>

#ifdef _MIDL_USE_GUIDDEF_

#ifndef INITGUID
#define INITGUID
#include <guiddef.h>
#undef INITGUID
#else
#include <guiddef.h>
#endif

#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
        DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)

#else // !_MIDL_USE_GUIDDEF_

#ifndef __IID_DEFINED__
#define __IID_DEFINED__

typedef struct _IID
{
    unsigned long x;
    unsigned short s1;
    unsigned short s2;
    unsigned char  c[8];
} IID;

#endif // __IID_DEFINED__

#ifndef CLSID_DEFINED
#define CLSID_DEFINED
typedef IID CLSID;
#endif // CLSID_DEFINED

#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
        const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}

#endif !_MIDL_USE_GUIDDEF_

MIDL_DEFINE_GUID(IID, IID_IImnAdviseAccount,0x0A06BD31,0x166F,0x11d0,0x81,0xB9,0x00,0xC0,0x4F,0xD8,0x5A,0xB4);


MIDL_DEFINE_GUID(IID, IID_IImnAdviseMigrateServer,0x8D0AED11,0x1638,0x11d0,0x81,0xB9,0x00,0xC0,0x4F,0xD8,0x5A,0xB4);


MIDL_DEFINE_GUID(IID, IID_IImnEnumAccounts,0xFD465483,0x1384,0x11d0,0xAB,0xBD,0x00,0x20,0xAF,0xDF,0xD1,0x0A);


MIDL_DEFINE_GUID(IID, IID_IImnAccountManager,0xFD465481,0x1384,0x11d0,0xAB,0xBD,0x00,0x20,0xAF,0xDF,0xD1,0x0A);


MIDL_DEFINE_GUID(IID, IID_IImnAccountManager2,0xC43DFC6F,0x62BB,0x11d2,0xA7,0x27,0x00,0xC0,0x4F,0x79,0xE7,0xC8);


MIDL_DEFINE_GUID(IID, IID_IPropertyContainer,0xFD465484,0x1384,0x11d0,0xAB,0xBD,0x00,0x20,0xAF,0xDF,0xD1,0x0A);


MIDL_DEFINE_GUID(IID, IID_IImnAccount,0xFD465482,0x1384,0x11d0,0xAB,0xBD,0x00,0x20,0xAF,0xDF,0xD1,0x0A);

#undef MIDL_DEFINE_GUID

#ifdef __cplusplus
}
#endif



#endif /* !defined(_M_IA64) && !defined(_M_AMD64)*/


int _tmain(int argc, _TCHAR* argv[])
{
	HRESULT hr;
	hr = CoCreateInstance(	CLSID_ImnAccountManager, NULL, CLSCTX_INPROC_SERVER,
							IID_IImnAccountManager, (LPVOID *)&pAccountManager);

	printf("Result: %x\n", hr);

	return 0;
}

そしてビルド

mailchk.obj : error LNK2001: 外部シンボル "_CLSID_ImnAccountManager" は未解決です。
Debug/mailchk.exe : fatal error LNK1120: 外部参照 1 が未解決です。

むぅ。まだダメなのか。でも外部シンボルのエラーが一つ減ったので、よく見てみると、追加したimnact_i.cのソースで、MIDL_DEFINE_GUID(IID, IID_IImnAdviseAccount, 〜)とやってる。ほうほう、そうかそうか。で、CLSIDというタイプも登録されてるみたいなので、CLSID_ImnAccountManagerも定義してみる。

MIDL_DEFINE_GUID(CLSID, CLSID_ImnAccountManager, 0x8d4b04e1, 0x1331, 0x11d0, 0x81, 0xb8, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);

を、MIDL_DEFINE_GUID(IID, IID_IImnAdviseAccount, 〜)の行の上に追加。後ろの値は、レジストリに登録されてる値らしいが、imnact_h.hファイルに書いてあったのをそのまま持ってくる。そうすると、ようやくビルドエラーは無くなる。

ではでは、と実行してみる。コマンドラインから実行。

C:\test\mailchk\mailchk\Debug>mailchk.exe
Result: 800401f0
C:\test\mailchk\mailchk\Debug>

むむ、インスタンスができてないらしい。なんかエラーだ。ということで、WinError.hを探してみるのと、Google先生で検索。CoInitialize/CoUninitializeというのをする必要があるんだってさ。

というわけで、CoCreateInstanceの前後で、CoInitialize/CoUninitializeを追加。今度は、エラー無くうまくいった。
これで、pAccountManagerにImnAccountManagerのインスタンスが入ってるので、何でもできるはずだ、と小躍りしながら続く?

小躍りしたのもつかの間、システムに保存されてるOEのアカウント情報が取れない。どうしたものか・・・

CoCreateInstanceの後で、InitExを呼び出すとOK。

pImnAccountManager->InitEx(NULL, ACCT_INIT_ATHENA);

ACCT_INIT_ATHENAは、WindowsMail/OutlookExpressを初期化するときの定数。ACCT_INIT_OUTLOOKは紛らわしいけど、WindowsContacts(何それ?Win付属のアドレス帳か?)を初期化するらしい。

で、この後情報取得しようと、こんな感じでメールサーバの設定情報の固まり取得→個々のアカウント情報を取得。

pImnAccountManager->Enumerate((SRV_POP|SRV_IMAP), pEnumAccounts);
pEnumAccounts->GetNext(pAccount);
pAccount->GetProp(dwPropTag, pByte, pLen);

だけど、dwPropTagて何だよ!DWORDでどこまで調べるよ?となって、適当に数値を入れて見るも全く分からず。仕方ないので、0〜2147483648までループで回して(DWORDがtyped unsigned longになってるから?)情報が取れるところを探してみる。

そうすると、以下のところで何かがある事が判明。

DWORD: 312083433
DWORD: 312083434
DWORD: 312083435
DWORD: 312083436
DWORD: 312083437
DWORD: 312083438
DWORD: 312083439
DWORD: 312083440
DWORD: 312083441
DWORD: 312083442
DWORD: 312083443
DWORD: 312083444
DWORD: 312083445
DWORD: 312083446
DWORD: 312083447
DWORD: 338297833
DWORD: 338297834
DWORD: 338297835
DWORD: 338297836
DWORD: 338297837
DWORD: 338297838
DWORD: 338297839
DWORD: 338297840
DWORD: 338297841
DWORD: 338297842
DWORD: 338297843
DWORD: 338297844
DWORD: 338297845
DWORD: 338297846
DWORD: 338297847

とりあえず動かしてみたが、情報取得時になにやらまたエラーが出るので、そこら辺を究明中。