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

オブジェクトが複数のインターフェイスを実装できる点については、ここまで見てきたとおりです。実際の例として Common Item Dialog があります。このオブジェクトでは、IFileOpenDialog インターフェイスを実装することによって、一般的な使用方法の大部分をサポートしています。このインターフェイスはダイアログ ボックスの表示と選択済みファイルに関する情報の取得のためのメソッドを定義します。また、これに加えて IFileDialogCustomize インターフェイスを実装することによって高度な使用方法を可能にしています。プログラムはこのインターフェイスを使用して新しい UI コントロールを追加することによって、ダイアログ ボックスの外観と動作をカスタマイズできます。

すべての COM は IUnknown インターフェイスから直接的または間接的に継承する必要があると説明しました。Common Item Dialog オブジェクトにおける継承を以下に示します。

 

Common Item Dialog オブジェクトによって公開されるインターフェイスの図

Common Item Dialog オブジェクトによって公開されるインターフェイスの図

 

この図からわかるように、IFileOpenDialog の直接の親は IFileDialog インターフェイスであり、このインターフェイスは IModalWindow を継承しています。継承チェーンを IFileOpenDialog から IModalWindow に上っていくに従って、ウィンドウの機能が一般化していきます。最後の IModalWindow インターフェイスは IUnknown を継承しています。また、Common Item Dialog オブジェクトは IFileDialogCustomize を実装していますが、これは別の継承チェーンに存在しています。

ではここで、IFileOpenDialog インターフェイスへのポインターを使用する場合に、IFileDialogCustomize インターフェイスへのポインターを取得する方法について考えてみます。

 

同じオブジェクトにあるインターフェイスへの 2 つのインターフェイス ポインターの図

同じオブジェクトにあるインターフェイスへの 2 つのインターフェイス ポインターの図

 

単に IFileOpenDialog ポインターを IFileDialogCustomize ポインターにキャストする方法はうまくいきません。継承階層を横断するような "クロス キャスト" を高い信頼性で実行するには、ランタイム型情報 (RTTI: Run-Time Type Information) 形式の機能が必要ですが、これは言語への依存性が非常に高い機能です。

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

QueryInterface メソッドのシグネチャを以下に示します。

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

これまでの CoCreateInstance に関する説明から、QueryInterface の動作を想像できるのではないでしょうか。

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

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

hr = pFileOpen->QueryInterface(IID_IFileDialogCustomize, 
    reinterpret_cast<void**>(&pCustom));
if (SUCCEEDED(hr))
{
    // インターフェイスを使用する  (省略)
    // ...

    pCustom->Release();
}
else
{
    // エラーを処理する
}

通常どおり、戻り値 HRESULT をチェックしてメソッドの失敗に備えます。メソッドが成功した場合、ポインターを使用し終えた時点で Release を呼び出す必要があります。詳細については、「オブジェクトの有効期間を管理する」を参照してください。

次のトピック

COM のメモリ割り当て

 

 

このトピックに関するご意見をお寄せください (英語のみ)。

作成日: 2010 年 10 月 5 日

コミュニティの追加

追加
表示:
© 2015 Microsoft