テクニカル ノート 38: MFC/OLE IUnknown の実装
[!メモ]
次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。
OLE 2 の中核は 「OLE コンポーネント オブジェクト モデル」、または COM があります。COM は協調のオブジェクトが相互にどのようにやり取りするか標準を定義します。これは 「オブジェクト」がどのようにメソッドがオブジェクトにディスパッチまたは含む詳細が含まれています。COM は、すべての COM 互換性のあるクラスを派生する基本クラスを定義します。この基本クラスは IUnknownです。C.C++ のクラス、 COM は、 1 種類の言語に固有ではないため IUnknown インターフェイスは、参照されるが — 15 C、 Pascal、または COM オブジェクトのバイナリ レイアウトをサポートする他の言語でも実行できます。
OLE では、 「インターフェイスとして IUnknown から派生したすべてのクラスが」これは IUnknown のような 「インターフェイス」がキャッシュと実装が提供されないため、相違点です。これは、の実装が実行する処理のオブジェクトが、仕様通信プロトコルを定義します。これは、システムに応じて最大限に高めるをことができます。これは MFC/C++ のプログラムの既定の動作を実装した MFC のジョブです。
MFC の IUnknown の実装を理解するには、最初にこのインターフェイスであるかを理解します。IUnknown の簡略化バージョンは、後で定義されています:
class IUnknown
{
public:
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
};
[!メモ]
__stdcall などの特定の必要な呼び出し規約の詳細は、この図には省かれます。
AddRef と リリース,解放 のメンバー関数は、オブジェクトのメモリ管理を制御します。COM はオブジェクトを追跡する参照カウントのメソッドを使用します。オブジェクトは、 C++ のように直接参照されません。代わりに、 COM オブジェクトは、ポインターを使用して常に参照されます。所有者がそれを使用してされると、オブジェクトを解放するには、オブジェクトの リリース,解放 のメンバーは、従来の C++ オブジェクトに対してするために呼び出されます ()演算子の削除の使用に対して。参照カウントの機能は、単一のオブジェクトへの複数の参照を管理することができます。AddRef と リリース,解放 の実装は、オブジェクトの参照カウントを保持します。オブジェクトは参照カウント最終値に達するまで削除されません。
AddRef と リリース,解放 は実装の観点からは比較的簡単です。単純な実装を次に示します。:
ULONG CMyObj::AddRef()
{
return ++m_dwRef;
}
ULONG CMyObj::Release()
{
if (--m_dwRef == 0)
{
delete this;
return 0;
}
return m_dwRef;
}
QueryInterface のメンバー関数は若干よりも注意が。唯一のメンバー関数が AddRef と リリース,解放 のオブジェクトを持つことは非常に必要です。 IUnknown が提供するオブジェクトをより詳細な機能を備えることは素晴らしいです。これは QueryInterface が役立つ。これは同じオブジェクトの別の 「インターフェイス」を取得できるようにします。これらのインターフェイスは通常 IUnknown から派生し、新しいメンバー関数を追加して、追加機能を追加します。COM インターフェイスのインターフェイスで宣言されているメンバー変数がなく、すべてのメンバー関数が、純粋仮想と宣言されます。次に例を示します。
class IPrintInterface : public IUnknown
{
public:
virtual void PrintObject() = 0;
};
IUnknown場合は IPrintInterface を呼び出し、 IUnknown::QueryInterfaceIPrintInterfaceの IID を使用して取得する。IID は、インターフェイスを識別する 128 ビットの数です。自分または OLE 定義する各インターフェイスに対して IID があります。パンクがIUnknown のオブジェクトへのポインターである場合、その IPrintInterface を取得するコードは次のとおりである可能性があります:
IPrintInterface* pPrint = NULL;
if (pUnk->QueryInterface(IID_IPrintInterface,
(void**)&pPrint) == NOERROR)
{
pPrint->PrintObject();
pPrint->Release();
// release pointer obtained via QueryInterface
}
この比較的単純な、どのように実装します IPrintInterface と IUnknown インターフェイスの両方をサポートするオブジェクトをようですか。この場合、は IPrintInterface が IUnknown から直接派生するため、単純です IUnknown は、IPrintInterface を実行して、…自動的にサポートされます。次に例を示します。
class CPrintObj : public CPrintInterface
{
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
virtual void PrintObject();
};
上で実行された AddRef と リリース,解放 の実装は、と同じです。CPrintObj::QueryInterface は次のようになります。:
HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
*ppvObj = this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
確認できるようにインターフェイス ID (IID)が認識されると、そのポインターはオブジェクトに戻ります; それ以外の場合はエラーが発生します。また、正常な QueryInterface が暗黙の AddRefが発生することに注意してください。もちろん、 CEditObj::Printを実行する必要があります。これは IPrintInterface が IUnknown インターフェイスから直接派生ため、単純です。ただし、 2 種類の異なるインターフェイスをサポートする場合は、両方の IUnknown検討してから、次を派生:
class IEditInterface : public IUnkown
{
public:
virtual void EditObject() = 0;
};
クラスのサポート IEditInterface と IPrintInterfaceを持っているが、この機能を実行する、含む C++ 多重継承を使用して実装するためのさまざまな方法がここでは、入れ子になったクラスの使用について説明します。
class CEditPrintObj
{
public:
CEditPrintObj();
HRESULT QueryInterface(REFIID iid, void**);
ULONG AddRef();
ULONG Release();
DWORD m_dwRef;
class CPrintObj : public IPrintInterface
{
public:
CEditPrintObj* m_pParent;
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
} m_printObj;
class CEditObj : public IEditInterface
{
public:
CEditPrintObj* m_pParent;
virtual ULONG QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
} m_editObj;
};
全体の実装は次のように含まれています:
CEditPrintObj::CEditPrintObj()
{
m_editObj.m_pParent = this;
m_printObj.m_pParent = this;
}
ULONG CEditPrintObj::AddRef()
{
return ++m_dwRef;
}
CEditPrintObj::Release()
{
if (--m_dwRef == 0)
{
delete this;
return 0;
}
return m_dwRef;
}
HRESULT CEditPrintObj::QueryInterface(REFIID iid, void** ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
*ppvObj = &m_printObj;
AddRef();
return NOERROR;
}
else if (iid == IID_IEditInterface)
{
*ppvObj = &m_editObj;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG CEditPrintObj::CEditObj::AddRef()
{
return m_pParent->AddRef();
}
ULONG CEditPrintObj::CEditObj::Release()
{
return m_pParent->Release();
}
HRESULT CEditPrintObj::CEditObj::QueryInterface(
REFIID iid, void** ppvObj)
{
return m_pParent->QueryInterface(iid, ppvObj);
}
ULONG CEditPrintObj::CPrintObj::AddRef()
{
return m_pParent->AddRef();
}
ULONG CEditPrintObj::CPrintObj::Release()
{
return m_pParent->Release();
}
HRESULT CEditPrintObj::CPrintObj::QueryInterface(
REFIID iid, void** ppvObj)
{
return m_pParent->QueryInterface(iid, ppvObj);
}
確認します IUnknown の実装の大部分を配置するに CEditPrintObj::CEditObj と CEditPrintObj::CPrintObj のコードを複製するのではなく、クラスに CEditPrintObj 。これは、コードの量を減らし、バグを回避できます。次のキー ポイントはオブジェクトがサポートする可能性のあるパブリック インターフェイスの各メソッドから同じが可能です。インターフェイスを取得するために QueryInterface をダイヤルするには、の IUnknown インターフェイスからファイルです。これは、各インターフェイスから使用できる QueryInterface のすべての関数が同じ方法を正確に実行する必要があることを意味します。「外部オブジェクト」の実装をダイヤルするこれらの埋め込みオブジェクトに対してを返すポインターが使用されます (m_pParent)。m_pParent ポインターは CEditPrintObj のコンストラクターの間に初期化されます。次 CEditPrintObj::CPrintObj::PrintObject と CEditPrintObj::CEditObj::EditObject を実装します。より、コードのビットは 1 の機能 —オブジェクトを編集できる機能)を追加するために追加されました。しかしこの場合、 EditObject と PrintObject は、通常、一つのインターフェイスに結合 (、インターフェイスが一つのメンバー関数だけ使用すると、一般的で行われ、)。
、などの単純な処理のための説明と、コードです。MFC/OLE のクラスが簡単な方法を提供します。MFC の実装は、メッセージをメッセージ マップ方法でラップされたウィンドウと同様の手法を使用します。この機能は Interface Maps と 呼ばれ、次のセクションで説明します。
MFC インターフェイス マップ
MFC/OLE は 「インターフェイスの実装をマップします」 MFC メッセージ マップの 「」および概念と実行の 「ディスパッチ マップ」のような含まれています。MFC のインターフェイス マップの中心的な機能は次のとおりです。:
CCmdTarget にクラスをビルドする IUnknownの標準実装。
AddRef と リリース,解放で変更された参照カウントの保守
QueryInterfaceのデータによって決定される実装
また、インターフェイス マップは、次の高度な機能をサポートします:
aggregatable COM オブジェクトを作成するためのサポート
COM オブジェクトの実装で集約オブジェクトを使用するためのサポート
実装は hookable および拡張できます。
集計の詳細については、 OLE プログラマの手引きを参照してください。
MFC のインターフェイス マップはサポート CCmdTarget のクラスをルートとします。CCmdTarget は、参照カウント、 IUnknown の実装に関連付けられているすべてのメンバー関数を 「has a」 (たとえば、参照カウントは CCmdTargetにあります)。OLE COM をサポートするクラスを作成するには、 CCmdTarget からクラスを派生し、目的のインターフェイスを実装するために CCmdTarget のさまざまなマクロ、またはメンバー関数を使用します。MFC の実装は、上記の例のように各インターフェイスの実装を定義するには、入れ子になったクラスを使用します。これにより、繰り返しコードの一部を削除するいくつかのマクロ、または IUnknown の既定の実装と簡単になります。
クラスを、 MFC のインターフェイス マップを使用して実行するには
**CCmdTarget.**からクラスを直接または間接的に派生します
派生クラス定義で DECLARE_INTERFACE_MAP 関数を使用します。
使用する各インターフェイスに対してサポートしたかったりクラス定義で BEGIN_INTERFACE_PART と END_INTERFACE_PART のマクロが。
実装ファイルのクラス インターフェイス マップの定義に BEGIN_INTERFACE_MAP と END_INTERFACE_MAP のマクロを使用します。
サポートされている各 IID については、クラスの特定の部分 「」に IID 割り当てるに END_INTERFACE_MAP の BEGIN_INTERFACE_MAP とマクロとの INTERFACE_PART のマクロを使用します。
ユーザーがサポートするインターフェイスを表す入れ子になったクラスを実装します。
親、 CCmdTarget派生オブジェクトにアクセスするに METHOD_PROLOGUE のマクロを使用します。
AddRef、 リリース,解放と QueryInterface は CCmdTarget にこれらの関数 (ExternalAddRef、 ExternalReleaseと ExternalQueryInterface)の実装に委任できます。
CPrintEditObj を前の例は次のように実装する場合:
class CPrintEditObj : public CCmdTarget
{
public:
// member data and member functions for CPrintEditObj go here
// Interface Maps
protected:
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART(EditObj, IEditInterface)
STDMETHOD_(void, EditObject)();
END_INTERFACE_PART(EditObj)
BEGIN_INTERFACE_PART(PrintObj, IPrintInterface)
STDMETHOD_(void, PrintObject)();
END_INTERFACE_PART(PrintObj)
};
上記の定義は CCmdTargetから派生したクラスを作成します。DECLARE_INTERFACE_MAP のマクロは、このクラスにカスタム インターフェイス マップがあることを、フレームワークに指示します。また、 BEGIN_INTERFACE_PART と END_INTERFACE_PART のマクロは、名前 CEditObj と CPrintObj (「15 C の入れ子になったクラス (この場合は」で始まる使用され、 「I」で開始する)クラス インターフェイスをグローバル区別せずに X はクラスから入れ子になったクラスを定義します。これらのクラスの 2 種類の入れ子のメンバーが作成されます: m_CEditObj と m_CPrintObj、それぞれ。マクロは自動的に AddRef、 リリース,解放と QueryInterface 関数を宣言します; このインターフェイスにのみ関数を特定と宣言します: _stdcall および仮想キーワードがターゲット プラットフォームに応じて、用意されているように) EditObject と PrintObject (OLE マクロ STDMETHOD は、こうした使用されます。
このクラスのインターフェイス マップを実行するには:
BEGIN_INTERFACE_MAP(CPrintEditObj, CCmdTarget)
INTERFACE_PART(CPrintEditObj, IID_IPrintInterface, PrintObj)
INTERFACE_PART(CPrintEditObj, IID_IEditInterface, EditObj)
END_INTERFACE_MAP()
これは m_CPrintObj との IID_IPrintInterface IID およびそれぞれ m_CEditObj との IID_IEditInterface をアタッチします。QueryInterface (CCmdTarget::ExternalQueryInterface)の CCmdTarget の実装は要求されたとき m_CPrintObj と m_CEditObj へのポインターを返すには、このマッピングを使用します。IID_IUnknownのエントリが含まれている必要はありません; フレームワークは、マップ (この場合、 m_CPrintObj)で IID_IUnknown が要求されると最初のインターフェイスを使用します。
BEGIN_INTERFACE_PART のマクロが自動的に、の AddRef、 リリース,解放 と QueryInterface 関数を宣言していても、そのスクリプトを実行する必要があります:
ULONG FAR EXPORT CEditPrintObj::XEditObj::AddRef()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CEditPrintObj::XEditObj::Release()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT CEditPrintObj::XEditObj::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
void FAR EXPORT CEditPrintObj::XEditObj::EditObject()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
// code to "Edit" the object, whatever that means...
}
CEditPrintObj::CPrintObj の実装は、 CEditPrintObj::CEditObj に上記の定義に似ています。自動的にこれらの関数を生成するために (ただし前に MFC/OLE の開発でこのケースで使用できる)マクロを作成することは可能ですが、マクロが複数のコード行を生成するときに中断ポイントを設定するのが困難になります。したがって、このコードは手動で配置されます。
メッセージ マップのフレームワークの実装を使用して、するためのさまざまな項目があります:
実装 QueryInterface
実装とリリース AddRef
インターフェイスの両方でこれらの組み込みのメソッドのいずれかを宣言します。
また、フレームワークはメッセージ マップを内部的に使用します。これは、指示します COleServerDocを既に特定のインターフェイスをサポートし、フレームワークが提供するインターフェイスに置換または加算を提供するフレームワーク クラスから派生するようにします。これは、インターフェイスを 継承する フレームワーク完全にサポートが BEGIN_INTERFACE_MAP が 2 番目のパラメーターとして基本クラスの名前を使用する理由から原因である基本クラス マップします。これによって実現されます。
[!メモ]
一般に、 MFC バージョンからそのインターフェイスの埋め込み特化の 継承 によって MFC OLE インターフェイスの組み込み実装の実装を再利用することはできません。これを実現するため METHOD_PROLOGUE マクロを使用 CCmdTarget含むへのアクセスの派生オブジェクトから取得 CCmdTargetの埋め込みオブジェクトの fixed offset を意味します )を派生オブジェクトではありません。XAdviseSink が COleClientItem のオブジェクトの先頭から特定のオフセットであることに依存するため、メジャー、たとえば、 COleClientItem::XAdviseSinkの MFC 実装から埋め込み XMyAdviseSink を取得できません。
[!メモ]
ただし、 MFC の既定の動作の対象となる関数すべての MFC 実装に委任できます。これは COleFrameHook のクラス (多くの関数で m_xOleInPlaceUIWindow に委任します)の IOleInPlaceFrame (XOleInPlaceFrame)の MFC で実装されます。このデザインで多数のインターフェイスを実装するオブジェクトの実行時のサイズを小さくするために選択されています; 型を返すポインターの要求を削除します (m_pParent 方法など、前のセクションで使用されています)。
集計およびインターフェイス マップ
スタンドアロン COM オブジェクトをサポートするだけでなく、 MFC は、集約をサポートします。集計自体はここで説明する複雑すぎるトピックです; 集計の詳細については、 OLE プログラマの手引きを 参照してください。ここでは、フレームワークとインターフェイス マップにビルドされた集計のサポートを単について説明します。
集計を使用する方法が 2 つあります: 集約をサポートする COM オブジェクトを使用して、 (1)、 (2)別の集約できるオブジェクトを実行します。これらの機能は集約オブジェクト」と 「オブジェクトを」 aggregatable 設定を使用するように 「参照できます。MFC は両方ともサポートします。
集約オブジェクトを使用する
集約オブジェクトを使用するには、 QueryInterface の機能に集計を設定する必要があります。つまり、集約オブジェクトは、オブジェクトのネイティブ一部であるように動作する必要があります。したがって、 MFC のインターフェイスへの機能をマップします。このタイがどのようにする。IID への入れ子になったオブジェクトが割り当てられている INTERFACE_PART のマクロに加えて、または CCmdTarget の派生クラスの一部として集計オブジェクトを宣言できます。そのためには、 INTERFACE_AGGREGATE のマクロが使用されます。これは、指定したポインターである必要があります)メンバー変数 ( IUnknown または派生クラスへ使用して、インターフェイス マップの機能に統合されます。ポインターの null でないは CCmdTarget::ExternalQueryInterface が呼び出されたとき、フレームワークが自動的に要求された IID が CCmdTarget のオブジェクト自体によってサポートされているネイティブ IIDの秒の 1 つがでない場合は集約オブジェクトの QueryInterface のメンバー関数をダイヤルします。
INTERFACE_AGGREGATE マクロを使用するには
集約オブジェクトへのポインターを含むメンバー変数 ( IUnknown*)を宣言します。
メンバー変数を名前で参照しているインターフェイス マップに INTERFACE_AGGREGATE のマクロを追加します。
ある時点 (通常 CCmdTarget::OnCreateAggregates時)に、 null 以外にメンバー変数を初期化します。
次に例を示します。
class CAggrExample : public CCmdTarget
{
public:
CAggrExample();
protected:
LPUNKNOWN m_lpAggrInner;
virtual BOOL OnCreateAggregates();
DECLARE_INTERFACE_MAP()
// "native" interface part macros may be used here
};
CAggrExample::CAggrExample()
{
m_lpAggrInner = NULL;
}
BOOL CAggrExample::OnCreateAggregates()
{
// wire up aggregate with correct controlling unknown
m_lpAggrInner = CoCreateInstance(CLSID_Example,
GetControllingUnknown(), CLSCTX_INPROC_SERVER,
IID_IUnknown, (LPVOID*)&m_lpAggrInner);
if (m_lpAggrInner == NULL)
return FALSE;
// optionally, create other aggregate objects here
return TRUE;
}
BEGIN_INTERFACE_MAP(CAggrExample, CCmdTarget)
// native "INTERFACE_PART" entries go here
INTERFACE_AGGREGATE(CAggrExample, m_lpAggrInner)
END_INTERFACE_MAP()
m_lpAggrInner は NULL にコンストラクターで初期化されます。フレームワークは QueryInterfaceの既定の実装の空白のメンバー変数を無視します。OnCreateAggregates は、実際に集約オブジェクトの作成に適しています。COleObjectFactoryの MFC 実装の外部オブジェクトを作成することを明示的にダイヤルする必要があります。CCmdTarget::OnCreateAggregates で集計、 CCmdTarget::GetControllingUnknown の使用を作成するための原因は、 aggregatable オブジェクトを作成すると、明らかについてはです。
この手法は集約オブジェクトがネイティブ サポートするインターフェイスとインターフェイスのオブジェクトをすべて提供します。集計がサポートするインターフェイスのサブセットのみが必要な場合は、 CCmdTarget::GetInterfaceHookをオーバーライドできます。これは QueryInterfaceに似た非常に下位レベルの hookability を示します。通常、集計がサポートするすべてのインターフェイスする場合。
オブジェクトの実装を Aggregatable できます。
aggregatable、 AddRefの実装である、オブジェクトに対して リリース,解放と QueryInterface は 「不明のコントロールに代行させる必要があります」。つまり、オブジェクトの一部であるそのためには、 IUnknownから派生した異なるオブジェクトに AddRef、 リリース,解放と QueryInterface に、デリゲートする必要があります。これは 「オブジェクトにコントロールの演算子」つまり、 COleObjectFactoryの実装に提供される作成時に提供されます。これを実行すると、わずかオーバーヘッドをラフティング、場合によっては望ましくない場合もあります、 MFC はこれを省略可能になります。オブジェクトが使用できるようにするには、 aggregatable であることをオブジェクトのコンストラクターから CCmdTarget::EnableAggregation をダイヤルします。
オブジェクトが、集計を使用する場合は、集約オブジェクトに正しい 「の」不明な制御を渡します確認する必要があります。通常 IUnknown のこのポインターはオブジェクトに集計の作成時に渡されます。たとえば、 pUnkOuter パラメーターは CoCreateInstanceで作成されたオブジェクトの 「コントロール」不明です。コントロールの正しい 「unknown」ポインターは CCmdTarget::GetControllingUnknownを呼び出すことによって取得できます。ただし、この関数から返される値は、コンストラクターの間は無効です。したがって COleObjectFactory の実装またはから作成されて、 GetControllingUnknown からの戻り値が信頼できる CCmdTarget::OnCreateAggregatesのオーバーライドでのみ集計を作成することが、推奨されます。
意図的に参照カウントを追加するか解放すると、オブジェクトが正しい参照カウントを処理することも重要です。これを実現することは、常に、 InternalRelease と InternalAddRefの代わりに ExternalAddRef と ExternalRelease をダイヤルします。これは、集約をサポートするクラスの InternalRelease か InternalAddRef をダイヤルすることはほとんどありません。
リファレンスです。
インターフェイスを定義するか、またはフレームワークの OLE インターフェイスの実装をオーバーライドするなどの OLE の高度な用途は、基のインターフェイス マップの機能を使用します。
このセクションでは、これらの高度な機能を実行するために使用される API と各マクロについて説明します。
CCmdTarget::EnableAggregation —関数の説明
void EnableAggregation();
解説
この型のオブジェクトの OLE 集約をサポートする場合は、派生クラスのコンストラクターでこの関数を呼び出します。これは、 aggregatable オブジェクトに必要な IUnknown の特別な実装を準備します。
CCmdTarget::ExternalQueryInterface —関数の説明
DWORD ExternalQueryInterface(
const void FAR* lpIID,
LPVOID FAR* ppvObj
);
解説
パラメーター
lpIID
IID (QueryInterface への最初の引数)へのポインターもppvObj
IUnknown* (QueryInterface への第 2 引数へのポインター)
解説
各インターフェイスの IUnknown の実装でこの関数をクラスの実装と呼ばれます。この関数は、オブジェクトのインターフェイス マップに QueryInterface の標準データ ドリブン基づいて実装を提供します。HRESULT に戻り値をキャストする必要です。オブジェクトが集約されている場合、この関数を呼び出します。ローカル インターフェイス マップを使用する代わりに 「コントロールの IUnknown」。
CCmdTarget::ExternalAddRef —関数の説明
DWORD ExternalAddRef();
解説
各インターフェイスに対して IUnknown::AddRef の実装でこの関数をクラスの実装と呼ばれます。戻り値は CCmdTarget のオブジェクトの新しい参照カウントです。オブジェクトが集約されている場合、この関数を呼び出します。ローカル参照カウントを処理する代わりに 「コントロールの IUnknown」。
CCmdTarget::ExternalRelease —関数の説明
DWORD ExternalRelease();
解説
各インターフェイスに対して IUnknown::Release の実装でこの関数をクラスの実装と呼ばれます。戻り値は、オブジェクトの新しい参照カウントを示します。オブジェクトが集約されている場合、この関数を呼び出します。ローカル参照カウントを処理する代わりに 「コントロールの IUnknown」。
- マクロついて DECLARE INTERFACE MAP
DECLARE_INTERFACE_MAP
解説
インターフェイス マップがある CCmdTarget から派生したクラスでこのマクロを使用します。DECLARE_MESSAGE_MAPと同様に使用します。このマクロ呼び出しはヘッダーのクラス定義に、通常配置する必要があります。H)ファイル。DECLARE_INTERFACE_MAP のクラスは BEGIN_INTERFACE_MAP と END_INTERFACE_MAP マクロの実装ファイル (.cpp)のインターフェイス マップを定義する必要があります。
BEGIN_INTERFACE_PART と END_INTERFACE_PART —マクロについて
BEGIN_INTERFACE_PART(
localClass,
iface
);
END_INTERFACE_PART(
localClass
)
解説
パラメーター
localClass
インターフェイスを実装するクラスの名前iface
インターフェイスの名前、このクラスの実装
解説
クラスが実装するインターフェイスごとに、 BEGIN_INTERFACE_PART と END_INTERFACE_PART のペアを持つ必要があります。これらのマクロは、定義し、そのクラスの埋め込みメンバー変数 OLE インターフェイスから派生したローカル クラスを定義します。AddRef、 リリース,解放と QueryInterface のメンバーは自動的に宣言されます。実装されるインターフェイスの一部であるそのほかのメンバー関数の宣言を含めます (これらの宣言は BEGIN_INTERFACE_PART と END_INTERFACE_PART マクロの間に配置されます)。
iface の 引数は、 IAdviseSink、または IPersistStorage など、実行する OLE インターフェイス (またはカスタム インターフェイスを作成する場合)。
localClass の 引数が定義されているローカル クラスの名前です。X は名前に自動的に追加されます。この名前付け規則が同じ名前のグローバル クラスとの競合を避けるために使用されます。また、埋め込みメンバー、 "m_x" プレフィックスとして付けられた以外 localClass が 同じ名前を付けるの名前。
次に例を示します。
BEGIN_INTERFACE_PART(MyAdviseSink, IAdviseSink)
STDMETHOD_(void,OnDataChange)(LPFORMATETC, LPSTGMEDIUM);
STDMETHOD_(void,OnViewChange)(DWORD, LONG);
STDMETHOD_(void,OnRename)(LPMONIKER);
STDMETHOD_(void,OnSave)();
STDMETHOD_(void,OnClose)();
END_INTERFACE_PART(MyAdviseSink)
IAdviseSink から派生 XMyAdviseSink というローカル クラスとそれが呼び出された m_xMyAdviseSink.Note で宣言されたクラスのメンバーを定義します:
[!メモ]
STDMETHOD_ で始まる行は OLE2.H で主にコピーし、わずかに変更されます。OLE2.H からそれらのファイルをコピー解決が困難なエラーを減らすことができます。
BEGIN_INTERFACE_MAP と END_INTERFACE_MAP —マクロについて
BEGIN_INTERFACE_MAP(
theClass,
baseClass
)
END_INTERFACE_MAP
解説
パラメーター
theClass
インターフェイス マップが定義されたクラスbaseClass
theClass の派生元のクラス。
解説
実装ファイルで BEGIN_INTERFACE_MAP と END_INTERFACE_MAP のマクロが実際にインターフェイス マップの定義に使用されます。実装されるインターフェイスごとに一つ以上の INTERFACE_PART マクロの呼び出しがあります。クラスを使用する各集計の場合、 1 回の INTERFACE_AGGREGATE マクロの呼び出しがあります。
- マクロついて INTERFACE PART
INTERFACE_PART(
theClass,
iid,
localClass
)
解説
パラメーター
theClass
インターフェイス マップを含んでいるクラスの名前。iid
IID 埋め込みクラスにマップされます。localClass
ローカル クラスの名前 (X が少ない)。
解説
このマクロは、オブジェクトがサポートする各インターフェイスに対して BEGIN_INTERFACE_MAP のマクロを使用すると END_INTERFACE_MAP マクロの間で。これは theClass と localClassに示すクラスのメンバーに IID を割り当てることができます。" m_x は localClass に自動的に追加されます。複数の IID が一つのメンバーに関連付けられている可能性があることに注意してください。これは 「ほとんどの派生インターフェイス」のみ実行し、すべての中間を提供するがあり、インターフェイスする場合に非常に便利です。この良い例は IOleInPlaceFrameWindow インターフェイスです。その階層外観になります。:
IUnknown
IOleWindow
IOleUIWindow
IOleInPlaceFrameWindow
オブジェクトが IOleInPlaceFrameWindowを実行すると、クライアントはこれらのインターフェイスのいずれかの QueryInterface 可能性があります: 「ほとんどの派生インターフェイス (」 IOleInPlaceFrameWindow 、実際に実行している)のほかの IOleUIWindow、 IOleWindow、または IUnknown、 1。これを処理するには IOleInPlaceFrameWindow インターフェイスに基本インターフェイスを割り当てるに INTERFACE_PART の複数のマクロを使用できます:
クラスの定義ファイル:
BEGIN_INTERFACE_PART(CMyFrameWindow, IOleInPlaceFrameWindow)
クラスの実装ファイル:
BEGIN_INTERFACE_MAP(CMyWnd, CFrameWnd)
INTERFACE_PART(CMyWnd, IID_IOleWindow, MyFrameWindow)
INTERFACE_PART(CMyWnd, IID_IOleUIWindow, MyFrameWindow)
INTERFACE_PART(CMyWnd, IID_IOleInPlaceFrameWindow, MyFrameWindow)
END_INTERFACE_MAP
フレームワークは、常に必要なため、 IUnknown 処理します。
- マクロついて INTERFACE PART
INTERFACE_AGGREGATE(
theClass,
theAggr
)
解説
パラメーター
theClass
インターフェイス マップを含むクラスの名前、theAggr
集計するメンバー変数の名前。
解説
クラスが集約オブジェクトを使用していることをこのマクロは、フレームワークに指示するために使用されます。これは BEGIN_INTERFACE_PART と END_INTERFACE_PART マクロの間に記述する必要があります。集約オブジェクトは IUnknownから派生した二つのオブジェクトです。集計および INTERFACE_AGGREGATE マクロを使用して、集計なサポートがオブジェクトによって直接サポートするようにあるすべてのインターフェイスを作成できます。theAggr の 引数は IUnknown から派生したクラスのメンバー変数の名前です (直接または間接的に)。INTERFACE_AGGREGATE のすべてのマクロはインターフェイス マップにある場合 INTERFACE_PART のマクロに従う必要があります。