【COM学習】のひとつ、QueryInterface


まず、comを学ぶ前にc++オブジェクトモデルをマスターしなければなりません.
QueryInterfaceの使用:
QueryInterfaceはIUnknownのメンバー関数で、お客様はこの関数を使用してコンポーネントが特定のインタフェースをサポートしているかどうかを問い合わせることができます.
QueryInterfaceは、このインタフェースへのポインタを返すことに成功しました.エラーはエラーコードを返します.
HRESULT _stdcall QueryInterface(const IID& iid, void **ppv);

 
次はQueryInterfaceの使用例です.(対応するコンポーネントが特定のインタフェースをサポートしているかどうかを知ることができます)
 
void ceshi(IUnknown * pI)

{

       IX* pIX = NULL;

       HRESULT hr = pI->QueryInterface(IID_IX, (void**)&pIX);

       if(SUCCEEDED(hr))

       {

              pIX->Fx();

       }

}

私たちはpIがIID_をサポートしているかどうかを調べます.IXによって識別されるインタフェース.
 
コードの中で考えているのはpIXがNULLに初期化する必要があることであり、これは比較的良いプログラミング方法であり、後の実装ではQueryInterfaceが失敗したときに戻ったインタフェースポインタをNULLに設定することを見ることができる.
QueryInterfaceはシステムではなくプログラマによって実装されるため、クエリに失敗したときにこのポインタをNULLに設定しないコンポーネントもあります.安全のため、プログラムでは自分でNULLにしたほうがいいです.
QueryInterfaceの実装:
彼の実装は、所与のIIDに基づいて対応するインタフェースを指すポインタを返すことにすぎない.
コンポーネントがお客様が指定したインタフェースをサポートする場合は、S_に戻る必要があります.OKおよび対応するポインタ.
サポートされていない場合、戻り値は:E_NOINTERFACEは、対応するポインタの戻り値をNULLに設定します.
 
HRESULT _stdcall CA::QueryInterface(const IID& iid, void ** ppv)

{

    if(iid == IID_IUnknown)

    {

         *ppv = static_cast<IX*>(this);

    }else if(iid == IID_IX)

    {

         *ppv = static_cast<IX*>(this);

    }else if(iid == IID_IY)

    {

         *ppv = static_cast<IY*>(this)

    }else

    {

         *ppv = NULL;

         return E_NOINTERFACE;

    }

    static_cast<IUnknown*>(*ppv)->AddRed();

    return S_OK;

}

QueryInterfaceの末尾呼び出しAddRefは実際には何の役にも立たず、後でAddRefについて議論する.
 
QueryInterfaceの実装規則:
1.QueryInterfaceは常に同じIUnknownポインタを返します.
2.お客様がインタフェースを取得したことがある場合、そのインタフェースは常に取得されます.
3.お客様は、既存のインタフェースを再度取得できます.
4.お客様は、開始インタフェースに戻ることができます.
5.あるインタフェースから特定のインタフェースを取得できる場合、任意のインタフェースからこのインタフェースを取得できます.
QueryInterfaceはコンポーネントを定義しています.
QueryInterfaceはCOMの最も重要な部分であり、1つのコンポーネントは実際にQueryInterfaceによって定義されているため、コンポーネントがサポートするインタフェースセットはQueryInterfaceがインタフェースポインタを返すことができるインタフェースである.
これは実装コンポーネントのC++クラスではなく,QueryInterfaceの実装によって決定される.
お客様はQueryInterfaceの実装を知らないため、コンポーネントがサポートするすべてのインタフェースを知ることができません.コンポーネントがサポートするインタフェースを理解する唯一の方法は、クエリーです.
COMはある社交パーティーで誰かと会うのと似ていて、彼らに対する仕事の面接とは大きく異なり、仕事の面接を行うと、被験者は彼の状況を紹介する履歴書を提出します.この履歴書はc++クラスの定義に似ています.社交パーティーで会うと、履歴書を提供する人はいません.事情を知るために質問しなければならない.これはCOMコンポーネントに似ています.
新しいバージョンの処理:
Comでは、インタフェースは変更されません.コンポーネントがインタフェースをパブリッシュし、クライアントによって使用されると、インタフェースは変更されず、永遠に変更されません.
各インタフェースには一意のインタフェース識別子IIDがあり、一般的にはインタフェースを変更することなく、新しいインタフェースを確立し、新しいIIDを指定することができます.
QueryInterfaceが古いIIDに対するクエリーを受信すると、古いインタフェースに戻り、新しいIIDに対するクエリーを受信すると、新しいインタフェースに戻ります.  
QueryInterfaceの場合、IIDはインタフェースです.
新しいインタフェースは古いインタフェースを継承することができ、彼も古いインタフェースとは全く異なることができます.古いインタフェースが変わらないため、既存のお客様の実行には影響はありません.
新しいお客様は、古いインタフェースを使用するか、新しいインタフェースを使用するかを自分で決めることができます.彼はそのインタフェースを検索するかを自由に決めることができるからです.
インタフェースのIIDは、クライアントがインタフェースを取得すると、異なるバージョンのインタフェースが実際には異なるインタフェースであるため、それぞれ異なるIDを持っているため、クライアントは正しいバージョンのインタフェースを取得することができます.
新しいバージョンを作成する必要があるのはいつですか?
次のいずれかの条件を変更する場合は、新しい街角に新しいidを指定する必要があります.
1、インタフェースの関数の数;
2、インタフェースの関数の順序;
3、ある関数のパラメータ;
4.ある関数パラメータの順序;
5、ある関数パラメータのタイプ;
6、関数の可能な戻り値;
7、関数の戻り値のタイプ;
8、関数パラメータの意味;
9、インタフェースの関数の意味.
修正した場合、既存のお客様が正常に動作する場合は、インタフェースに新しいIDを指定する必要があります.
2013.8.4
jofranksは南昌で