65.9K
CodeProject is changing. Read more.
Home

How to Use the IMessageFilter

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.92/5 (9 votes)

Jan 11, 2006

viewsIcon

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

  1. Add the IMessageFilterImpl<> to your STA object's base class list.
    class ATL_NO_VTABLE CFoo : 
        public CComObjectRootEx<CComSingleThreadModel>,
        public IMessageFilterImpl<CFoo>, ...
  2. Add COM_INTERFACE_ENTRY(IMessageFilter) to your COM_MAP.
    BEGIN_COM_MAP(CFoo)
        COM_INTERFACE_ENTRY(IFoo)
        COM_INTERFACE_ENTRY(IMessageFilter) ... 
    END_COM_MAP()
  3. Call RegisterFilter() in the FinalConstruct().
  4. 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; 
   }
};