次の方法で共有


複数のコールバックのサポート

複数の非同期メソッドを呼び出す場合、それぞれが 個別に IMFAsyncCallback::Invoke を実装する必要があります。 ただし、1 つの C++ クラス内にコールバックを実装することもできます。 クラスには 1 つの Invoke メソッドのみを含めることができるので、1 つのソリューションは、コンテナー クラスの別のメソッドに 対する Invoke 呼び出しをデリゲートするヘルパー クラスを提供することです。

次のコードは、 という名前 AsyncCallbackのクラス テンプレートを示しています。この方法を示します。

//////////////////////////////////////////////////////////////////////////
//  AsyncCallback [template]
//
//  Description:
//  Helper class that routes IMFAsyncCallback::Invoke calls to a class
//  method on the parent class.
//
//  Usage:
//  Add this class as a member variable. In the parent class constructor,
//  initialize the AsyncCallback class like this:
//      m_cb(this, &CYourClass::OnInvoke)
//  where
//      m_cb       = AsyncCallback object
//      CYourClass = parent class
//      OnInvoke   = Method in the parent class to receive Invoke calls.
//
//  The parent's OnInvoke method (you can name it anything you like) must
//  have a signature that matches the InvokeFn typedef below.
//////////////////////////////////////////////////////////////////////////

// T: Type of the parent object
template<class T>
class AsyncCallback : public IMFAsyncCallback
{
public:
    typedef HRESULT (T::*InvokeFn)(IMFAsyncResult *pAsyncResult);

    AsyncCallback(T *pParent, InvokeFn fn) : m_pParent(pParent), m_pInvokeFn(fn)
    {
    }

    // IUnknown
    STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
    {
        static const QITAB qit[] =
        {
            QITABENT(AsyncCallback, IMFAsyncCallback),
            { 0 }
        };
        return QISearch(this, qit, riid, ppv);
    }
    STDMETHODIMP_(ULONG) AddRef() {
        // Delegate to parent class.
        return m_pParent->AddRef();
    }
    STDMETHODIMP_(ULONG) Release() {
        // Delegate to parent class.
        return m_pParent->Release();
    }

    // IMFAsyncCallback methods
    STDMETHODIMP GetParameters(DWORD*, DWORD*)
    {
        // Implementation of this method is optional.
        return E_NOTIMPL;
    }

    STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult)
    {
        return (m_pParent->*m_pInvokeFn)(pAsyncResult);
    }

    T *m_pParent;
    InvokeFn m_pInvokeFn;
};

テンプレート パラメーターは、コンテナー クラスの名前です。 AsyncCallbackコンストラクターには、コンテナー クラスへのポインターと、コンテナー クラスのコールバック メソッドのアドレスという 2 つのパラメーターがあります。 コンテナー クラスは、 クラスの複数のインスタンスを AsyncCallback メンバー変数として持つことができます。1 つは非同期メソッドごとに 1 つです。 コンテナー クラスは、非同期メソッドを呼び出すときに、適切なAsyncCallbackオブジェクトの IMFAsyncCallback インターフェイスを使用します。 オブジェクトの AsyncCallbackInvoke メソッドが呼び出されると、呼び出しはコンテナー クラスの正しいメソッドに委任されます。

また、 オブジェクトは AsyncCallbackAddRef 呼び出しと Release 呼び出しをコンテナー クラスに委任するため、コンテナー クラスはオブジェクトの有効期間を AsyncCallback 管理します。 これにより、コンテナー オブジェクト自体が AsyncCallback 削除されるまで、オブジェクトは削除されません。

次のコードは、このテンプレートの使用方法を示しています。

#pragma warning( push )
#pragma warning( disable : 4355 )  // 'this' used in base member initializer list

class CMyObject : public IUnknown
{
public:

    CMyObject() : m_CB(this, &CMyObject::OnInvoke)
    {
        // Other initialization here.
    }

    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();
    STDMETHODIMP QueryInterface(REFIID iid, void** ppv);


private:

    AsyncCallback<CMyObject>   m_CB;

    HRESULT OnInvoke(IMFAsyncResult *pAsyncResult);
};

#pragma warning( pop )

この例では、コンテナー クラスの名前 CMyObjectは です。 m_CBメンバー変数は オブジェクトですAsyncCallback。 コンストラクターでは CMyObjectm_CB メンバー変数は メソッドの CMyObject::OnInvoke アドレスで初期化されます。

非同期コールバック メソッド