在VC++程序中接收COM事件[转贴]
2011-07-04 18:23
232 查看
感谢原作者nelsonc,原文地址:
/article/11735784.html
在VC++程序中接收COM事件
关键字:连接点 COM 事件 IDispEventImpl
接收事件是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就可以通过这个接口发送事件给客户端了。
目前,大多数的连接点都要求通过IDispatch接口发送事件, ATL自动生成的连接点和通过MFC及VB制作的控件都是通过IDispatch接口传递事件。虽然通过IDispatch发送事件可以产生一致的事件接收接口,但由于IDispatch接口的困难,也造成了接收事件代码实现起来更加复杂。
本文中的例子通过ATL的IDispEventImpl模板简化了事件接收对象的编码。同时,本文中的例子也说明了如何在非ATL项目中使用ATL的功能。
2 使用ATL实现连接点
接收事件的就必须实现一个专用的COM对象,这也是实现上最困难的地方。而且,很多连接点都要求通过IDispatch接口传递事件,这样就造成了更大的困难。
我们按照步骤说明如何编写代码在普通的应用程序中接收通过IDispatch接口发送的事件。
2.1 添加ATL头文件
使用ATL前必须包含以下头文件:atlbase.h和atlcom.h,并且定义_Module变量[2]。把以下代码加到stdafx.h是最方便的:
当然,如果项目是通过ATL项目向导产生的就不必再次添加头文件了。
2.2 ATL初始化
使用ATL之前必须初始化,使用完之后还要终止ATL。
对于控制台程序,初始化ATL的方法是:
2.3 事件接收器
2.3.1 引入COM对象
为了方便,本例使用#import引入COM类,也可以通过其它方式引入COM对象,但其它代码要做相应修改。
#import "[COM或TLB的路径]" named_guids, no_namespace
注意,必须要添加named_guids属性。否则,#import就不会生成TLB类的GUID定义。
2.3.2 事件接受器类
A. 类定义
事件接收器是一个类,从IDispEventImpl继承。IDispEventImpl是ATL中的一个模板,专用于接收IDispatch接口的事件。IDispEventImpl的定义是:
事件接收器类的代码如下:
对于每个要响应的事件,要在事件响应类中添加相应的事件响应函数。事件响应函数的名称可以自己选择,但参数和返回值必须和COM对象的定义一致。
事件响应函数是标准的接口方法,应该使用STDMETHOD和STDMETHODIMP声明。
本例中,我们接收一个事件,具有一个整形参数。首先,在事件响应类中添加函数定义:
C.事件对应表
事件响应类中要定义事件对应表,说明哪个函数响应哪个事件。事件对应表通过三个宏实现,它们是:BEGIN_SINK_MAP,SINK_ENTRY_EX,END_SINK_MAP。
BEGIN_SINK_MAP有一个参数,是事件接收类的名称。SINK_ENTRY_EX有四个参数,分别是nID、diid、EventId和FuncName。nID是0、diid是事件接口的GUID、EventId是事件编号、FuncName是响应函数的名称。
以下代码中的事件响应表声明事件编号是1的事件通过EventNotify函数响应。可以写多个SINK_ENTRY_EX来响应多个事件。
事件连接类实现完成之后,要连接到具体的COM对象才可以接收事件。IDispEventImpl通过DispEventAdvise方法连接到COM对象。DispEventAdvise使用要连接的COM对象指针作为参数。连接前要先生成事件接收类的实例,代码如下:
本文的实例可以发邮件到nelsonc@online.sh.cn 索取。例子中包含了发送事件COM对象和接收事件的控制台程序。并且在Virtual Studio 6.0 SP5 + Platform SDK下编译运行成功。[1] 控件是一种特殊的COM对象。
[2] 变量名称必须是_Module
/article/11735784.html
在VC++程序中接收COM事件
关键字:连接点 COM 事件 IDispEventImpl
接收事件是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就可以通过这个接口发送事件给客户端了。
目前,大多数的连接点都要求通过IDispatch接口发送事件, ATL自动生成的连接点和通过MFC及VB制作的控件都是通过IDispatch接口传递事件。虽然通过IDispatch发送事件可以产生一致的事件接收接口,但由于IDispatch接口的困难,也造成了接收事件代码实现起来更加复杂。
本文中的例子通过ATL的IDispEventImpl模板简化了事件接收对象的编码。同时,本文中的例子也说明了如何在非ATL项目中使用ATL的功能。
2 使用ATL实现连接点
接收事件的就必须实现一个专用的COM对象,这也是实现上最困难的地方。而且,很多连接点都要求通过IDispatch接口传递事件,这样就造成了更大的困难。
我们按照步骤说明如何编写代码在普通的应用程序中接收通过IDispatch接口发送的事件。
2.1 添加ATL头文件
使用ATL前必须包含以下头文件:atlbase.h和atlcom.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 "[COM或TLB的路径]" named_guids, no_namespace
注意,必须要添加named_guids属性。否则,#import就不会生成TLB类的GUID定义。
2.3.2 事件接受器类
A. 类定义
事件接收器是一个类,从IDispEventImpl继承。IDispEventImpl是ATL中的一个模板,专用于接收IDispatch接口的事件。IDispEventImpl的定义是:
class IDispEventImpl<nID, T, pdiid, plibid, MajorVer, MinorVer, tihClass> { };nID可以设成0,T是事件接收器类的名字,pdiid是事件接口的GUID,plibid是类型库GUID的指针,MajorVer和MinorVer分别是主、次版本号,tihClass是用于处理TLB的类。TihClass可以使用缺省值。
事件接收器类的代码如下:
class EventReceiver : public IDispEventImpl<0, EventReceiver, &DIID__ConnectPointInterface, &LIBID_xxxLib, 1, 0> { ... };B. 事件响应函数
对于每个要响应的事件,要在事件响应类中添加相应的事件响应函数。事件响应函数的名称可以自己选择,但参数和返回值必须和COM对象的定义一致。
事件响应函数是标准的接口方法,应该使用STDMETHOD和STDMETHODIMP声明。
本例中,我们接收一个事件,具有一个整形参数。首先,在事件响应类中添加函数定义:
class EventReceiver : public ... { ... public: STDMETHOD(EventNotify)(int i); ... }然后添加具体的事件响应代码:
C.事件对应表
事件响应类中要定义事件对应表,说明哪个函数响应哪个事件。事件对应表通过三个宏实现,它们是:BEGIN_SINK_MAP,SINK_ENTRY_EX,END_SINK_MAP。
BEGIN_SINK_MAP有一个参数,是事件接收类的名称。SINK_ENTRY_EX有四个参数,分别是nID、diid、EventId和FuncName。nID是0、diid是事件接口的GUID、EventId是事件编号、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事件
- 在VC++程序中接收COM事件
- 在VC++程序中接收COM事件
- vc6 0 atl工程开发的com组件输出事件到VB,VB接收不到中件响应
- vc6 接收html 的事件
- COM 组件设计与应用(十四)——事件和通知(vc.net)
- VC++调用COM(含连接点事件)过程
- QT编写DLL给外部程序调用,提供VC/C#/C调用示例(含事件)
- VC++利用socket开发udp数据接收程序的步骤(异步方式)
- vc程序大小优化最佳方案(转)http://blog.sina.com.cn/s/blog_4c50333c0100gjs3.html
- vc++ 响应关闭按钮退出程序事件
- vc控制台程序事件处理(转)
- QT编写DLL给外部程序调用,提供VC/C#/C调用示例(含事件)
- vb窗体程序调用vc ATl写的com组建一个小发现
- 利用Delphi编写Socket通信程序-- 转贴收藏 http://dev.rdxx.com/Delphi/DelphiNET/
- QT编写DLL给外部程序调用,提供VC/C#/C调用示例(含事件)good
- VC++ 6.0下编写COM客户程序的三种方法(转载)
- vc++ 单文档程序添加窗口移动事件(不是大小改变),以实现子窗口的伴随移动
- VC:透明窗体+接收鼠标事件
- VC++ 6.0下编写COM客户程序的三种方法