次の方法で共有


CUnknown の使用

DirectShow は CUnknown と呼ばれる基底クラスの IUnknown を実装する。この CUnknown を使って他のクラスを派生し、コンポーネント間で変わるメソッドだけをオーバーライドできる。DirectShow の他の基底クラスのほとんどは CUnknown から派生するので、作成するコンポーネントを CUnknown または他の基底クラスから直接継承できる。

INonDelegatingUnknown

CUnknownINonDelegatingUnknown を実装する。CUnknown は参照カウントを内部的に管理し、ほとんどの状況で派生クラスは同じ 2 つの参照カウント メソッドを実装する。CUnknown は参照カウントがゼロになるとそれ自体を削除する。その一方では、CUnknown::NonDelegatingQueryInterface をオーバーライドしなければならない。なぜなら、基底クラスのメソッドは IID_IUnknown 以外の IID を受け取ると E_NOINTERFACE を返すからである。派生クラスでは、次の例に示すようにサポートするインターフェイスの IID をテストする必要がある。

STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
    if (riid == IID_ISomeInterface)
    {
        return GetInterface((ISomeInterface*)this, ppv);
    }
    // デフォルト。
    return CUnknown::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 インターフェイスへのポインタを取得する。集成したコンポーネントの場合、その所有者は外部コンポーネントである。それ以外の場合、コンポーネントはそれ自体を所有する。クラス定義の public セクションに DECLARE_IUNKNOWN マクロをインクルードする。

クラス コンストラクタ

クラスに固有の操作に加えて、クラス コンストラクタは、親クラスのコンストラクタ メソッドを起動しなければならない。次の例に、一般的なコンストラクタ メソッドを示す。

CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr) 
    : CUnknown(tszName, pUnk, phr)
{ 
    /* 他の初期化。 */ 
};

このメソッドは次のパラメータを取って 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)
    { 
        /* 他の初期化。 */ 
    };

    // 後でさらに宣言を追加する。
};

この例では、次のポイントを示している。

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

フィルタ開発における次のステップでは、アプリケーションを有効にしてコンポーネントの新しいインスタンスを作成する。このためには、DLL に関する知識に加え、クラス ファクトリおよびクラス コンストラクタ メソッドとの関係を理解していることが必要になる。詳細については、「DLL の作成方法」を参照すること。