本文的更新:借助模板类自动实现COM连接点接收器(Sink)更新 (2014-06-09 17:09)

最初的代码源自free2000fly一个标准的 COM 连接点接收器(Sink)的实现, 使用相当简单!!!,作者封装了不少工作,但调用时的代码还可以再封装一下,最后只要拷贝并修改Sink实现类的Invoke就好了。

以下是这个代码的头文件 "sinkimpl.h",比free2000fly的"sinkimpl.h"多了一个模板类ConnectionPointerHelper<>

  1. #if !defined( __sinkimpl_h_INCLUDED__ )
  2. #define __sinkimpl_h_INCLUDED__
  3.  
  4. #if _MSC_VER > 1000
  5. #pragma once
  6. #endif // _MSC_VER > 1000
  7.  
  8. template<typename T, typename EventInterface, const GUID * evtLibID = NULL >
  9. class ATL_NO_VTABLE CSinkImpT
  10. : public CComObjectRootEx<CComSingleThreadModel>
  11. , public CComCoClass<CSinkImpT<T, EventInterface, evtLibID>, &__uuidof(T)>
  12. , public IDispatchImpl < EventInterface, &__uuidof(EventInterface), evtLibID >
  13. {
  14. public:
  15. CSinkImpT() {}
  16. virtual ~CSinkImpT() {}
  17.  
  18. typedef IDispatchImpl<EventInterface, &__uuidof(EventInterface), evtLibID> _parentClass;
  19. typedef CSinkImpT<T, EventInterface, evtLibID> _thisClass;
  20.  
  21. STDMETHOD( Invoke )(DISPID dispidMember, REFIID riid,
  22. LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  23. EXCEPINFO* pexcepinfo, UINT* puArgErr)
  24. {
  25. T * pThis = static_cast<T *>(this);
  26. return pThis->DoInvoke( dispidMember, riid,
  27. lcid, wFlags, pdispparams, pvarResult,
  28. pexcepinfo, puArgErr );
  29. }
  30.  
  31. DECLARE_NO_REGISTRY()
  32.  
  33. DECLARE_PROTECT_FINAL_CONSTRUCT()
  34.  
  35. BEGIN_COM_MAP( _thisClass )
  36. COM_INTERFACE_ENTRY( IDispatch )
  37. COM_INTERFACE_ENTRY( EventInterface )
  38. END_COM_MAP();
  39.  
  40. STDMETHOD( DoInvoke )(DISPID dispidMember, REFIID riid,
  41. LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  42. EXCEPINFO* pexcepinfo, UINT* puArgErr)
  43. {
  44. return _parentClass::Invoke( dispidMember, riid,
  45. lcid, wFlags, pdispparams, pvarResult,
  46. pexcepinfo, puArgErr );
  47. }
  48. };
  49.  
  50. inline HRESULT WINAPI GetConnectPoint( IUnknown * pItf, const IID & rSinkIID, IConnectionPoint ** ppCP )
  51. {
  52. HRESULT hr = E_FAIL;
  53. do
  54. {
  55. if ( pItf == NULL || ppCP == NULL ) { break; }
  56.  
  57. CComQIPtr<IConnectionPointContainer> spContainer;
  58. hr = pItf->QueryInterface( &spContainer );
  59. if ( FAILED( hr ) ) { break; }
  60.  
  61. hr = spContainer->FindConnectionPoint( rSinkIID, ppCP );
  62. } while ( FALSE );
  63. return hr;
  64. }
  65.  
  66. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  67. // 使用方法:
  68. // ComDllLib::ITestComPtr pCom;
  69. // HRESULT hr = pCom.CreateInstance( L"Test.Com" );
  70. // ConnectionPointHelper<ComDllLib::_ITestComEvent, CSink3> cph( pCom );
  71. //
  72. template<typename EventInterface, typename EventProcessor>
  73. class ConnectionPointHelper
  74. {
  75. CComPtr<IUnknown> m_spInterface;
  76. DWORD m_dwCookie;
  77. public:
  78. ConnectionPointHelper( IUnknown* pInterface ) : m_spInterface( pInterface ), m_dwCookie( 0 ) { Connect(); }
  79. ~ConnectionPointHelper() { Disconnect(); }
  80. protected:
  81. void Connect()
  82. {
  83. HRESULT hr = E_FAIL;
  84. do
  85. {
  86. if ( m_spInterface == NULL || m_dwCookie != 0 ) { break; }
  87.  
  88. CComQIPtr<IConnectionPoint> spCP;
  89. hr = GetConnectPoint( m_spInterface, __uuidof(EventInterface), &spCP );
  90. if ( FAILED( hr ) ){ break; }
  91.  
  92. CComQIPtr<IDispatch> spSink;
  93. {
  94. CComObject<EventProcessor> * pTmp = NULL;
  95. hr = CComObject<EventProcessor>::CreateInstance( &pTmp );
  96. if ( FAILED( hr ) ){ break; }
  97.  
  98. pTmp->AddRef();
  99. hr = pTmp->QueryInterface( &spSink );
  100. pTmp->Release();
  101.  
  102. if ( FAILED( hr ) ){ break; }
  103. }
  104.  
  105. spCP->Advise( spSink, &m_dwCookie );
  106.  
  107. } while ( FALSE );
  108. }
  109.  
  110. void Disconnect()
  111. {
  112. HRESULT hr = E_FAIL;
  113. do {
  114. if ( m_dwCookie == 0 ) { break; }
  115.  
  116. CComQIPtr<IConnectionPoint> spCP;
  117.  
  118. hr = GetConnectPoint( m_spInterface, __uuidof(EventInterface), &spCP );
  119. if ( FAILED( hr ) ){ break; }
  120.  
  121. hr = spCP->Unadvise( m_dwCookie );
  122. m_dwCookie = 0;
  123. } while ( FALSE );
  124. }
  125.  
  126. };
  127. #endif // !defined( __sinkimpl_h_INCLUDED__ )

  

  1. 使用方法:
  1. UIAddChildWindowContainer( m_hWnd );
  2. ComDllLib::ITestComPtr pCom;
  3. CComPtr<IUnknown> pUnknown;
  4. HRESULT hr = pCom.CreateInstance( L"Test.Com" );
  5. if (SUCCEEDED(hr))
  6. {
  7. hr = pCom->QueryInterface( IID_IUnknown, reinterpret_cast<void**>(&pUnknown) );
  8. if ( SUCCEEDED( hr ) )
  9. {
  10. ConnectionPointHelper<ComDllLib::_ITestComEvent, CSink3> cph( pUnknown );
  11. LONG c = pCom->Add( 1, 5 );
  12. }
  13. }

  CSink3的实现(与free2000fly写的一样):

  1. // 要响应连接点事件,只需要重写此类
  2. //
  3. class DECLSPEC_UUID( "492194D9-7BEE-422D-AE7C-C43A809F20EC" ) CSink3;
  4. class ATL_NO_VTABLE CSink3
  5. : public CSinkImpT < CSink3, ComDllLib::_ITestComEvent >
  6. {
  7. public:
  8. CSink3( void ) { }
  9. virtual ~CSink3( void ) {}
  10.  
  11. typedef CSinkImpT<CSink3, ComDllLib::_ITestComEvent> _parentClass;
  12.  
  13. STDMETHOD( DoInvoke )(DISPID dispidMember, REFIID riid,
  14. LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  15. EXCEPINFO* pexcepinfo, UINT* puArgErr)
  16. {
  17. // 3. the dispidMember must referenced from .thl file, and you can have a look using oleview.exe
  18. switch ( dispidMember )
  19. {
  20. case 1:
  21. {
  22. CComVariant result( *pvarResult );
  23. if ( SUCCEEDED( result.ChangeType( VT_BSTR ) ) )
  24. ::MessageBoxW( ::GetActiveWindow(), result.bstrVal, L"Sink Message", MB_OK );
  25. return S_OK;
  26. }
  27. default:
  28. break;
  29. }
  30. return _parentClass::DoInvoke( dispidMember, riid,
  31. lcid, wFlags, pdispparams, pvarResult,
  32. pexcepinfo, puArgErr );
  33. }
  34. };

  

借助模板类自动实现COM连接点接收器(Sink)的更多相关文章

  1. 借助模板类自动实现COM连接点接收器(Sink)更新

    之前在借助模板类自动实现COM连接点接收器(Sink)中对原作者的代码进一步封装,弄清了连接点使用的原理,在看ATL代码的过程中,发现ATL本身就提供了AtlAdvise/AtlUnadvise这样的 ...

  2. C++学习34 模板类

    C++除了支持模板函数,还支持模板类.模板类的目的同样是将数据类型参数化. 声明模板类的语法为: template<typename 数据类型参数 , typename 数据类型参数 , …&g ...

  3. C++17尝鲜:类模板中的模板参数自动推导

    模板参数自动推导 在C++17之前,类模板构造器的模板参数是不能像函数模板的模板参数那样被自动推导的,比如我们无法写 std::pair a{1, "a"s}; // C++17 ...

  4. c# 利用t4模板,自动生成Model类

    我们在用ORM(比如dapper)的时候,很多时候都需要自己写Model层(当然也有很多orm框架自带了这种功能,比如ef),特别是表里字段比较多的时候,一个Model要写半天,而且Model如果用于 ...

  5. QCache 缓存(模板类,类似于map,逻辑意义上的缓存,方便管理,和CPU缓存无关。自动获得被插入对象的所有权,超过一定数量就会抛弃某些值)

    在软件开发中,我们经常需要在内存中存储一些临时数据用于后续相关计算.我们一般把这些数据存储到某个数组里,或者STL中的某个合适的容器中.其实,在Qt中直接为我们提供了一个QCache类专用于这种需求. ...

  6. c++模板类

    c++模板类 理解编译器的编译模板过程 如何组织编写模板程序 前言常遇到询问使用模板到底是否容易的问题,我的回答是:“模板的使用是容易的,但组织编写却不容易”.看看我们几乎每天都能遇到的模板类吧,如S ...

  7. C++ 模板函数与模板类

    一.模板函数 函数模板提供了一类函数的抽象,即代表了一类函数.当函数模板被实例化后,它会生成具体的模板函数.例如下面便是一个函数模板:

  8. 开涛spring3(7.2) - 对JDBC的支持 之 7.2 JDBC模板类

    7.2  JDBC模板类 7.2.1  概述 Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDB ...

  9. STL标准模板类

    STL,中文名标准模板库,是一套C++的标准模板类(是类!),包含一些模板类和函数,提供常用的算法和数据结构. STL分为:迭代器,容器,适配器,算法以及函数对象. --迭代器是一种检查容器内元素并遍 ...

随机推荐

  1. 总线宽度VS总线带宽

    很多人把计算机总线宽度和总线带宽混为一谈,其实他们是不一样的. 总线宽度:总线宽度一般指CPU中运算器与存储器之间进行互连的内部总线二进制位数,影响吞吐量,即下面说的总线位宽. 总线带宽:总线的带宽指 ...

  2. zookeeper图形化的客户端工具(ZooInspector)

    1.ZooInspector下载地址 https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip 2.解压压缩 ...

  3. [LeetCode] 417. Pacific Atlantic Water Flow 太平洋大西洋水流

    Given an m x n matrix of non-negative integers representing the height of each unit cell in a contin ...

  4. vue系列--vue是如何实现绑定事件

    一.前言 vuejs中的事件绑定,使用<v-on:事件名 = 函数名>来完成的,这里函数名是定义在Vue实例中的methods对象中的,Vue实例可以直接访问其中的方法. 二.事件绑定方式 ...

  5. vue组件component没效果

    如果实在不知道问题所在,你就看看你的component的命名是不是驼峰命名

  6. linux 开启oracle监听

    secureCRT连接到数据库所在的linux机器,切换到oracle用户模式下 [root@nstlbeta ~]# su - oracle 步骤阅读 2 然后用sqlplus登录到数据库,关闭数据 ...

  7. Java并发之原子性,可见性,有序性

    原子性 ​原子性指的是一个或者多个操作在 CPU 执行的过程中不被中断的特性 在多线程情况下,线程会被操作系统调度进行任务切换,占有CPU时间片段的就执行,否则就阻塞 java中对基础类型的变量赋值是 ...

  8. 024 如何让html引用公共的头部和尾部(多个html文件公用一个header.html和footer.html)

    前端静态html页面,封装公共的头文件(header:顶部页眉,顶部导航栏等部分)和尾部文件(footer:CopyRight.友情链接等部分) 当前方法:通过load()函数,引入公共头部和尾部文件 ...

  9. Linux : Nginx相关

    nginx安装参考链接: https://www.cnblogs.com/kaid/p/7640723.html 自定义编译目录: https://blog.csdn.net/ainuser/arti ...

  10. winform加快窗体加载速度

    //加快控件加载的速度 protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams ...