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 your COM_MAP
. BEGIN_COM_MAP(CFoo)
COM_INTERFACE_ENTRY(IFoo)
COM_INTERFACE_ENTRY(IMessageFilter) ...
END_COM_MAP()
- Call
RegisterFilter()
in the FinalConstruct()
.
- Implement the following helper as a class method:
DWORD ProcessInComingCall(DWORD dwCallType,
HTASK threadIDCaller,DWORD dwTickCount,
LPINTERFACEINFO lpInterfaceInfo)
{
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 S_OK; }
public:
STDMETHODIMP_(DWORD) HandleInComingCall(
DWORD dwCallType,
HTASK threadIDCaller,
DWORD dwTickCount,
LPINTERFACEINFO lpInterfaceInfo)
{
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)
{
if(dwRejectType == SERVERCALL_REJECTED)
{ return -1; }
return dwTimeOut;
}
STDMETHODIMP_(DWORD) MessagePending(
HTASK threadIDCallee,
DWORD dwTickCount,
DWORD dwPendingType)
{
return PENDINGMSG_WAITNOPROCESS;
}
};