다음을 통해 공유


여러 콜백 지원

둘 이상의 비동기 메서드를 호출하는 경우 각각 IMFAsyncCallback::Invoke의 별도 구현이 필요합니다. 그러나 단일 C++ 클래스 내에서 콜백을 구현할 수 있습니다. 클래스에는 Invoke 메서드가 하나만 있을 수 있으므로 한 가지 솔루션은 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 컨테이너 클래스에 AddRefRelease 호출을 위임하므로 컨테이너 클래스는 개체의 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 주소를 사용하여 초기화됩니다.

비동기 콜백 메서드