次の方法で共有


CUnknown の使用

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

DirectShow は、 CUnknown という基本クラスに IUnknown を実装します。 CUnknown を使用して他のクラスを派生し、コンポーネント間で変更されるメソッドのみをオーバーライドできます。 DirectShow の他の基底クラスのほとんどは CUnknown から派生しているため、コンポーネントは CUnknown または別の基底クラスから直接継承できます。

INonDelegatingUnknown

CUnknownINonDelegatingUnknown を実装します。 内部的に参照カウントを管理します。ほとんどの場合、派生クラスは変更なしで 2 つの参照カウント メソッドを継承できます。 CUnknown は、参照カウントが 0 に低下すると、それ自体を削除することに注意してください。 一方、 CUnknown::NonDelegatingQueryInterface をオーバーライドする必要があります。基底クラスの メソッドは、IID_IUnknown以外の IID を受け取った場合、E_NOINTERFACEを返します。 派生クラスで、次の例に示すように、サポートするインターフェイスの ID をテストします。

STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
    if (riid == IID_ISomeInterface)
    {
        return GetInterface((ISomeInterface*)this, ppv);
    }
    // Default: Call parent class method. 
    // The CUnknown class must be in the inheritance chain.
    return CParentClass::NonDelegatingQueryInterface(riid, ppv);
}

ユーティリティ関数 GetInterface ( COM ヘルパー関数を参照) は、ポインターを設定し、スレッド セーフな方法で参照カウントをインクリメントし、S_OKを返します。 既定のケースでは、基底クラス メソッドを呼び出し、結果を返します。 別の基底クラスから派生した場合は、代わりに NonDelegatingQueryInterface メソッドを 呼び出します。 これにより、親クラスがサポートするすべてのインターフェイスをサポートできます。

IUnknown

前述のように、 IUnknown の委任バージョンは、すべてのコンポーネントで同じです。これは、委任されていないバージョンの正しいインスタンスを呼び出す以外に何も行わないためです。 便宜上、ヘッダー ファイル Combase.h には、3 つの委任メソッド インライン メソッドとして宣言するマクロ DECLARE_IUNKNOWNが含まれています。 次のコードに展開されます。

STDMETHODIMP QueryInterface(REFIID riid, void **ppv) {      
    return GetOwner()->QueryInterface(riid,ppv);            
};                                                          
STDMETHODIMP_(ULONG) AddRef() {                             
    return GetOwner()->AddRef();                            
};                                                          
STDMETHODIMP_(ULONG) Release() {                            
    return GetOwner()->Release();                           
};

ユーティリティ関数 CUnknown::GetOwner は、このコンポーネントを所有するコンポーネントの IUnknown インターフェイスへのポインターを取得します。 集計されたコンポーネントの場合、所有者は外部コンポーネントです。 それ以外の場合、コンポーネントはそれ自体を所有します。 クラス定義のパブリック セクションに DECLARE_IUNKNOWN マクロを含めます。

クラスのコンストラクター

クラス コンストラクターは、クラスに固有の処理に加えて、親クラスのコンストラクター メソッドを呼び出す必要があります。 一般的なコンストラクター メソッドの例を次に示します。

CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr) 
    : CUnknown(tszName, pUnk, phr)
{ 
    /* Other initializations */ 
};

メソッドは、 CUnknown コンストラクター メソッドに直接渡す次のパラメーターを受け取ります。

  • tszName は、コンポーネントの名前を指定します。
  • pUnk は、集計 IUnknown へのポインターです。
  • pHr は、メソッドの成功または失敗を示す HRESULT 値へのポインターです。

まとめ

次の例は、 IUnknown をサポートする派生クラスと、ISomeInterface という名前の架空のインターフェイスを示しています。

class CMyComponent : public CUnknown, public ISomeInterface
{
public:

    DECLARE_IUNKNOWN;

    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
    {
        if( riid == IID_ISomeInterface )
        {
            return GetInterface((ISomeInterface*)this, ppv);
        }
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
    }

    CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr) 
        : CUnknown(tszName, pUnk, phr)
    { 
        /* Other initializations */ 
    };

    // More declarations will be added later.
};

この例では、次の点を示します。

  • CUnknown クラスは IUnknown インターフェイスを実装します。 新しいコンポーネントは、 CUnknown と、コンポーネントがサポートするすべてのインターフェイスから継承されます。 コンポーネントは、 代わりに CUnknown から継承する別の基底クラスから派生できます。
  • DECLARE_IUNKNOWN マクロは、委任する IUnknown メソッドをインライン メソッドとして宣言します。
  • CUnknown クラスは、INonDelegatingUnknown の実装を提供します。
  • IUnknown 以外のインターフェイスをサポートするには、派生クラスで NonDelegatingQueryInterface メソッドをオーバーライドし、新しいインターフェイスの IID をテストする必要があります。
  • クラス コンストラクターは 、CUnknown のコンストラクター メソッドを呼び出します。

フィルターを記述する次の手順は、アプリケーションがコンポーネントの新しいインスタンスを作成できるようにすることです。 これには、DLL と、クラス ファクトリとクラス コンストラクター メソッドとの関係を理解する必要があります。 詳細については、「 DirectShow フィルター DLL を作成する方法」を参照してください。

IUnknown を実装する方法