はじめに
COM の要件は IUnknown インターフェースを実装していることです。しかし、要件ではないですが、IDispatch インターフェースを実装するのが一般的です。
これは何かといえば、Java や C# の「リフレクション」のような機能を実現するためのインターフェースです。IDispatch が実装されていると、Invoke メソッドを使って COM オブジェクトのプロパティやメソッドを利用できます。
IDispatch の使用手順
- TLB をインポートしてオブジェクトの諸元を得る。
- COM を初期化して使用可能にする。
- COM オブジェクトを作成する。
- IDispatch を実装しているか調べる。
- Invoke メソッドに渡すためのパラメータを作成する。
- Invoke メソッドを呼び出す。
サンプル
前述の手順をコードとして記述したサンプルを示します。
実はこのサンプルですが、完全ではありません。Invoke メソッドのパラメータとして SAFEARRAY を渡す必要があるのですが、それの作り方がよくわからず途中で頓挫してしまいました。
SAFEARRAY を作るための API 関数を使うといくらか楽になるようです。(SafeArrayCreate)
// CheckDualInterface.cpp : アプリケーションのエントリ ポイントを定義します。
//
# include "stdafx.h"
# import "C:\lib\AxStrFuncs.tlb" named_guids no_namespace
void CreateParams(VARIANTARG *sarr, LPCTSTR str, short n, BSTR ret);
//
// IDispatch を実装した COM オブジェクトの使用法
// ==============================================
int main()
{
IUnknown *punk;
IDispatch *pdisp;
DISPID dispid;
OLECHAR *pName; // OLECHAR は WCHAR の別名
VARIANTARG arg1[3];
DISPPARAMS dispparams;
// 開始メッセージ表示
printf_s("Check IDispatch installed.\n");
// COM 初期化
HRESULT hr = OleInitialize(NULL); // 内部的に ComInitializeEx を呼び出している。
if (FAILED(hr))
{
printf_s("Failed to initialize COM.\n");
return -1;
}
// オブジェクトを作成する。
hr = CoCreateInstance(__uuidof(StrFuncObject), NULL, CLSCTX_SERVER, IID_IUnknown, (void**)&punk);
if (FAILED(hr))
{
printf_s("Failed to create the object.\n");
return -1;
}
// IDispatch を実装しているか調べる。
hr = punk->QueryInterface(IID_IDispatch, (void**)&pdisp);
if (FAILED(hr))
{
printf_s("IDispatch is not suppored.\n");
return -1;
}
// オブジェクトのメソッド Right の DISPID を得る。
CComBSTR right(L"Right");
pName = right;
hr = pdisp->GetIDsOfNames(IID_NULL, &pName, 1, LOCALE_USER_DEFAULT, &dispid);
if (FAILED(hr))
{
printf_s("IDispatch is not suppored.\n");
return -1;
}
else
{
printf_s("Right Disp ID = %d\n", dispid);
}
// Right メソッドのパラメータを作成する。
BSTR bstr = SysAllocString(L"");
CreateParams(arg1, L"ABCDEFGH", 3, bstr);
// SAFEARRAY でないと NG
// dispparams.rgvarg->parray = arg1;
dispparams.rgvarg->vt = VT_ARRAY;
dispparams.cArgs = 2;
dispparams.cNamedArgs = NULL;
dispparams.rgdispidNamedArgs = NULL;
VARIANT vResult; // 戻り値
vResult.vt = VT_BSTR | VT_BYREF;
vResult.pbstrVal = &bstr;
// Invoke メソッドを使って COM オブジェクトの Right メソッドを実行する。
hr = pdisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, &vResult, NULL, NULL);
if (FAILED(hr))
{
printf_s("Invoke method has failed.\n");
return -1;
}
else
{
wprintf_s(L"%s\n", bstr);
}
// 終わり
printf_s("Done.\n");
SysFreeString(bstr);
getchar();
return 0;
}
//
// パラメータを作成する。
// =====================
void CreateParams(VARIANTARG *sarr, LPCTSTR str, short n, BSTR ret)
{
VARIANT *p1, *p2, *p3;
p1 = sarr;
p1->vt = VT_BSTR;
p1->bstrVal = CComBSTR(str);
p2 = sarr + 1;
p2->vt = VT_I2;
p2->iVal = n;
p3 = sarr + 2;
p3->vt = VT_BSTR;
p3->bstrVal = ret;
}