本文的更新:借助模板类自动实现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. B1043 输出PATest (20 分)

    一.技术总结: 对于哈希字符处理方式,一般是用一个数组存储字符出现的次数,然后再考虑后续. 同时,在输出时,比如这题要输出指定几个字符,我们可以首先统计下这几个字符一共出现的次数sum,然后输出一个就 ...

  2. 《30天自制操作系统》笔记4 --- (Day2 下节)了解如何用汇编写操作系统中的HelloWorld

    关于上一节,我测试了发现3e.4c.4e都OK ,4b 4d 4f都进不去系统还把qemu卡死了. 50不会输出HelloWorld,可能需要hex偶数且在0x3e~4f区间吧.上节复制并运行命令如下 ...

  3. 第01组 Beta冲刺(2/5)

    队名:007 组长博客: https://www.cnblogs.com/Linrrui/p/11998909.html 作业博客: https://edu.cnblogs.com/campus/fz ...

  4. 收藏一份devmem源码

    /* * devmem2.c: Simple program to read/write from/to any location in memory. * * Copyright (C) 2000, ...

  5. Visual Studio 2019(VS2019)正式版注册码秘钥

    Visual Studio 2019 EnterpriseBF8Y8-GN2QH-T84XB-QVY3B-RC4DF Visual Studio 2019 ProfessionalNYWVH-HT4X ...

  6. python read readline readlines区别

    file 对象使用 open 函数来创建,下表列出了 file 对象常用函数read.readline.readlines区别: 1.从文件读取指定的字节数,size如果未给定或为负则读取所有. fi ...

  7. 使用GitHub的仓库以及介绍

    一.创建仓库 假如Responsitory name是Hello-World Description一栏中可以设置仓库的说明. Public, Private  在这一栏可以选择Public还是Pri ...

  8. 将Prometheus alerts保存到elasticsearch

    Prometheus产生的告警通常会发送到alertmanager,当使用alertmanager时,其告警信息仅存在于alertmanager的内存中,无法持久化.故实现了小工具,用于将Promet ...

  9. 系统内置委托Action和func

    Action委托, action是系统内置的委托,它可指向无返回值,没有参数的方法. using System; using System.Collections.Generic; using Sys ...

  10. Nginx 变量参数

    $args #请求中的参数值 $query_string #同 $args $arg_NAME #GET请求中NAME的值 $is_args #如果请求中有参数,值为"?",否则为 ...