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