IDispatch
COMIDispatch (デュアル)comobj 経由でメソッド名による遅延バインド呼び出しができます(vtableインデックス不要)。公式ドキュメント
オブジェクト、メソッド、プロパティを、オートメーションをサポートするプログラミングツールやその他のアプリケーションに公開します。
メソッド 4
vtbl = vtable インデックス(0始まり)。IDispatch 実装のため HSP ではメソッド名でも呼べます(上記)。低レベルの index 呼び出し用に vtbl も掲載。0〜2 は IUnknown。
オブジェクトが提供する型情報インターフェイスの数(0 または 1)を取得します。
| pctinfo | DWORD* | out | オブジェクトが提供する型情報インターフェイスの数。オブジェクトが型情報を提供する場合、この数値は 1 になり、そうでない場合は 0 になります。 |
戻り値
解説(Remarks)
このメソッドは 0 を返すことがあり、これはオブジェクトが型情報を一切提供しないことを示します。この場合でも、オブジェクトは IDispatch または VTBL を介してプログラム制御可能な場合がありますが、型情報にアクセスするブラウザー、コンパイラー、その他のプログラミングツールに対して実行時の型情報を提供しません。これは、ブラウザーからオブジェクトを隠す場合に有用です。
例
次の Lines サンプルファイル Lines.cpp のコードは、CLines クラス(ActiveX または OLE オブジェクト)の GetTypeInfoCount メンバー関数を実装しています。
STDMETHODIMP
CLines::GetTypeInfoCount(UINT * pctinfo)
{
if (pctinfo == NULL) {
return E_INVALIDARG;
}
*pctinfo = 1;
return NOERROR;
}
オブジェクトの型情報を取得します。これを使用してインターフェイスの型情報を取得できます。
| iTInfo | DWORD | in | 返す型情報。IDispatch 実装の型情報を取得するには 0 を渡します。 |
| lcid | DWORD | in | 型情報のロケール識別子。オブジェクトは言語ごとに異なる型情報を返せる場合があります。これは、ローカライズされたメンバー名をサポートするクラスにとって重要です。ローカライズされたメンバー名をサポートしないクラスでは、このパラメーターは無視できます。 |
| ppTInfo | ITypeInfo** | out | 要求された型情報オブジェクト。 |
戻り値
このメソッドは、次のいずれかの値を返します。
| 戻り値 | 説明 |
|---|---|
| 成功しました。 | |
| iTInfo パラメーターが 0 ではありませんでした。 |
単一のメンバーと、省略可能な引数名のセットを、対応する整数 DISPID のセットにマッピングします。これらの DISPID は、以降の Invoke 呼び出しで使用できます。
| riid | GUID* | in | 将来の使用のために予約されています。IID_NULL を指定する必要があります。 |
| rgszNames | LPWSTR* | in | マッピングする名前の配列。 |
| cNames | DWORD | in | マッピングする名前の数。 |
| lcid | DWORD | in | 名前を解釈するロケールコンテキスト。 |
| rgDispId | INT* | out | 呼び出し元が割り当てた配列であり、その各要素には rgszNames 配列で渡された名前の 1 つに対応する識別子(ID)が格納されます。最初の要素はメンバー名を表します。以降の要素は、メンバーの各パラメーターを表します。 |
戻り値
このメソッドは、次のいずれかの値を返します。
| 戻り値 | 説明 |
|---|---|
| 成功しました。 | |
| メモリが不足しています。 | |
| 指定された名前の 1 つ以上が不明でした。返される DISPID の配列には、不明な名前に対応する各エントリに DISPID_UNKNOWN が格納されます。 | |
| ロケール識別子(LCID)が認識されませんでした。 |
解説(Remarks)
IDispatch の実装は、任意の正の整数 ID 値を特定の名前に関連付けることができます。0 は既定の Value プロパティ用に予約されており、–1 は不明な名前を示すために予約されています。その他の負の値は、別の目的のために定義されています。たとえば、GetIDsOfNames が呼び出され、実装が名前の 1 つ以上を認識しない場合、DISP_E_UNKNOWNNAME を返し、rgDispId 配列には不明な名前に対応するエントリに DISPID_UNKNOWN が格納されます。
メンバーおよびパラメーターの DISPID は、オブジェクトの存続期間中は一定に保たれる必要があります。これにより、クライアントは一度 DISPID を取得し、後で使用するためにキャッシュできます。
GetIDsOfNames が複数の名前で呼び出された場合、最初の名前(rgszNames[0])はメンバー名に対応し、以降の名前はメンバーのパラメーター名に対応します。
同じ名前でも、コンテキストによって異なる DISPID にマッピングされる場合があります。たとえば、ある名前が特定のインターフェイスのメンバー名として使用されるときには DISPID を持ち、別のインターフェイスのメンバーとしては別の ID を持ち、パラメーターとして現れるたびに異なるマッピングを持つことがあります。
GetIDsOfNames は、IDispatch クライアントが実行時に名前へバインドする際に使用されます。代わりにコンパイル時にバインドするには、IDispatch クライアントは Type Description Interfaces で説明されている型情報インターフェイスを使用して、名前を DISPID にマッピングできます。これにより、クライアントはコンパイル時にメンバーへバインドし、実行時に GetIDsOfNames を呼び出すことを回避できます。コンパイル時のバインドの説明については、Type Description Interfaces を参照してください。
GetIDsOfNames の実装は大文字と小文字を区別しません。大文字と小文字を区別する名前マッピングが必要なユーザーは、GetIDsOfNames を呼び出すのではなく、型情報インターフェイスを使用して名前を DISPID にマッピングする必要があります。
例
次の Lines サンプルファイル Lines.cpp のコードは、CLine クラスの GetIDsOfNames メンバー関数を実装しています。ActiveX または OLE オブジェクトは、標準の実装である DispGetIDsOfNames を使用します。この実装は、入力引数の検証を DispGetIdsOfNames に依存しています。セキュリティリスクを最小限に抑えるため、入力引数のより堅牢な検証を行うコードを含めてください。
STDMETHODIMP
CLine::GetIDsOfNames(
REFIID riid,
OLECHAR ** rgszNames,
UINT cNames,
LCID lcid,
DISPID * rgDispId)
{
return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgDispId);
}
次のコードは、CLine の Color プロパティの DISPID を取得するために GetIDsOfNames を呼び出す ActiveX クライアントに現れる可能性があります。
HRESULT hresult;
IDispatch * pdisp = (IDispatch *)NULL;
DISPID dispid;
OLECHAR * szMember = "color";
// Code that sets a pointer to the dispatch (pdisp) is omitted.
hresult = pdisp->GetIDsOfNames(
IID_NULL,
&szMember,
1, LOCALE_SYSTEM_DEFAULT,
&dispid);
オブジェクトが公開するプロパティおよびメソッドへのアクセスを提供します。
| dispIdMember | INT | in | メンバーを識別します。ディスパッチ識別子を取得するには、GetIDsOfNames またはオブジェクトのドキュメントを使用してください。 | ||||||||||
| riid | GUID* | in | 将来の使用のために予約されています。IID_NULL を指定する必要があります。 | ||||||||||
| lcid | DWORD | in | 引数を解釈するロケールコンテキスト。lcid は GetIDsOfNames 関数で使用され、また Invoke にも渡されて、オブジェクトがロケールに固有の方法で引数を解釈できるようにします。 複数の各国語をサポートしないアプリケーションは、このパラメーターを無視できます。詳細については、Supporting Multiple National Languages および Exposing ActiveX Objects を参照してください。 | ||||||||||
| wFlags | DISPATCH_FLAGS | in | Invoke 呼び出しのコンテキストを記述するフラグ。
| ||||||||||
| pDispParams | DISPPARAMS* | in | 引数の配列、名前付き引数の引数 DISPID の配列、および配列内の要素数のカウントを含む DISPPARAMS 構造体へのポインター。 | ||||||||||
| pVarResult | VARIANT* | outoptional | 結果を格納する場所へのポインター。呼び出し元が結果を期待しない場合は NULL を指定します。DISPATCH_PROPERTYPUT または DISPATCH_PROPERTYPUTREF が指定されている場合、この引数は無視されます。 | ||||||||||
| pExcepInfo | EXCEPINFO* | outoptional | 例外情報を含む構造体へのポインター。DISP_E_EXCEPTION が返される場合、この構造体を設定する必要があります。NULL を指定できます。 | ||||||||||
| puArgErr | DWORD* | outoptional | エラーを含む最初の引数の rgvarg 内でのインデックス。引数は pDispParams->rgvarg に逆順で格納されるため、最初の引数は配列内で最も大きいインデックスを持つものになります。このパラメーターは、結果の戻り値が DISP_E_TYPEMISMATCH または DISP_E_PARAMNOTFOUND の場合にのみ返されます。この引数は null に設定できます。詳細については、Returning Errors を参照してください。 |
戻り値
このメソッドは、次のいずれかの値を返します。
| 戻り値 | 説明 |
|---|---|
| 成功しました。 | |
| DISPPARAMS に指定された要素数が、メソッドまたはプロパティが受け付ける引数の数と異なります。 | |
| DISPPARAMS 内の引数の 1 つが有効なバリアント型ではありません。 | |
| アプリケーションが例外を発生させる必要があります。この場合、pexcepinfo に渡された構造体を設定する必要があります。 | |
| 要求されたメンバーが存在しません。 | |
| この IDispatch の実装は、名前付き引数をサポートしていません。 | |
| DISPPARAMS 内の引数の 1 つを指定された型に変換できませんでした。 | |
| パラメーター ID の 1 つが、メソッド上のパラメーターに対応していません。この場合、puArgErr はエラーを含む最初の引数に設定されます。 | |
| 引数の 1 つ以上を変換できませんでした。rgvarg 内で正しくない型を持つ最初のパラメーターのインデックスが puArgErr に返されます。 | |
| riid に渡されたインターフェイス識別子が IID_NULL ではありません。 | |
| 呼び出されるメンバーが LCID に従って文字列引数を解釈しますが、その LCID が認識されません。引数の解釈に LCID が不要な場合、このエラーは返されるべきではありません。 | |
| 必須のパラメーターが省略されました。 |
解説(Remarks)
通常、Invoke を直接実装すべきではありません。代わりに、ディスパッチインターフェイスを使用して、CreateStdDispatch および DispInvoke 関数を作成してください。詳細については、CreateStdDispatch、DispInvoke、Creating the IDispatch Interface、および Exposing ActiveX Objects を参照してください。
メンバーを呼び出す前にアプリケーション固有の処理を行う必要がある場合、コードは必要なアクションを実行してから、ITypeInfo::Invoke を呼び出してメンバーを呼び出します。ITypeInfo::Invoke は Invoke とまったく同じように動作します。CreateStdDispatch および DispInvoke によって作成される Invoke の標準実装は、ITypeInfo::Invoke に処理を委譲します。
ActiveX クライアントでは、Invoke を使用してプロパティの値を取得および設定したり、ActiveX オブジェクトのメソッドを呼び出したりします。dispIdMember 引数は、呼び出すメンバーを識別します。メンバーを識別する DISPID は、オブジェクトの実装者によって定義され、オブジェクトのドキュメント、IDispatch::GetIDsOfNames 関数、または ITypeInfo インターフェイスを使用して判別できます。
IDispatch::Invoke() を DISPATCH_PROPERTYPUT または DISPATCH_PROPERTYPUTREF とともに使用する場合、DISPPARAMS 構造体の cNamedArgs および rgdispidNamedArgs 要素を次のように特別に初期化する必要があります。
DISPID dispidNamed = DISPID_PROPERTYPUT;
dispparams.cNamedArgs = 1;
dispparams.rgdispidNamedArgs = &dispidNamed;
以降の情報は、ActiveX クライアントの開発者、およびコードを使用して ActiveX オブジェクトを公開するその他の人を対象としています。公開されたオブジェクトの利用者が想定すべき動作について説明します。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)
HSP用 COM定義
#usecom / #comfunc によるHSPのCOM呼び出し定義。数字は vtbl インデックス(0始まり)。クラスIDが無い場合 #usecom の末尾は "{}"、ある場合は "{CLSID}"。
#define global IID_IDispatch "{00020400-0000-0000-C000-000000000046}" #usecom global IDispatch IID_IDispatch "{}" #comfunc global IDispatch_GetTypeInfoCount 3 var #comfunc global IDispatch_GetTypeInfo 4 int,int,sptr #comfunc global IDispatch_GetIDsOfNames 5 var,var,int,int,var #comfunc global IDispatch_Invoke 6 int,var,int,int,var,var,var,var ; ※数字は vtbl インデックス(0始まり)。0/1/2 は IUnknown(QueryInterface/AddRef/Release)。 ; ※このインターフェースは直接 CoCreateInstance するクラスIDが無いため "{}"(他メソッド/アクティベーションで取得)。 ; ※出力/バッファ引数は var(変数直渡し)。varptr 方式にも切替可。 ; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。 ; ※IDispatch 実装。HSP では comobj 経由でメソッド名による呼び出しも可能(vtbl 不要)。#define global IID_IDispatch "{00020400-0000-0000-C000-000000000046}" #usecom global IDispatch IID_IDispatch "{}" #comfunc global IDispatch_GetTypeInfoCount 3 sptr #comfunc global IDispatch_GetTypeInfo 4 int,int,sptr #comfunc global IDispatch_GetIDsOfNames 5 sptr,sptr,int,int,sptr #comfunc global IDispatch_Invoke 6 int,sptr,int,int,sptr,sptr,sptr,sptr ; ※数字は vtbl インデックス(0始まり)。0/1/2 は IUnknown(QueryInterface/AddRef/Release)。 ; ※このインターフェースは直接 CoCreateInstance するクラスIDが無いため "{}"(他メソッド/アクティベーションで取得)。 ; ※出力/バッファ引数はポインタ方式(token=sptr / 呼び出しは varptr(変数))。 ; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。 ; ※IDispatch 実装。HSP では comobj 経由でメソッド名による呼び出しも可能(vtbl 不要)。