How to Use the IMessageFilter






3.92/5 (9 votes)
Jan 11, 2006

44553
This article explains how to use the IMessageFilter.
Introduction
In my system, I found out that I needed to use the IMessageFilter
– and don’t ask me how and why – so I looked in books on COM, newsgroups, and even here – but could not find a good example of how to use this interface.
Maybe, this is something trivial for others, but anyway – after I found a good example (of a guy named Darma Sukla, from the MS team), the first thing that came through my mind was sharing it. So I hope that the next desperate guy, who will need to use this interface, and comes here – he will have a nice example available…
So, the IMessageFilter
is used to solve the re-entrance problem in STA objects. This solution that I’ve found is not very generic, but it is a good example.
The idea is that I inherit the interface, using the class IMessageFilterImpl
. Then, the problematic COM object implements this interface.
Using the code
- Add the
IMessageFilterImpl<>
to your STA object's base class list.class ATL_NO_VTABLE CFoo : public CComObjectRootEx<CComSingleThreadModel>, public IMessageFilterImpl<CFoo>, ...
- Add
COM_INTERFACE_ENTRY(IMessageFilter)
to yourCOM_MAP
.BEGIN_COM_MAP(CFoo) COM_INTERFACE_ENTRY(IFoo) COM_INTERFACE_ENTRY(IMessageFilter) ... END_COM_MAP()
- Call
RegisterFilter()
in theFinalConstruct()
. - Implement the following helper as a class method:
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; } }
The class
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; } };