65.9K
CodeProject 正在变化。 阅读更多。
Home

如何使用 IMessageFilter

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.92/5 (9投票s)

2006 年 1 月 11 日

viewsIcon

44906

本文档解释了如何使用 IMessageFilter。

引言

在我的系统中,我发现我需要使用 IMessageFilter – 别问我怎么回事和为什么 – 所以我在 COM 书籍、新闻组,甚至在这里查找,但找不到一个关于如何使用这个接口的好例子。

也许,这对于其他人来说是微不足道的事情,但无论如何 – 在我找到一个好的例子(来自 MS 团队的 Darma Sukla),我首先想到的就是分享它。所以我希望下一个绝望的人,如果需要使用这个接口,并且来到这里 – 他会有一个不错的例子可用…

因此,IMessageFilter 用于解决 STA 对象中的重入问题。我找到的这个解决方案不是非常通用的,但它一个很好的例子。

我的想法是继承该接口,使用类 IMessageFilterImpl。然后,有问题的 COM 对象实现这个接口。

使用代码

  1. IMessageFilterImpl<> 添加到你的 STA 对象的基类列表中。
    class ATL_NO_VTABLE CFoo : 
        public CComObjectRootEx<CComSingleThreadModel>,
        public IMessageFilterImpl<CFoo>, ...
  2. COM_INTERFACE_ENTRY(IMessageFilter) 添加到你的 COM_MAP 中。
    BEGIN_COM_MAP(CFoo)
        COM_INTERFACE_ENTRY(IFoo)
        COM_INTERFACE_ENTRY(IMessageFilter) ... 
    END_COM_MAP()
  3. FinalConstruct() 中调用 RegisterFilter()
  4. 将以下辅助函数实现为类方法
    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; 
   }
};
© . All rights reserved.