Sdílet prostřednictvím


Podpora více zpětných volání

Pokud voláte více než jednu asynchronní metodu, každá vyžaduje samostatnou implementaci MMFAsyncCallback::Invoke. Můžete však chtít implementovat zpětná volání uvnitř jedné třídy C++. Třída může mít pouze jednu metodu Invoke, takže jedním řešením je poskytnout pomocnou třídu, která deleguje Invoke volání jiné metody třídy kontejneru.

Následující kód ukazuje šablonu třídy s názvem AsyncCallback, která ukazuje tento přístup.

//////////////////////////////////////////////////////////////////////////
//  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;
};

Parametr šablony je název třídy kontejneru. Konstruktor AsyncCallback má dva parametry: ukazatel na třídu kontejneru a adresu metody zpětného volání třídy kontejneru. Třída kontejneru může mít více instancí AsyncCallback třídy jako členské proměnné, jednu pro každou asynchronní metodu. Když třída kontejneru volá asynchronní metodu, používá MMFAsyncCallback rozhraní příslušného AsyncCallback objektu. Když je volána metoda AsyncCallback objektu Invoke, volání je delegováno na správnou metodu ve třídě kontejneru.

Objekt AsyncCallback také deleguje volání AddRef a Release na třídu kontejneru, takže tato třída spravuje životnost objektu AsyncCallback. To zaručuje, že objekt AsyncCallback nebude odstraněn, dokud se samotný objekt kontejneru neodstraní.

Následující kód ukazuje, jak použít tuto šablonu:

#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 )

V tomto příkladu má třída kontejneru název CMyObject. m_CB členská proměnná je objekt AsyncCallback. V konstruktoru CMyObject je m_CB členské proměnné inicializována s adresou CMyObject::OnInvoke metody.

Asynchronní metody zpětného volání