色々調べてもラチが空かないので、OLEのインタフェースを書いているハズのタイプライブラリィを調べてみる。
まずはタイプライブラリィを登録するにはRegSvr32.exeを使うので、レジストリィを探してみる。
HKEY_CLASSES_ROOT\TypeLib
HKEY_CLASSES_ROOT\WOW6432Node\TypeLib
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WOW6432Node\TypeLib
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Classes\TypeLib
この5か所に登録したプログラム(exeとかdll)のフルパスを登録しているらしい。
WOW6432Nodeは64ビット版Windowsだけだろう。パスこそ違えど、登録内容は同じみたいなので、一般ユーザで見れそうなトコを使えば良さそうだ。HKEY_CLASSES_ROOT\TypeLibが無難かな?
この配下に、
{CLSID}
{バージョン1} @={TypeLibraryのバージョン1の名前}
0
win32 @={バージョン1の32ビット版のプログラムファイルのフルパス名}
win64 @={バージョン1の64ビット版のプログラムファイルのフルパス名}
・・・
{バージョンn} @={TypeLibraryのバージョンnの名前}
0
win32 @={バージョンnの32ビット版のプログラムファイルのフルパス名}
win64 @={バージョンnの64ビット版のプログラムファイルのフルパス名}
な構成で、プログラムファイルのフルパス名だけが保存されていた。
※Windowsのバージョンごとにこの構成も違うのかもしれないけどね。
ファイルのありかは解ったけど、具体的なインタフェース(メソッドとかプロパティ等)を取得する方法は不明。またTypeLibの直下がクラス識別子 (CLSID)なので名前で検索しようとすると時間がかかりそうだから、一旦ヒットしたらINIファイルにでも保存して再利用した方がいいだろう。
とりあえず、ネットで探してみたら、この辺にやこのあたりに情報があった。
OLEView.EXEを管理者権限で開けば詳しく調べられるし見つけた内容はIDLファイルで保存できる
※管理者権限で開く必要がる。
CLSIDFromProgIDを使って名前からCLSIDを調べられるらしいが、正しい名前を知らないとダメだろうからOLEView.EXEで事前に正確な名前を判っていないと難しそう。
見つからなかったら、全検索して部分一致した名前を列挙するようなヘルプ機能が欲しい。
一応、TypeInfoを大元の情報を探してみる。
ただ、インタフェースで階層化してるトコまで見えてしまうので、
徹底的に調べ尽くしつくしかなく、最後に纏めて目の前のクラスから使えるメソッドを列挙するようにしないと使いにくい。
IDLファイルからADODB.ConnectionがOpenSchemaメソッドを持っていると判るまで
// Connectionを見つけた_Connectionが親らしい
coclass Connection {
[default] interface _Connection;
[default, source] dispinterface ConnectionEvents;
};
・・・
// _Connectionを見つけたConnection15が親らしい
interface _Connection : Connection15 {
[id(0x00000015), helpcontext(0x0012c8b8)]
HRESULT Cancel();
};
・・・
// Connection15を見つけた。これが本体らしい
interface Connection15 : _ADO {
[id(00000000), propget, helpcontext(0x0012c918)]
HRESULT ConnectionString([out, retval] BSTR* pbstr); // Getterらしい
[id(00000000), propput, helpcontext(0x0012c918)]
HRESULT ConnectionString([in] BSTR pbstr); // Setterらしい
・・・
// OpenSchemaを発見
[id(0x00000013), helpcontext(0x0012c8d8)]
HRESULT OpenSchema(
[in] SchemaEnum Schema,
[in, optional] VARIANT Restrictions,
[in, optional] VARIANT SchemaID,
[out, retval] _Recordset** pprset);
}
この場合、Connectionの本体はConnection15らしいから、クラスのテンプレを作るならメソッドを列挙すれば良さそう。
このあたりのソースを改造しoleaut32.dllのLoadTypeLibでComTypes.TYPEKIND.TKIND_DISPATCHをチェックする様に
if (ta.typekind == ComTypes.TYPEKIND.TKIND_DISPATCH)
{
char[] numChars = { '0', '1', '2', '3', '5', '6', '7', '8', '9' };
if (sname.IndexOf("_") != 0 && sname.IndexOf("Events") == -1 && sname.IndexOfAny(numChars) == -1)
{
Console.WriteLine("DISPATCH {0} cFuncs:{1}, cImplTypes:{2}, cVars:{3}", sname, ta.cFuncs, ta.cImplTypes, ta.cVars);
int href;
info.GetRefTypeOfImplType(-1, out href); // -1は、謎仕様
ComTypes.ITypeInfo info2;
info.GetRefTypeInfo(href, out info2);
info2.GetTypeAttr(out ppta);
ComTypes.TYPEATTR ta2 = (ComTypes.TYPEATTR)Marshal.PtrToStructure(ppta, typeof(ComTypes.TYPEATTR));
if (ta2.typekind == ComTypes.TYPEKIND.TKIND_INTERFACE)
{
int con2;
string sname2, doc2, hlp2;
info2.GetDocumentation(-1, out sname2, out doc2, out con2, out hlp2);
Console.WriteLine("INTERFACE {0} cFuncs:{1}, cImplTypes:{2}, cVars:{3}", sname2, ta2.cFuncs, ta2.cImplTypes, ta2.cVars);
for (int j = 0; j < ta.cImplTypes; j++)
{
}
}
}
}
GetRefTypeOfImplTypeの謎仕様は偶然ココで見つけた。
Pythonのソースだけど、これが参考になるかもしれない。tlbparser.py のdef parse_typeinfo
MSのページでは
[in] index
ハンドルが返される実装された型のインデックス。有効な範囲は 0 からTYPEATTR 構造体のcImplTypesフィールドまでです。
となっているのに-1を渡すと得られるインデックスをGetRefTypeInfoに渡すと、その型が引き継いでいるインタフェース(typekind が ComTypes.TYPEKIND.TKIND_INTERFACE)な情報を得られる。
DISPATCH Properties cFuncs:11, cImplTypes:1, cVars:0
DISPATCH Property cFuncs:13, cImplTypes:1, cVars:0
DISPATCH Error cFuncs:14, cImplTypes:1, cVars:0
DISPATCH Errors cFuncs:12, cImplTypes:1, cVars:0
DISPATCH Fields cFuncs:17, cImplTypes:1, cVars:0
DISPATCH Field cFuncs:29, cImplTypes:1, cVars:0
DISPATCH Parameters cFuncs:13, cImplTypes:1, cVars:0
※名前に_や番号やEventsが付いていたものは除外
とインターフェースの情報の数が得られたので一歩前進かな?