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

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

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

#if !defined( __sinkimpl_h_INCLUDED__ )
#define __sinkimpl_h_INCLUDED__ #if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000 template<typename T, typename EventInterface, const GUID * evtLibID = NULL >
class ATL_NO_VTABLE CSinkImpT
: public CComObjectRootEx<CComSingleThreadModel>
, public CComCoClass<CSinkImpT<T, EventInterface, evtLibID>, &__uuidof(T)>
, public IDispatchImpl < EventInterface, &__uuidof(EventInterface), evtLibID >
{
public:
CSinkImpT() {}
virtual ~CSinkImpT() {} typedef IDispatchImpl<EventInterface, &__uuidof(EventInterface), evtLibID> _parentClass;
typedef CSinkImpT<T, EventInterface, evtLibID> _thisClass; STDMETHOD( Invoke )(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
T * pThis = static_cast<T *>(this);
return pThis->DoInvoke( dispidMember, riid,
lcid, wFlags, pdispparams, pvarResult,
pexcepinfo, puArgErr );
} DECLARE_NO_REGISTRY() DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP( _thisClass )
COM_INTERFACE_ENTRY( IDispatch )
COM_INTERFACE_ENTRY( EventInterface )
END_COM_MAP(); STDMETHOD( DoInvoke )(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
return _parentClass::Invoke( dispidMember, riid,
lcid, wFlags, pdispparams, pvarResult,
pexcepinfo, puArgErr );
}
}; inline HRESULT WINAPI GetConnectPoint( IUnknown * pItf, const IID & rSinkIID, IConnectionPoint ** ppCP )
{
HRESULT hr = E_FAIL;
do
{
if ( pItf == NULL || ppCP == NULL ) { break; } CComQIPtr<IConnectionPointContainer> spContainer;
hr = pItf->QueryInterface( &spContainer );
if ( FAILED( hr ) ) { break; } hr = spContainer->FindConnectionPoint( rSinkIID, ppCP );
} while ( FALSE );
return hr;
} ///////////////////////////////////////////////////////////////////////////////////////////////////////
// 使用方法:
// ComDllLib::ITestComPtr pCom;
// HRESULT hr = pCom.CreateInstance( L"Test.Com" );
// ConnectionPointHelper<ComDllLib::_ITestComEvent, CSink3> cph( pCom );
//
template<typename EventInterface, typename EventProcessor>
class ConnectionPointHelper
{
CComPtr<IUnknown> m_spInterface;
DWORD m_dwCookie;
public:
ConnectionPointHelper( IUnknown* pInterface ) : m_spInterface( pInterface ), m_dwCookie( 0 ) { Connect(); }
~ConnectionPointHelper() { Disconnect(); }
protected:
void Connect()
{
HRESULT hr = E_FAIL;
do
{
if ( m_spInterface == NULL || m_dwCookie != 0 ) { break; } CComQIPtr<IConnectionPoint> spCP;
hr = GetConnectPoint( m_spInterface, __uuidof(EventInterface), &spCP );
if ( FAILED( hr ) ){ break; } CComQIPtr<IDispatch> spSink;
{
CComObject<EventProcessor> * pTmp = NULL;
hr = CComObject<EventProcessor>::CreateInstance( &pTmp );
if ( FAILED( hr ) ){ break; } pTmp->AddRef();
hr = pTmp->QueryInterface( &spSink );
pTmp->Release(); if ( FAILED( hr ) ){ break; }
} spCP->Advise( spSink, &m_dwCookie ); } while ( FALSE );
} void Disconnect()
{
HRESULT hr = E_FAIL;
do {
if ( m_dwCookie == 0 ) { break; } CComQIPtr<IConnectionPoint> spCP; hr = GetConnectPoint( m_spInterface, __uuidof(EventInterface), &spCP );
if ( FAILED( hr ) ){ break; } hr = spCP->Unadvise( m_dwCookie );
m_dwCookie = 0;
} while ( FALSE );
} };
#endif // !defined( __sinkimpl_h_INCLUDED__ )

  

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

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

// 要响应连接点事件,只需要重写此类
//
class DECLSPEC_UUID( "492194D9-7BEE-422D-AE7C-C43A809F20EC" ) CSink3;
class ATL_NO_VTABLE CSink3
: public CSinkImpT < CSink3, ComDllLib::_ITestComEvent >
{
public:
CSink3( void ) { }
virtual ~CSink3( void ) {} typedef CSinkImpT<CSink3, ComDllLib::_ITestComEvent> _parentClass; STDMETHOD( DoInvoke )(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
// 3. the dispidMember must referenced from .thl file, and you can have a look using oleview.exe
switch ( dispidMember )
{
case 1:
{
CComVariant result( *pvarResult );
if ( SUCCEEDED( result.ChangeType( VT_BSTR ) ) )
::MessageBoxW( ::GetActiveWindow(), result.bstrVal, L"Sink Message", MB_OK );
return S_OK;
}
default:
break;
}
return _parentClass::DoInvoke( dispidMember, riid,
lcid, wFlags, pdispparams, pvarResult,
pexcepinfo, puArgErr );
}
};

  

借助模板类自动实现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. CSP2019题解

    CSP2019题解 格雷码 按照生成的规则模拟一下即可. 代码 括号树 看到括号匹配首先想到用栈,然后又在树上就可以想到可追溯化栈. 令\(a_i=1\)表示\(i\)号节点上的括号为(,否则为), ...

  2. 【LGR-060】洛谷10月月赛 I

    A - 打字练习 出题:memset0 送分模拟题,按题意模拟即可. 需要注意的是对退格键的判断,如果光标已经在行首,则直接忽略被读入的退格键. B - 小猪佩奇爬树 出题:_QAQ 维护所有相同节点 ...

  3. [LeetCode] 272. Closest Binary Search Tree Value II 最近的二分搜索树的值之二

    Given a non-empty binary search tree and a target value, find k values in the BST that are closest t ...

  4. Sentinel: 分布式系统的流量防卫兵

    前言 在 Spring Cloud 体系中,熔断降级我们会使用 Hystrix 框架,限流通常会在 Zuul 中进行处理,Zuul 中没有自带限流的功能,我们可以自己做限流或者集成第三方开源的限流框架 ...

  5. linux内核动态调试技术

    动态调试功能就是你可以决定在程序运行过程中是否要 pr_debug(), dev_dbg(), print_hex_dump_debug(), print_hex_dump_bytes() 这些函数正 ...

  6. linux中断子系统

    参考引用:http://www.wowotech.net/sort/irq_subsystem wowotech:一个很好的linux技术博客. 一.概述 目的 kernel管理硬件设备的方式:轮询. ...

  7. useEffect传入第二个参数陷入死循环

    最近新项目刚上手,就用了react的hooks,之前也看过hooks的不少文章,只是还没实战实战. 业务场景1:需要在页面一开始时得到一个接口的返回值,取调用另一个接口. 我的思路是,先设置这个接口的 ...

  8. 23 Maven工程module的移除和重新导入

    1.移除module 移除后: 点击右侧的maven projects: 2.重新导入刚才移除的module (1)方法1 (2)方法2 Ctrl+Shift+ALT+S的快捷键 选择modules ...

  9. postgresql NUMERIC(precision, scale)

  10. cookie、session和token的概念

    Cookie.Session和Token都是为了解决Web身份校验而产生的,这里对它们的概念做一个简单了解. Web身份校验的发展 很久很久以前,Web基本上就是文档的浏览而已.既然是浏览,作为服务器 ...