如何使用 IMessageFilter






3.92/5 (9投票s)
2006 年 1 月 11 日

44906
本文档解释了如何使用 IMessageFilter。
引言
在我的系统中,我发现我需要使用 IMessageFilter
– 别问我怎么回事和为什么 – 所以我在 COM 书籍、新闻组,甚至在这里查找,但找不到一个关于如何使用这个接口的好例子。
也许,这对于其他人来说是微不足道的事情,但无论如何 – 在我找到一个好的例子(来自 MS 团队的 Darma Sukla),我首先想到的就是分享它。所以我希望下一个绝望的人,如果需要使用这个接口,并且来到这里 – 他会有一个不错的例子可用…
因此,IMessageFilter
用于解决 STA 对象中的重入问题。我找到的这个解决方案不是非常通用的,但它是一个很好的例子。
我的想法是继承该接口,使用类 IMessageFilterImpl
。然后,有问题的 COM 对象实现这个接口。
使用代码
- 将
IMessageFilterImpl<>
添加到你的 STA 对象的基类列表中。class ATL_NO_VTABLE CFoo : public CComObjectRootEx<CComSingleThreadModel>, public IMessageFilterImpl<CFoo>, ...
- 将
COM_INTERFACE_ENTRY(IMessageFilter)
添加到你的COM_MAP
中。BEGIN_COM_MAP(CFoo) COM_INTERFACE_ENTRY(IFoo) COM_INTERFACE_ENTRY(IMessageFilter) ... END_COM_MAP()
- 在
FinalConstruct()
中调用RegisterFilter()
。 - 将以下辅助函数实现为类方法
DWORD ProcessInComingCall(DWORD dwCallType, HTASK threadIDCaller,DWORD dwTickCount, LPINTERFACEINFO lpInterfaceInfo) { //Do the right thing ! if(dwCallType == CALLTYPE_TOPLEVEL) { return SERVERCALL_ISHANDLED; } else { return SERVERCALL_REJECTED; } }
类
class ATL_NO_VTABLE CFoo : template <class T, DWORD dwTimeOut = 5000> class ATL_NO_VTABLE IMessageFilterImpl : public IMessageFilter { public: IMessageFilterImpl() {} ~IMessageFilterImpl() { RevokeFilter(); } public: HRESULT RegisterFilter() { return ::CoRegisterMessageFilter( static_cast<IMessageFilter*>(this), NULL);} HRESULT RevokeFilter() { return /*::CoRegisterMessageFilter(NULL, NULL)*/ S_OK; } public: //IMessageFilter STDMETHODIMP_(DWORD) HandleInComingCall( DWORD dwCallType, HTASK threadIDCaller, DWORD dwTickCount, LPINTERFACEINFO lpInterfaceInfo) { //we CANNOT reject these calls if(dwCallType == CALLTYPE_ASYNC_CALLPENDING || dwCallType == CALLTYPE_ASYNC) { return SERVERCALL_ISHANDLED; } T* pT = static_cast<T*>(this); return pT->ProcessInComingCall(dwCallType, threadIDCaller,dwTickCount,lpInterfaceInfo); } STDMETHODIMP_(DWORD) RetryRejectedCall( HTASK threadIDCallee, DWORD dwTickCount, DWORD dwRejectType) //the ret val from HandleInComingCall() { if(dwRejectType == SERVERCALL_REJECTED) { return -1; } //indicates that the call should be canceled //we must've got SERVERCALL_RETRYLATER return dwTimeOut; } STDMETHODIMP_(DWORD) MessagePending( HTASK threadIDCallee, DWORD dwTickCount, DWORD dwPendingType) //the ret val from RetryRejectedCall() { return PENDINGMSG_WAITNOPROCESS; } };