Partager via


Prise en charge de plusieurs rappels

Si vous appelez plusieurs méthodes asynchrones, chacune d’elles nécessite une implémentation distincte d’IMFAsyncCallback::Invoke. Toutefois, vous pouvez implémenter les rappels à l’intérieur d’une seule classe C++. La classe ne peut avoir qu’une seule méthode Invoke . Par conséquent, une solution consiste à fournir une classe d’assistance qui délègue les appels Invoke à une autre méthode sur une classe de conteneur.

Le code suivant montre un modèle de classe nommé AsyncCallback, qui illustre cette approche.

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

Le paramètre de modèle est le nom de la classe de conteneur. Le AsyncCallback constructeur a deux paramètres : un pointeur vers la classe conteneur et l’adresse d’une méthode de rappel sur la classe conteneur. La classe conteneur peut avoir plusieurs instances de la AsyncCallback classe en tant que variables membres, une pour chaque méthode asynchrone. Lorsque la classe de conteneur appelle une méthode asynchrone, elle utilise l’interface IMFAsyncCallback de l’objet approprié AsyncCallback . Lorsque la AsyncCallback méthode Invoke de l’objet est appelée, l’appel est délégué à la méthode appropriée sur la classe conteneur.

L’objet AsyncCallback délègue également les appels AddRef et Release à la classe conteneur, de sorte que la classe conteneur gère la durée de vie de l’objet AsyncCallback . Cela garantit que l’objet AsyncCallback n’est pas supprimé tant que l’objet conteneur lui-même n’est pas supprimé.

Le code suivant montre comment utiliser ce modèle :

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

Dans cet exemple, la classe de conteneur est nommée CMyObject. La variable membre m_CB est un AsyncCallback objet. Dans le CMyObject constructeur, la variable membre m_CB est initialisée avec l’adresse de la CMyObject::OnInvoke méthode.

Méthodes de rappel asynchrones