オブジェクトにインターフェイスを要求する

先ほど、オブジェクトが複数のインターフェイスを実装できることを確認しました。 共通項目ダイアログ オブジェクトは、この実際の例です。 最も一般的な用途をサポートするために、オブジェクトは IFileOpenDialog インターフェイスを実装します。 このインターフェイスは、ダイアログ ボックスを表示し、選択したファイルに関する情報を取得するための基本的なメソッドを定義します。 ただし、より高度な使用のために、オブジェクトは IFileDialogCustomize という名前のインターフェイスも実装します。 プログラムでは、新しい UI コントロールを追加することで、このインターフェイスを使用してダイアログ ボックスの外観と動作をカスタマイズできます。

すべての COM インターフェイスは、 IUnknown インターフェイスから直接または間接的に継承する必要があることを思い出してください。 次の図は、共通項目ダイアログ オブジェクトの継承を示しています。

diagram that shows interfaces exposed by the common item dialog object

図からわかるように、 IFileOpenDialog の直接の先祖は IFileDialog インターフェイスであり、 IModalWindow を継承します。 継承チェーンを IFileOpenDialog から IModalWindow に上げると、インターフェイスはますます一般化されたウィンドウ機能を定義します。 最後に、 IModalWindow インターフェイスは IUnknown を継承します。 共通項目ダイアログ オブジェクトは、別の継承チェーンに存在する IFileDialogCustomize も実装します。

次に、 IFileOpenDialog インターフェイスへのポインターがあるとします。 IFileDialogCustomize インターフェイスへのポインターを取得するにはどうすればよいですか?

diagram that shows two interface pointers to interfaces on the same object

IFileOpenDialog ポインターを IFileDialogCustomize ポインターにキャストするだけでは機能しません。 言語に依存する高度な機能であるランタイム型情報 (RTTI) を使用せずに、継承階層全体で "クロス キャスト" する信頼性の高い方法はありません。

COM アプローチでは、最初のインターフェイスをオブジェクトへのコンジットとして使用して、IFileDialogCustomize ポインターをオブジェクトに渡すように依頼します。 これを行うには、最初のインターフェイス ポインターから IUnknown::QueryInterface メソッドを呼び出します。 QueryInterface は、C++ の dynamic_cast キーワードの言語に依存しないバージョンと考えることができます。

QueryInterface メソッドには、次のシグネチャがあります。

HRESULT QueryInterface(REFIID riid, void **ppvObject);

CoCreateInstance について既に知っていることに基づいて、QueryInterface のしくみを推測できる場合があります。

  • riid パラメーターは、要求するインターフェイスを識別する GUID です。 データ型 REFIID は、次の typedef です const GUID&。 オブジェクトが既に作成されているため、クラス識別子 (CLSID) は必要ありません。 インターフェイス識別子のみが必要です。
  • ppvObject パラメーターは、インターフェイスへのポインターを受け取ります。 このパラメーターのデータ型は void** です。 CoCreateInstance がこのデータ型を使用するのと同じ理由で、 QueryInterface を使用して COM インターフェイスのクエリを実行できるため、パラメーターを厳密に型指定することはできません。

QueryInterface を呼び出して IFileDialogCustomize ポインターを取得する方法を次に示します。

hr = pFileOpen->QueryInterface(IID_IFileDialogCustomize, 
    reinterpret_cast<void**>(&pCustom));
if (SUCCEEDED(hr))
{
    // Use the interface. (Not shown.)
    // ...

    pCustom->Release();
}
else
{
    // Handle the error.
}

常に、メソッドが失敗した場合に HRESULT の戻り値を確認します。 メソッドが成功した場合は、「オブジェクトの有効期間の管理」の説明に従って、ポインターの使用が完了したときに Release を呼び出す必要があります。

次へ

COM でのメモリ割り当て