在VC++程序中接收COM事件

原创 2003年06月03日 07:48:00

VC++程序中接收COM事件

关键字:连接点 COM 事件 IDispEventImpl

 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

接收事件是COM客户端中非常重要的功能。但是除了在MFC中能够接收控件[1]所发出的事件以外,VC++不能自动生成接收事件的代码。为了接收普通COM的事件,必须自行编写接收事件的代码。本文通过一个具体的实例说明如何在VC++程序中通过ATL编写接收COM事件的代码,当然,程序本身不必是ATL项目。

1      COM事件原理

COM对象通过连接点实现发送事件的功能。每个连接点都规定了接收事件用的接口,而客户程序通过实现了这个接口的对象接收事件。

如下图所示,假设COM对象A的连接点要求事件接收对象实现IEventSink接口,整个事件接收过程是这样的:首先,客户程序创建COM对象A和用于接收COM对象A事件的事件接收对象B。接下来,客户程序在COM对象A中注册COM对象B的事件接收接口IEventSink。然后,COM对象A就可以通过这个接口发送事件给客户端了。

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />CSDN_Dev_Image_2003-6-22320050.wmz

目前,大多数的连接点都要求通过IDispatch接口发送事件, ATL自动生成的连接点和通过MFCVB制作的控件都是通过IDispatch接口传递事件。虽然通过IDispatch发送事件可以产生一致的事件接收接口,但由于IDispatch接口的困难,也造成了接收事件代码实现起来更加复杂。

本文中的例子通过ATLIDispEventImpl模板简化了事件接收对象的编码。同时,本文中的例子也说明了如何在非ATL项目中使用ATL的功能。

2      使用ATL实现连接点

接收事件的就必须实现一个专用的COM对象,这也是实现上最困难的地方。而且,很多连接点都要求通过IDispatch接口传递事件,这样就造成了更大的困难。

我们按照步骤说明如何编写代码在普通的应用程序中接收通过IDispatch接口发送的事件。

2.1     添加ATL头文件

使用ATL前必须包含以下头文件:atlbase.hatlcom.h,并且定义_Module变量[2]。把以下代码加到stdafx.h是最方便的:

 

#include <atlbase.h>

 

extern CComModule _Module;

#include <atlcom.h>

 

cpp文件中要对_Module进行定义。如下:

 

CcomModule _Module;

 

在添加了这两行之后,我们就可以使用ATL的功能了。而不必创建ATL的项目。

当然,如果项目是通过ATL项目向导产生的就不必再次添加头文件了。

2.2     ATL初始化

使用ATL之前必须初始化,使用完之后还要终止ATL

对于控制台程序,初始化ATL的方法是:

 

int main(int argc, char * argv[], char ** env)

{

_Module.Init(NULL, (HINSTANCE)GetModuleHandle(NULL));

...

 

如果是Windows程序或动态连接库,使用传入的Instance句柄初始化。

 

int WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

_Module.Init(NULL, hInstance);

...

 

终止ATL使用以下方法:

 

_Module.Term();

 

初始化ATL必须在任何ATL操作前进行,而终止则必须在所有ATL操作结束后进行。

2.3     事件接收器

2.3.1        引入COM对象

为了方便,本例使用#import引入COM类,也可以通过其它方式引入COM对象,但其它代码要做相应修改。

 

#import "[COMTLB的路径]" named_guids, no_namespace

 

注意,必须要添加named_guids属性。否则,#import就不会生成TLB类的GUID定义。

2.3.2        事件接受器类

A.            类定义

事件接收器是一个类,从IDispEventImpl继承。IDispEventImplATL中的一个模板,专用于接收IDispatch接口的事件。IDispEventImpl的定义是:

 

class IDispEventImpl<nID, T, pdiid, plibid, MajorVer, MinorVer, tihClass>

{

};

 

nID可以设成0T是事件接收器类的名字,pdiid是事件接口的GUIDplibid是类型库GUID的指针,MajorVerMinorVer分别是主、次版本号,tihClass是用于处理TLB的类。TihClass可以使用缺省值。

事件接收器类的代码如下:

 

class EventReceiver :

    public IDispEventImpl<0,

EventReceiver,

&DIID__ConnectPointInterface,

&LIBID_xxxLib, 1, 0>

{

    ...

};

 

B.            事件响应函数

对于每个要响应的事件,要在事件响应类中添加相应的事件响应函数。事件响应函数的名称可以自己选择,但参数和返回值必须和COM对象的定义一致。

事件响应函数是标准的接口方法,应该使用STDMETHODSTDMETHODIMP声明。

本例中,我们接收一个事件,具有一个整形参数。首先,在事件响应类中添加函数定义:

 

class EventReceiver : public ...

{

...

public:

    STDMETHOD(EventNotify)(int i);

...

}

 

然后添加具体的事件响应代码:

 

STDMETHODIMP EventReceiver::EventNotify(int i)

{

    printf("EventReceiver : %d/n", i);

    return S_OK;

}

 

C.            事件对应表

事件响应类中要定义事件对应表,说明哪个函数响应哪个事件。事件对应表通过三个宏实现,它们是:BEGIN_SINK_MAPSINK_ENTRY_EXEND_SINK_MAP

BEGIN_SINK_MAP有一个参数,是事件接收类的名称。SINK_ENTRY_EX有四个参数,分别是nIDdiidEventIdFuncNamenID0diid是事件接口的GUIDEventId是事件编号、FuncName是响应函数的名称。

以下代码中的事件响应表声明事件编号是1的事件通过EventNotify函数响应。可以写多个SINK_ENTRY_EX来响应多个事件。

 

class EventReceiver : public ...

{

...

public:

BEGIN_SINK_MAP(EventReceiver)

    SINK_ENTRY_EX(0, DIID__IConnectionPointTestObjEvents, 1, EventNotify)

END_SINK_MAP()

...

}

 

2.4     连接对象和关闭连接

事件连接类实现完成之后,要连接到具体的COM对象才可以接收事件。IDispEventImpl通过DispEventAdvise方法连接到COM对象。DispEventAdvise使用要连接的COM对象指针作为参数。连接前要先生成事件接收类的实例,代码如下:

 

EventReceiver * pReceiver = new EventReceiver;

pReceiver->DispEventAdvise(pObj);

 

如果不需要在接收事件,应该使用DispEventUnadvise函数关闭连接,代码如下:

 

pReceiver->DispEventUnadvise(pObj);

 

3      实例

本文的实例可以发邮件到nelsonc@online.sh.cn 索取。例子中包含了发送事件COM对象和接收事件的控制台程序。并且在Virtual Studio 6.0 SP5 + Platform SDK下编译运行成功。


[1] 控件是一种特殊的COM对象。

[2] 变量名称必须是_Module

在VC++程序中接收COM事件

接收事件是COM客户端中非常重要的功能。但是除了在MFC中能够接收控件[1]所发出的事件以外,VC++不能自动生成接收事件的代码。为了接收普通COM的事件,必须自行编写接收事件的代码。本文通过一个具体...
  • shejiannan
  • shejiannan
  • 2013年11月12日 18:24
  • 953

【VC串口】VC串口通信的3种常见方法

本文介绍了在Windows平台下串行通信的实现机制,讨论了根据不同的条件用Visual C++ 设计串行通信程序的三种方法,并结合实际,实现对温度数据的接收监控。 在实验室和工业应用中,串口是常用的...
  • ypist
  • ypist
  • 2013年04月12日 16:12
  • 9620

COM组件VC6.0调试方法

一.打开组件服务,找到你要调试的组件 二.打开组件的属性 三.将调试器路径中的字符串拷贝出来 我的是: "C:\Windows\system32\vsjitdebugger.exe" C:...
  • wanghaihao_1
  • wanghaihao_1
  • 2016年03月31日 14:42
  • 483

vc++导入com组件

1.生成dll 2.工程属性->C/C++->常规->附加库目录:添加dll所在路径 3.#import "组件所在目录myCom.dll" no_namespace...
  • figoleon
  • figoleon
  • 2015年09月17日 14:13
  • 545

总结一下在VC中调用COM组件的方法+++VC调用远程COM+组件

总结一下在VC中调用COM组件的方法 准备及条件: COM服务器为进程内服务器,DLL名为simpCOM.dll,该组件只有一个接口IFoo,该接口只有一个方法HRESULT SayHel...
  • embededvc
  • embededvc
  • 2014年01月29日 16:00
  • 1784

vc中调用Com组件的方法详解

需求: 1.创建myCom.dll,该COM只有一个组件,两个接口:    IGetRes--方法Hello(),    IGetResEx--方法HelloEx() 2.在工程中导入组件或类型库 ...
  • qq1134993111
  • qq1134993111
  • 2015年04月25日 01:05
  • 1401

COM组件设计与应用(十三)——事件和通知(VC6.0)

首页视频教程新闻文章代码在线杂志 会员登陆   注册   文章  代码          视频教程  更多...
  • tangyanzhi1111
  • tangyanzhi1111
  • 2013年07月10日 15:25
  • 1110

串口驱动程序设计详解---串口打开、发送、接收(下)

上一篇博客分析了串口驱动初始化部分,下面逐步分析串口驱动中的打开串口,数据发送和接收! 初始化主要工作流程: 先来分析串口打开操作流程,还是先上图: 这里分析还是离不开上篇博客中的两张重要...
  • coding__madman
  • coding__madman
  • 2016年05月25日 23:10
  • 9559

用ATL创建COM组件详细解说

用ATL创建COM组件详细解说 服务器interfacemicrosoftlibrarybasicobject 一、创建一个模型(工程) MyProj。 二、给模型(工程)增加一个组...
  • jolin678
  • jolin678
  • 2015年09月23日 11:22
  • 532

C#的COM事件在C++中触发和响应的实现

在C++中调用C#开发COM组件时,一般的接口调用都比较容易实现,但是对于COM组件中的事件,C++中要去响应却不好实现。因为C#中事件是采用委托机制,而C++中却没有委托的机制,这样就无法实现对应。...
  • hu_jiangan
  • hu_jiangan
  • 2014年11月01日 20:50
  • 1398
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在VC++程序中接收COM事件
举报原因:
原因补充:

(最多只允许输入30个字)