Supporto di più callback
Se si chiama più di un metodo asincrono, ognuno di essi richiede un'implementazione separata di IMFAsyncCallback::Invoke. Tuttavia, è possibile implementare i callback all'interno di una singola classe C++. La classe può avere un solo metodo Invoke, quindi una soluzione consiste nel fornire una classe helper che delega Invoke chiamate a un altro metodo in una classe contenitore.
Il codice seguente illustra un modello di classe denominato AsyncCallback
, che illustra questo approccio.
//////////////////////////////////////////////////////////////////////////
// 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;
};
Il parametro del modello è il nome della classe contenitore. Il costruttore AsyncCallback
ha due parametri: un puntatore alla classe contenitore e l'indirizzo di un metodo di callback nella classe contenitore. La classe contenitore può avere più istanze della classe AsyncCallback
come variabili membro, una per ogni metodo asincrono. Quando la classe contenitore chiama un metodo asincrono, usa l'interfacciaIMFAsyncCallback dell'oggetto AsyncCallback
appropriato. Quando viene chiamato il metodo Invoke dell'oggetto AsyncCallback
, la chiamata viene delegata al metodo corretto alla classe contenitore.
L'oggetto AsyncCallback
delega anche le chiamate AddRef e Release alla classe contenitore, in modo che la classe contenitore gestisca la durata dell'oggetto AsyncCallback
. In questo modo si garantisce che l'oggetto AsyncCallback
non venga eliminato fino a quando non viene eliminato l'oggetto contenitore stesso.
Il codice seguente illustra come usare questo modello:
#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 questo esempio la classe contenitore è denominata CMyObject
. La variabile membro m_CB è un oggetto AsyncCallback
. Nel costruttore CMyObject
la variabile membro m_CB viene inizializzata con l'indirizzo del metodo CMyObject::OnInvoke
.
Argomenti correlati