COM インターフェイスの使い方
COM インターフェイスの使い方
コンポーネント オブジェクト モデル (COM) オブジェクトを作成すると、作成メソッドがインターフェイス ポインタを返す。このポインタを使って、そのインターフェイスの任意のメソッドにアクセスできる。このポインタの構文は、C++ のメソッドの場合と同様である。次のコードは、前のトピックで示した例の拡張である。この例では、IDirectPlay8Peer オブジェクトの作成後、CoCreateInstance が返した IDirectPlay8Peer インターフェイス ポインタを使って IDirectPlay8Peer::Initialize メソッドを呼び出し、オブジェクトを初期化している。わかりやすいように、エラー訂正コードは省略してある。
IDirectPlay8Peer* g_pDP = NULL;
...
CoInitialize( NULL );
...
hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL,CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Peer, (LPVOID*) &g_pDP );
hr = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 );
追加のインターフェイスの要求
通常は、作成メソッドから受け取るインターフェイス ポインタだけで用は足りる。実際、オブジェクトが公開するインターフェイスが IUnknown 以外には 1 つだけであることも多い。しかし、多くのオブジェクトは複数のインターフェイスを公開する。このため、複数のインターフェイスへのポインタが必要になる場合もある。作成メソッドが返すインターフェイスの他にもインターフェイスが必要な場合、新しいオブジェクトを作成する必要はない。オブジェクトの IUnknown::QueryInterface メソッドを使って別のインターフェイス ポインタを要求できる。
CoCreateInstance でオブジェクトを作成した場合は、IUnknown インターフェイス ポインタを要求した後、IUnknown::QueryInterface を呼び出すことによって、必要なすべてのインターフェイスを要求できる。ただし、この方法は、必要なインターフェイスが 1 つだけの場合は不便である。また、返すインターフェイス ポインタを指定できないオブジェクト作成メソッドを使う場合は、まったく役に立たない。実際には、すべての COM インターフェイスは IUnknown インターフェイスを拡張するので、通常は、明示的な IUnknown ポインタを取得する必要はない。
インターフェイスの拡張は、C++ のクラスの継承に似ている。子インターフェイスは、親インターフェイスのすべてのメソッドと子独自のメソッドを 1 つ以上公開する。実際、「拡張」の代わりに「継承」という表現を使うことも多い。ただし、継承はオブジェクト内部で行われるものである。アプリケーションがオブジェクトのインターフェイスを継承または拡張することはできない。しかし、子インターフェイスを使うと、子または親インターフェイスの任意のメソッドを呼び出せる。
すべてのインターフェイスは IUnknown の子である。このため、オブジェクトに対して取得したどのインターフェイス ポインタを使っても、QueryInterface を呼び出せる。その場合は、要求するインターフェイスのインターフェイス識別子 (IID) とインターフェイス ポインタのアドレスを指定する必要がある。メソッドが戻るとき、このポインタにインターフェイス ポインタが格納される。たとえば、次のコードは IDirectSound9::CreateSoundBuffer を呼び出して、プライマリ バッファ オブジェクトを作成している。このオブジェクトは、複数のインターフェイスを公開する。CreateSoundBuffer メソッドは IDirectSoundBuffer9 インターフェイスを返す。次のコードでは、IDirectSoundBuffer9 インターフェイスを使って QueryInterface を呼び出すことによって、IDirectSound3DListener9 インターフェイスを要求している。
IDirectSoundBuffer9* pDSBPrimary = NULL;
IDirectSound3DListener9* pDSListener;
...
if(FAILED(hr = g_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL )))
return hr;
if(FAILED(hr = pDSBPrimary->QueryInterface(IID_IDirectSound3DListener9,
(LPVOID *)&pDSListener)))
return hr;