Compatibilidad con varias devoluciones de llamada
Si llama a más de un método asincrónico, cada uno requiere una implementación independiente de IMFAsyncCallback::Invoke. Sin embargo, es posible que quiera implementar las devoluciones de llamada dentro de una sola clase de C++. La clase solo puede tener un método Invoke , por lo que una solución consiste en proporcionar una clase auxiliar que delegue llamadas Invoke a otro método en una clase contenedora.
En el código siguiente se muestra una plantilla de clase denominada AsyncCallback
, que muestra este enfoque.
//////////////////////////////////////////////////////////////////////////
// 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;
};
El parámetro de plantilla es el nombre de la clase contenedora. El AsyncCallback
constructor tiene dos parámetros: un puntero a la clase contenedora y la dirección de un método de devolución de llamada en la clase contenedora. La clase contenedora puede tener varias instancias de la AsyncCallback
clase como variables miembro, una para cada método asincrónico. Cuando la clase contenedora llama a un método asincrónico, usa la interfaz IMFAsyncCallback del objeto adecuado AsyncCallback
. Cuando se llama al AsyncCallback
método Invoke del objeto, la llamada se delega al método correcto en la clase contenedora.
El AsyncCallback
objeto también delega las llamadas AddRef y Release a la clase contenedora, por lo que la clase contenedora administra la duración del AsyncCallback
objeto. Esto garantiza que el AsyncCallback
objeto no se eliminará hasta que se elimine el propio objeto contenedor.
En el código siguiente se muestra cómo usar esta plantilla:
#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 )
En este ejemplo, la clase contenedora se denomina CMyObject
. La variable miembro m_CB es un AsyncCallback
objeto . En el CMyObject
constructor, la variable miembro m_CB se inicializa con la dirección del CMyObject::OnInvoke
método .
Temas relacionados