QueryInterface を実装するための規則

COM オブジェクトに IUnknown::QueryInterface メソッドを実装する規則には、次の 3 つのメインがあります。

  • オブジェクトには ID が必要です。
  • オブジェクト インスタンス上のインターフェイスのセットは静的である必要があります。
  • 他のインターフェイスからオブジェクト上の任意のインターフェイスに対してクエリを正常に実行できる必要があります。

オブジェクトには ID が必要です。

特定のオブジェクト インスタンスに対して、IID_IUnknown を使用して QueryInterface を呼び出すと、常に同じ物理ポインター値が返される必要があります。 これにより、任意の 2 つのインターフェイスで QueryInterface を呼び出し、結果を比較して、それらがオブジェクトの同じインスタンスを指しているかどうかを判断できます。

オブジェクト インスタンス上のインターフェイスのセットは静的である必要があります。

QueryInterface を介して、オブジェクトでアクセスできるインターフェイスのセットは、動的ではなく静的である必要があります。 具体的には、QueryInterface が特定の IID のS_OKを 1 回返す場合、同じオブジェクトに対する後続の呼び出しで E_NOINTERFACE を返すことはありません。また、QueryInterface が特定の IID に対してE_NOINTERFACEを返す場合、同じオブジェクトに対する同じ IID に対する後続の呼び出しでS_OKを返すことはありません。

他のインターフェイスからオブジェクト上の任意のインターフェイスに対してクエリを正常に実行できる必要があります。

つまり、次のコードが考えられます。

IA * pA = (some function returning an IA *); 
IB * pB = NULL; 
HRESULT   hr; 
hr = pA->QueryInterface(IID_IB, &pB); 
 

次の規則が適用されます。

  • オブジェクト上のインターフェイスへのポインターがある場合、その同じインターフェイスに対する QueryInterface への次のような呼び出しは成功する必要があります。

    pA->QueryInterface(IID_IA, ...) 
    
    
  • 2 番目のインターフェイス ポインターに対する QueryInterface の呼び出しが成功した場合は、最初のインターフェイスのそのポインターから QueryInterface を呼び出しても成功する必要があります。 pB が正常に取得された場合は、次も成功する必要があります。

    pB->QueryInterface(IID_IA, ...) 
    
    
  • どのインターフェイスでも、オブジェクト上の他のインターフェイスに対してクエリを実行できる必要があります。 pB が正常に取得され、そのポインターを使用して 3 番目のインターフェイス (IC) のクエリに成功した場合は、最初のポインター pA を使用して IC のクエリも正常に実行できる必要があります。 この場合、次のシーケンスが成功する必要があります。

    IC * pC = NULL; 
    hr = pB->QueryInterface(IID_IC, &pC); 
    pA->QueryInterface(IID_IC, ...) 
    
    

インターフェイス実装は、特定のオブジェクト上のすべてのインターフェイスへの未処理のポインター参照のカウンタを維持する必要があります。 カウンターには符号なし整数を使用する必要があります。

リソースが解放されたことをクライアントが認識する必要がある場合は、IUnknown::Release を呼び出す前に、上位レベルのセマンティクスを持つオブジェクトのインターフェイスでメソッドを使用する必要があります。

IUnknown の使用と実装