Condividi tramite


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.

Metodi di Callback Asincroni