여러 콜백 지원
둘 이상의 비동기 메서드를 호출하는 경우 각각 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
컨테이너 클래스에 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
주소를 사용하여 초기화됩니다.
관련 항목