之前在借助模板类自动实现COM连接点接收器(Sink)中对原作者的代码进一步封装,弄清了连接点使用的原理,在看ATL代码的过程中,发现ATL本身就提供了AtlAdvise/AtlUnadvise这样的机制来简化连接点的使用,CComPtrBase中也有Advise这个成员函数,它是对AtlAdvise,进一步封装,因此,对ConnectionHelper的代码可以再简化,简化后Connect()只有十来行了。原作者写的GetConnectPoint函数也用不上了。

  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. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  51. // ComDllLib::ITestComPtr pCom;
  52. // HRESULT hr = pCom.CreateInstance( L"Test.Com" );
  53. // ConnectionPointHelper<ComDllLib::ITestCom, ComDllLib::_ITestComEvent, CSink3> cph( pCom );
  54. //
  55. template<typename EventInterface, typename EventProcessor>
  56. class ConnectionPointHelper
  57. {
  58. CComPtr<IUnknown> m_spInterface;
  59. DWORD m_dwCookie;
  60. public:
  61. ConnectionPointHelper( IUnknown* pInterface ) : m_spInterface( pInterface ), m_dwCookie( 0 ) { Connect(); }
  62. ~ConnectionPointHelper() { Disconnect(); }
  63. protected:
  64. void Connect()
  65. {
  66. HRESULT hr = E_FAIL;
  67. do
  68. {
  69. if ( m_spInterface == NULL || m_dwCookie != 0 ) { break; }
  70.  
  71. CComObject<EventProcessor> * pTmp = NULL;
  72. hr = CComObject<EventProcessor>::CreateInstance( &pTmp );
  73. if ( FAILED( hr ) ){ break; }
  74.  
  75. CComQIPtr<IUnknown, &IID_IUnknown> spSink( pTmp );
  76.  
  77. hr = m_spInterface.Advise( spSink, __uuidof(EventInterface), &m_dwCookie );
  78.  
  79. } while ( FALSE );
  80. }
  81.  
  82. void Disconnect()
  83. {
  84. HRESULT hr = E_FAIL;
  85. do {
  86. if ( m_dwCookie == 0 ) { break; }
  87.  
  88. AtlUnadvise( m_spInterface, __uuidof(EventInterface), m_dwCookie );
  89. m_dwCookie = 0;
  90.  
  91. } while ( FALSE );
  92. }
  93.  
  94. };
  95. #endif // !defined( __sinkimpl_h_INCLUDED__ )

  以上就是全部代码,减少到不到100行。

使用方法:

  1. { // .tlh中的接口方式调用
  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. }
  14. }

  

  1. { // IDispatch方式调用
  2. CComPtr<IDispatch> spDisp;
  3. HRESULT hr = spDisp.CoCreateInstance( L"Test.Com" );
  4. if ( SUCCEEDED( hr ) )
  5. {
  6. CComQIPtr<IUnknown, &IID_IUnknown> spUnknown( spDisp );
  7. ConnectionPointHelper<ComDllLib::_ITestComEvent, CSink3> cph( spUnknown );
  8. _variant_t ret;
  9. _variant_t m = 2, n = 3;
  10. spDisp.Invoke2( (LPCOLESTR) L"Add", &m, &n, &ret );
  11. }
  12. }

  

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

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

    本文的更新:借助模板类自动实现COM连接点接收器(Sink)更新 (2014-06-09 17:09) 最初的代码源自free2000fly的一个标准的 COM 连接点接收器(Sink)的实现, 使用 ...

  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. MySQL实战45讲学习笔记:第十三讲

    一.引子 经常会有同学来问我,我的数据库占用空间太大,我把一个最大的表删掉了一半的数据,怎么表文件的大小还是没变? 那么今天,我就和你聊聊数据库表的空间回收,看看如何解决这个问题. 这里,我们还是针对 ...

  2. CSP-S考前救急(考试前还是别复习了,事实证明复习了也没考到...

    “不要为明天而忧虑,因为明天自有明天的忧虑:一天的难处一天当就够了.” 念念不忘,必有回响. 考试结束前15分钟停止写代码.然后按照以下顺序进行检查: -检查文件名是否写错-检查是否打开文件输入输出 ...

  3. Vertica性能分析

    Vertica的特点简单的说可以总结为:列存储.MPP架构.技术比较新.列存储本身带来了数据高度压缩的便利,MPP架构使得可以用相对廉价的PC级服务器横向扩展到较大规模(PB级),05年才问世使得它在 ...

  4. 实验一 Linux基础与Java开发环境

    实验一 (一)实验内容 基于命令行和IDE(Intellj IDEA 简易教程http://www.cnblogs.com/rocedu/p/4421202.html)进行简单的Java程序编辑.编译 ...

  5. 【操作系统之十四】iptables扩展模块

    1.iprange 使用iprange扩展模块可以指定"一段连续的IP地址范围",用于匹配报文的源地址或者目标地址.--src-range:匹配报文的源地址所在范围--dst-ra ...

  6. Mybatis设置主键自增

    <insert id="insertArea" useGeneratedKeys="true" keyProperty="areaId" ...

  7. javascript参数化拼接字符串两种方法

    javascript如果直接使用字符串+的话,会被大量单引号搞晕,可以有两种比较简单的方法使用参数化拼接. 方式一,传统js //示例:StringFormat("abc{0}def&quo ...

  8. MySQL如何定位并优化慢查询sql

    1.如何定位并优化慢查询sql a.根据慢日志定位慢查询sql SHOW VARIABLES LIKE '%query%'      查询慢日志相关信息 slow_query_log 默认是off关闭 ...

  9. Linq 用得太随意导致的性能问题一则

    问题场景 有一个很多条数据的数据库(数据源),在其中找出指定的项,这些项的 ID 位于 给定的列表中,如 TargetList 中. private readonly IDictionary<s ...

  10. Python - 注释 - 第四天

    注释 确保对模块, 函数, 方法和行内注释使用正确的风格 Python中的注释有单行注释和多行注释: Python中单行注释以 # 开头,例如: # 这是一个注释 print('Hello Pytho ...