IUnknown のしくみ
[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayer、IMFMediaEngine、Audio/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);
}
委任の性質上、委任メソッドはすべてのコンポーネントで同じように見える。 削除されていないバージョンのみが変更されます。
関連トピック