テクニカル ノート 39: MFC/OLE オートメーションの実装
[!メモ]
次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。
IDispatch OLE インターフェイスの概要
IDispatch インターフェイスは、 Visual Basic などの他のアプリケーション、または他の言語では、アプリケーションの機能を利用できるアプリケーションがメソッドやプロパティをそのうち公開する方法です。このインターフェイスの重要な部分は IDispatch::Invoke 関数です。MFC は、 「 IDispatch::Invokeの実行にディスパッチ マップ」を使用します。ディスパッチ マップは CCmdTarget派生クラスが、そのうちレイアウトまたは 「形状」で直接オブジェクトのプロパティを処理するため、または IDispatch::Invoke の要求を満たすためにオブジェクト内のメンバー関数をダイヤルします。 MFC 実装の情報が。
ほとんどの場合、 ClassWizard と MFC は、アプリケーション プログラムからの OLE オートメーションの詳細の大部分を非表示にするように連携します。プログラマは実際の機能にアプリケーションに公開するためにローカライズされますが、基になる配管を気にする必要はありません。
ただし、 MFC がバックグラウンドでしていることを理解することが必要になるケースでケースがあります。ここでは、フレームワークがメンバー関数やプロパティに DISPIDの秒の割り当てまたはアドレス指定します。DISPIDの秒を代入するアルゴリズムの MFC の使用に関する知識は、アプリケーションのオブジェクトの 「タイプ ライブラリ」を作成すると ID を知る必要がある場合にのみ必要などです。
MFC DISPID の代入
オートメーション (Visual Basic ユーザーなど)のエンド ユーザーが、オートメーション対応するプロパティの実際の名前とコードのメソッド (obj.ShowWindow など)表示されますが、 IDispatch::Invoke の実装は、実際の名前を受け取りません。最適化では、アクセスされたプロパティやメソッドを説明する、 32 ビット魔法 「の」クッキーである DISPIDを受け取ります。DISPID これらの値は IDispatch の実装から IDispatch::GetIDsOfNamesと呼ばれる別のメソッドによって返されます。アクセスするプロパティごとに IDispatch::Invokeまたはメンバーに対して一度ずつオートメーション クライアント アプリケーションは GetIDsOfNames は、以降の呼び出しで設定をキャッシュします。この方法では IDispatch::Invoke の呼び出しごとのオブジェクトを使用するごとに、高い文字列の参照ではなく、一度に一つずつ実行されます。
MFC は、次の 2 点に基づいて各メソッドおよびプロパティの DISPIDの秒数を決定します:
ディスパッチ マップ (1 人の相対)の先頭から間隔
ほとんどの派生クラス (0 人の相対)のディスパッチ マップの間隔
DISPID は 2 人の部分に分かれています。DISPID の LOWORD は最初のコンポーネント、ディスパッチ マップの先頭から間隔が含まれます。HIWORD は、最派生クラスからの距離が含まれます。次に例を示します。
class CDispPoint : public CCmdTarget
{
public:
short m_x, m_y;
...
DECLARE_DISPATCH_MAP()
...
};
class CDisp3DPoint : public CDispPoint
{
public:
short m_z;
...
DECLARE_DISPATCH_MAP()
...
};
BEGIN_DISPATCH_MAP(CDispPoint, CCmdTarget)
DISP_PROPERTY(CDispPoint, "x", m_x, VT_I2)
DISP_PROPERTY(CDispPoint, "y", m_y, VT_I2)
END_DISPATCH_MAP()
BEGIN_DISPATCH_MAP(CDisp3DPoint, CDispPoint)
DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
END_DISPATCH_MAP()
確認できるように、 OLE オートメーション インターフェイスを公開するクラスは 2 つあります。これらのクラスの 1 つが他から派生するため、 OLE オートメーションの部分 (「x」と 「y」プロパティこの場合は)を含む基本クラスの機能を活用します。
MFC は次のようにクラス CDispPoint の DISPIDの秒を生成します:
property X (DISPID)0x00000001
property Y (DISPID)0x00000002
プロパティが、基本クラスにはないため、 DISPID の HIWORD は常にです (CDispPoint の最派生クラスからの距離はゼロになります)。
MFC は次のようにクラス CDisp3DPoint の DISPIDの秒を生成します:
property Z (DISPID)0x00000001
property X (DISPID)0x00010001
property Y (DISPID)0x00010002
18 Z のプロパティがプロパティを公開するクラス、 CDisp3DPoint で定義されているため、ゼロ HIWORD の DISPID が与えられます。X 座標および Y 座標のプロパティから基本クラスで、 DISPID の HIWORD 。これらのプロパティが最派生クラスで 1 種類の派生の間隔にある定義されているクラスから 1、が定義されます。
[!メモ]
LOWORD は、マップの位置によってそのエントリに明示 DISPID のマップも、常に決定されます ( DISP_PROPERTY と DISP_FUNCTION のマクロの _ID バージョンの詳細については、次のセクションを参照してください)。
高度な MFC ディスパッチ マップ機能
ClassWizard は、 Visual C++ のこのリリースにサポートしないいくつかの他の機能があります。ClassWizard メソッドは、メンバー変数のプロパティ定義し、メンバー設定の関数のプロパティを、それぞれ取得 DISP_FUNCTION、 DISP_PROPERTYと DISP_PROPERTY_EX をサポートします。これらの機能は、ほとんどのオートメーション サーバーの作成に必要なすべての機能です。
次のマクロに ClassWizard でサポートされているマクロでは不十分な場合に使用できます。: DISP_PROPERTY_NOTIFYと DISP_PROPERTY_PARAM。
DISP PROPERTY NOTIFY - マクロについて
DISP_PROPERTY_NOTIFY(
theClass,
pszName,
memberName,
pfnAfterSet,
vtPropType
)
解説
パラメーター
theClass
クラスの名前。pszName
プロパティの外部名。memberName
プロパティが保存されるメンバー変数の名前。pfnAfterSet
プロパティが変更されているかダイヤルするメンバー関数の名前。vtPropType
指定したプロパティ値の型。
解説
このマクロは DISP_PROPERTYと同様ですが、追加の引数を受け取ります。追加 pfnAfterSet は 、引数と戻り、何もメンバー関数であることが必要で、パラメーターを、無効の " OnPropertyNotify() " 受け取ります。また、メンバー変数が変更された 後 に呼び出されます。
DISP PROPERTY PARAM - マクロについて
DISP_PROPERTY_PARAM(
theClass,
pszName,
pfnGet,
pfnSet,
vtPropType,
vtsParams
)
解説
パラメーター
theClass
クラスの名前。pszName
プロパティの外部名。memberGet
プロパティを取得するために使用されるメンバー関数の名前。memberSet
プロパティの設定に使用されたメンバー関数の名前。vtPropType
指定したプロパティ値の型。vtsParams
領域の文字列は、各パラメーターの VTS_ をされています。
解説
DISP_PROPERTY_EX のマクロと同様、このマクロは別にアクセスされるプロパティを取得および設定のメンバー関数定義します。ただし、このマクロは、プロパティでパラメーター リストを指定できるようにします。これにより、他の方法でインデックス化されたか、パラメーター化されたプロパティを実装するために役立ちます。パラメーターは、プロパティの新しい値によって、その後常に最初に配置されます。次に例を示します。
DISP_PROPERTY_PARAM(CMyObject, "item", GetItem, SetItem, VT_DISPATCH, VTS_I2 VTS_I2)
メンバー関数の設定を取得するに対応し、は:
LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)
- マクロについて
DISP_FUNCTION_ID(
theClass,
pszName,
dispid,
pfnMember,
vtRetVal,
vtsParams
)
DISP_PROPERTY_ID(
theClass,
pszName,
dispid,
memberName,
vtPropType
)
DISP_PROPERTY_NOTIFY_ID(
theClass,
pszName,
dispid,
memberName,
pfnAfterSet,
vtPropType
)
DISP_PROPERTY_EX_ID(
theClass,
pszName,
dispid,
pfnGet,
pfnSet,
vtPropType
)
DISP_PROPERTY_PARAM_ID(
theClass,
pszName,
dispid,
pfnGet,
pfnSet,
vtPropType,
vtsParams
)
解説
パラメーター
theClass
クラスの名前。pszName
プロパティの外部名。dispid
プロパティまたはメソッドの固定 DISPID。pfnGet
プロパティを取得するために使用されるメンバー関数の名前。pfnSet
プロパティの設定に使用されたメンバー関数の名前。memberName
プロパティにマップのメンバー変数の名前vtPropType
指定したプロパティ値の型。vtsParams
領域の文字列は、各パラメーターの VTS_ をされています。
解説
これらのマクロの割り当て MFC を使用する代わりに DISPID を指定する、自動的に 1 になります。これらの高度なマクロの名前が同じですが、 ID は、マクロ名に追加されます (たとえば。DISP_PROPERTY_ID)と ID は pszName パラメーターの直後に指定されたパラメーターによって決まります。これらのマクロの詳細については AFXDISP.H を参照してください。_ID エントリはディスパッチ マップの末尾に配置する必要があります。これらは、マクロの**_ID** ないバージョンと同様に DISPID の自動生成に影響します ( DISPIDの秒は位置によって決まります)。次に例を示します。
BEGIN_DISPATCH_MAP(CDisp3DPoint, CCmdTarget)
DISP_PROPERTY(CDisp3DPoint, "y", m_y, VT_I2)
DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
DISP_PROPERTY_ID(CDisp3DPoint, "x", 0x00020003, m_x, VT_I2)
END_DISPATCH_MAP()
MFC は次のようにクラス CDisp3DPoint の DISPIDs を生成します:
property X (DISPID)0x00020003
property Y (DISPID)0x00000002
property Z (DISPID)0x00000001
固定 DISPID を指定すると、前に、既存のディスパッチ インターフェイスに下位互換性を維持する便利な場合は、実装に特定のシステムはメソッドまたはプロパティを定義します (通常 DISPID_NEWENUM の収集などの負の DISPIDで、示します)。
COleClientItem の IDispatch インターフェイスの取得
多くのサーバーは OLE サーバーの機能とともにドキュメント オブジェクト内のオートメーションをサポートします。このオートメーション インターフェイスにアクセスするためには、直接 COleClientItem::m_lpObject のメンバー変数にアクセスする必要があります。次のコードは COleClientItemから派生オブジェクトの IDispatch インターフェイスを取得します。必要なこの検索機能をアプリケーションに次のコードを含めることができます:
LPDISPATCH CMyClientItem::GetIDispatch()
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
LPUNKNOWN lpUnk = m_lpObject;
Run(); // must be running
LPOLELINK lpOleLink = NULL;
if (m_lpObject->QueryInterface(IID_IOleLink,
(LPVOID FAR*)&lpOleLink) == NOERROR)
{
ASSERT(lpOleLink != NULL);
lpUnk = NULL;
if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)
{
TRACE0("Warning: Link is not connected!\n");
lpOleLink->Release();
return NULL;
}
ASSERT(lpUnk != NULL);
}
LPDISPATCH lpDispatch = NULL;
if (lpUnk->QueryInterface(IID_IDispatch, &lpDispatch)
!= NOERROR)
{
TRACE0("Warning: does not support IDispatch!\n");
return NULL;
}
ASSERT(lpDispatch != NULL);
return lpDispatch;
}
この関数から返されたディスパッチ インターフェイスは直接使用されるか、または COleDispatchDriver にタイプ セーフ アクセスに接続できます。それを直接使用すると、ポインターを持つを通じて リリース,解放 のメンバーをとダイヤルすることを確認します ( COleDispatchDriver のデストラクターは、これが既定で説明します)。