次の方法で共有


IUnknown のしくみ

[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayerIMFMediaEngineAudio/Video Capture を使用することを強くお勧めします。 Microsoft は、レガシ API を使用する既存のコードを、可能であれば新しい API を使用するように書き換えるよう提案しています。]

IUnknown のメソッドを使用すると、アプリケーションはコンポーネント上のインターフェイスに対してクエリを実行し、コンポーネントの参照カウントを管理できます。

参照数

参照カウントは内部変数であり、 AddRef メソッドでインクリメントされ、 Release メソッドでデクリメントされます。 基底クラスは参照カウントを管理し、複数のスレッド間で参照カウントへのアクセスを同期します。

インターフェイス クエリ

インターフェイスのクエリも簡単です。 呼び出し元は、インターフェイス識別子 (IID) とポインターのアドレスという 2 つのパラメーターを渡します。 コンポーネントが要求されたインターフェイスをサポートしている場合は、インターフェイスへのポインターを設定し、独自の参照カウントをインクリメントして、S_OKを返します。 それ以外の場合は、ポインターを NULL に設定し、E_NOINTERFACEを返します。 次の擬似コードは、 QueryInterface メソッドの一般的なアウトラインを示しています。 次のセクションで説明するコンポーネントの集計では、複雑さが増します。

if (IID == IID_IUnknown)
    set pointer to (IUnknown *)this
    AddRef
    return S_OK

else if (IID == IID_ISomeInterface)
    set pointer to (ISomeInterface *)this
    AddRef
    return S_OK

else if ... 

else
    set pointer to NULL
    return E_NOINTERFACE

1 つのコンポーネントの QueryInterface メソッドと別のコンポーネントの QueryInterface メソッドの唯一の違いは、各コンポーネントがテストする IID の一覧です。 コンポーネントがサポートするすべてのインターフェイスについて、コンポーネントはそのインターフェイスの IID をテストする必要があります。

集計と委任

コンポーネントの集計は、呼び出し元に対して透過的である必要があります。 したがって、集約は単一の IUnknown インターフェイスを公開する必要があり、集計されたコンポーネントは外側のコンポーネントの実装に遅延されます。 それ以外の場合、呼び出し元には、同じ集計に 2 つの異なる IUnknown インターフェイスが表示されます。 コンポーネントが集計されていない場合は、独自の実装が使用されます。

この動作をサポートするには、コンポーネントに間接参照のレベルを追加する必要があります。 委任された IUnknown は、作業を適切な場所 (外部コンポーネントがある場合は外部コンポーネント、またはコンポーネントの内部バージョン) に委任します。 前のセクションで説明したように、 削除されていない IUnknown が作業を行います。

委任バージョンはパブリックであり、 IUnknown という名前を保持します。 削除されていないバージョンの名前は INonDelegatingUnknown に変更されます。 この名前はパブリック インターフェイスではないので、COM 仕様の一部ではありません。

クライアントは、コンポーネントのインスタンスを作成すると、 IClassFactory::CreateInstance メソッドを 呼び出します。 1 つのパラメーターは、集計コンポーネントの IUnknown インターフェイスへのポインター、または新しいインスタンスが集計されていない場合は NULL です。 コンポーネントでは、次の例に示すように、このパラメーターを使用して、使用する IUnknown インターフェイスを示すメンバー変数を格納します。

CMyComponent::CMyComponent(IUnknown *pOuterUnkown)
{
    if (pOuterUnknown == NULL)
        m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;
    else
        m_pUnknown = pOuterUnknown;

    [ ... more constructor code ... ]
}

次の例に示すように、委任 IUnknown の各メソッドは、その非委任に対応するメソッドを呼び出します。

HRESULT QueryInterface(REFIID iid, void **ppv) 
{
    return m_pUnknown->QueryInterface(iid, ppv);
}

委任の性質上、委任メソッドはすべてのコンポーネントで同じように見える。 削除されていないバージョンのみが変更されます。

IUnknown を実装する方法