다음을 통해 공유


여러 콜백 지원

둘 이상의 비동기 메서드를 호출하는 경우 각각에는 IMFAsyncCallback::Invoke별도의 구현이 필요합니다. 그러나 단일 C++ 클래스 내에서 콜백을 구현할 수 있습니다. 클래스에는 Invoke 메서드가 하나만 있을 수 있으므로 한 가지 솔루션은 컨테이너 클래스의 다른 메서드에 호출 호출을 위임하는 도우미 클래스를 제공하는 것입니다.

다음 코드는 이 방법을 보여 주는 AsyncCallback클래스 템플릿을 보여 줍니다.

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

템플릿 매개 변수는 컨테이너 클래스의 이름입니다. AsyncCallback 생성자에는 컨테이너 클래스에 대한 포인터와 컨테이너 클래스의 콜백 메서드 주소라는 두 개의 매개 변수가 있습니다. 컨테이너 클래스는 멤버 변수로 AsyncCallback 클래스의 여러 인스턴스를 가질 수 있습니다. 각 비동기 메서드에 대해 하나씩. 컨테이너 클래스는 비동기 메서드를 호출할 때 적절한 AsyncCallback 개체의 IMFAsyncCallback 인터페이스를 사용합니다. AsyncCallback 개체의 Invoke 메서드가 호출되면 호출이 컨테이너 클래스의 올바른 메서드에 위임됩니다.

또한 AsyncCallback 개체는 컨테이너 클래스에 대한 AddRef Release 호출을 위임하므로 컨테이너 클래스는 AsyncCallback 개체의 수명을 관리합니다. 이렇게 하면 컨테이너 개체 자체가 삭제될 때까지 AsyncCallback 개체가 삭제되지 않습니다.

다음 코드는 이 템플릿을 사용하는 방법을 보여줍니다.

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

이 예제에서 컨테이너 클래스의 이름은 CMyObject. m_CB 멤버 변수는 AsyncCallback 개체입니다. CMyObject 생성자에서 m_CB 멤버 변수는 CMyObject::OnInvoke 메서드의 주소로 초기화됩니다.

비동기 콜백 메서드