Freigeben über


Unterstützung mehrerer Rückrufe

Wenn Sie mehr als eine asynchrone Methode aufrufen, erfordert jede eine separate Implementierung von IMFAsyncCallback::Invoke. Möglicherweise möchten Sie die Rückrufe jedoch in einer einzelnen C++-Klasse implementieren. Die -Klasse kann nur über eine Invoke-Methode verfügen, sodass eine Lösung darin besteht, eine Hilfsklasse bereitzustellen, die Invoke-Aufrufe an eine andere Methode für eine Containerklasse delegiert.

Der folgende Code zeigt eine Klassenvorlage namens AsyncCallback, die diesen Ansatz veranschaulicht.

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

Der Vorlagenparameter ist der Name der Containerklasse. Der AsyncCallback Konstruktor verfügt über zwei Parameter: einen Zeiger auf die Containerklasse und die Adresse einer Rückrufmethode für die Containerklasse. Die Containerklasse kann mehrere Instanzen der AsyncCallback -Klasse als Membervariablen aufweisen, eine für jede asynchrone Methode. Wenn die Containerklasse eine asynchrone Methode aufruft, verwendet sie die IMFAsyncCallback-Schnittstelle des entsprechenden AsyncCallback Objekts. Wenn die AsyncCallbackInvoke-Methode des Objekts aufgerufen wird, wird der Aufruf an die richtige Methode für die Containerklasse delegiert.

Das AsyncCallback -Objekt delegiert auch AddRef- und Release-Aufrufe an die Containerklasse, sodass die Containerklasse die Lebensdauer des AsyncCallback Objekts verwaltet. Dadurch wird sichergestellt, dass das AsyncCallback Objekt erst gelöscht wird, wenn das Containerobjekt selbst gelöscht wird.

Der folgende Code zeigt die Verwendung dieser Vorlage:

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

In diesem Beispiel heißt CMyObjectdie Containerklasse . Die m_CB Membervariable ist ein AsyncCallback -Objekt. CMyObject Im Konstruktor wird die m_CB Membervariable mit der Adresse der CMyObject::OnInvoke -Methode initialisiert.

Asynchrone Rückrufmethoden