• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > 深入解析C++程序中激发事件和COM中的事件处理

深入解析C++程序中激发事件和COM中的事件处理

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c++入门经典小程序,c++小游戏程序,c++程序设计教程,超级玛丽c++程序,c++雷达程序等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

本机 C++ 中的事件处理
在处理本机 C ++ 事件时,您分别使用 event_source 和 event_receiver 特性设置事件源和事件接收器,并指定 type=native。这些特性允许应用它们的类在本机的非 COM 上下文中激发和处理事件。
声明事件
在事件源类中,对一个方法声明使用 __event关键字可将该方法声明为事件。请确保声明该方法,但不要定义它;这样做会产生编译器错误,因为将该方法转换为事件时编译器会隐式定义它。本机事件可以是带有零个或多个参数的方法。返回类型可以是 void 或任何整型。
定义事件处理程序
在事件接收器类中,可定义事件处理程序,这些处理程序是具有与它们将处理的事件匹配的签名(返回类型、调用约定和参数)的方法。
将事件处理程序挂钩到事件
同样在事件接收器类中,可使用内部函数 __hook 将事件与事件处理程序关联,并可使用 __unhook 取消事件与事件处理程序的关联。您可将多个事件挂钩到一个事件处理程序,或将多个事件处理程序挂钩到一个事件。
激发事件
若要激发事件,只需调用声明为事件源类中的事件的方法即可。如果处理程序已挂钩到事件,则将调用处理程序。
本机 C++ 事件代码
以下示例演示如何在本机 C++ 中激发事件。若要编译并运行此示例,请参考代码中的注释。
示例代码

// evh_native.cpp
#include <stdio.h>

[event_source(native)]
class CSource {
public:
  __event void MyEvent(int nValue);
};

[event_receiver(native)]
class CReceiver {
public:
  void MyHandler1(int nValue) {
   printf_s("MyHandler1 was called with value %d.\n", nValue);
  }

  void MyHandler2(int nValue) {
   printf_s("MyHandler2 was called with value %d.\n", nValue);
  }

  void hookEvent(CSource* pSource) {
   __hook(&CSource::MyEvent, pSource, &CReceiver::MyHandler1);
   __hook(&CSource::MyEvent, pSource, &CReceiver::MyHandler2);
  }

  void unhookEvent(CSource* pSource) {
   __unhook(&CSource::MyEvent, pSource, &CReceiver::MyHandler1);
   __unhook(&CSource::MyEvent, pSource, &CReceiver::MyHandler2);
  }
};

int main() {
  CSource source;
  CReceiver receiver;

  receiver.hookEvent(&source);
  __raise source.MyEvent(123);
  receiver.unhookEvent(&source);
}

</div>

输出:

MyHandler2 was called with value 123.
MyHandler1 was called with value 123.
</div>

COM 中的事件处理
在 COM 事件处理中,您使用 event_source 和 event_receiver 特性分别设置事件源和事件接收器,并指定 type=com。这些特性为自定义接口、调度接口和双重接口注入相应的代码,从而使这些接口能够应用到的类激发事件并通过 COM 连接点处理事件。
声明事件
在事件源类中,在接口声明上使用 __event 关键字以将该接口的方法声明为事件。当您将该接口的事件作为接口方法调用时,将激发这些事件。事件接口上的方法可以有零个或多个参数(应全是 in 参数)。返回类型可以是 void 或任何整型。
定义事件处理程序
在事件接收器类中,可定义事件处理程序,这些处理程序是具有与它们将处理的事件匹配的签名(返回类型、调用约定和参数)的方法。对于 COM 事件,调用约定不必匹配;有关详细信息,请参阅下文中的依赖于布局的 COM 事件。
将事件处理程序挂钩到事件
同样在事件接收器类中,可使用内部函数 __hook 将事件与事件处理程序关联,并可使用 __unhook 取消事件与事件处理程序的关联。您可将多个事件挂钩到一个事件处理程序,或将多个事件处理程序挂钩到一个事件。
注意
通常,有两种方法使 COM 事件接收器能够访问事件源接口定义。第一种是共享公共头文件,如下所示。第二种是将 #import 与 embedded_idl 导入限定符结合使用,以便让事件源类型库写入到保留了特性生成的代码的 .tlh 文件。
激发事件
若要激发事件,只需调用在事件源类中使用 __event 关键字声明的接口中的方法。如果处理程序已挂钩到事件,则将调用处理程序。
COM 事件代码
下面的示例演示如何在 COM 类中激发事件。若要编译并运行此示例,请参考代码中的注释。

// evh_server.h
#pragma once

[ dual, uuid("00000000-0000-0000-0000-000000000001") ]
__interface IEvents {
  [id(1)] HRESULT MyEvent([in] int value);
};

[ dual, uuid("00000000-0000-0000-0000-000000000002") ]
__interface IEventSource {
  [id(1)] HRESULT FireEvent();
};

class DECLSPEC_UUID("530DF3AD-6936-3214-A83B-27B63C7997C4") CSource;

</div>

接着是服务器:

// evh_server.cpp
// compile with: /LD
// post-build command: Regsvr32.exe /s evh_server.dll
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
#include "evh_server.h"

[ module(dll, name="EventSource", uuid="6E46B59E-89C3-4c15-A6D8-B8A1CEC98830") ];

[coclass, event_source(com), uuid("530DF3AD-6936-3214-A83B-27B63C7997C4")]
class CSource : public IEventSource {
public:
  __event __interface IEvents; 

  HRESULT FireEvent() {
   __raise MyEvent(123);
   return S_OK;
  }
};

</div>

再然后是客户端:

// evh_client.cpp
// compile with: /link /OPT:NOREF
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
#include <stdio.h>
#include "evh_server.h"

[ module(name="EventReceiver") ];

[ event_receiver(com) ]
class CReceiver {
public:
  HRESULT MyHandler1(int nValue) {
   printf_s("MyHandler1 was called with value %d.\n", nValue);
   return S_OK;
  }

  HRESULT MyHandler2(int nValue) {
   printf_s("MyHandler2 was called with value %d.\n", nValue);
   return S_OK;
  }

  void HookEvent(IEventSource* pSource) {
   __hook(&IEvents::MyEvent, pSource, &CReceiver::MyHandler1);
   __hook(&IEvents::MyEvent, pSource, &CReceiver::MyHandler2);
  }

  void UnhookEvent(IEventSource* pSource) {
   __unhook(&IEvents::MyEvent, pSource, &CReceiver::MyHandler1);
   __unhook(&IEvents::MyEvent, pSource, &CReceiver::MyHandler2);
  }
};

int main() {
  // Create COM object
  CoInitialize(NULL);
  {
   IEventSource* pSource = 0;
   HRESULT hr = CoCreateInstance(__uuidof(CSource), NULL,     CLSCTX_ALL, __uuidof(IEventSource), (void **) &pSource);
   if (FAILED(hr)) {
     return -1;
   }

   // Create receiver and fire event
   CReceiver receiver;
   receiver.HookEvent(pSource);
   pSource->FireEvent();
   receiver.UnhookEvent(pSource);
  }
  CoUninitialize();
  return 0;
}

</div>

输出

MyHandler1 was called with value 123.
MyHandler2 was called with value 123.
</div>

依赖于布局的 COM 事件
布局依赖性只是 COM 编程中的一个问题。在本机和托管事件处理中,处理程序的签名(返回类型、调用约定和参数)必须与其事件匹配,但处理程序的名称不必与其事件匹配。
但是,在 COM 事件处理中,如果将 event_receiver 的 layout_dependent 参数设置为 true,则将强制名称和签名匹配。这意味着事件接收器中处理程序的名称和签名必须与处理程序将挂钩到的事件的名称和签名完全匹配。
当 layout_dependent 设置为 false 时,激发事件方法与挂钩方法(其委托)之间的调用约定和存储类(虚拟、静态等)可以混合和匹配。将 layout_dependent 设置为 true 效率会稍微高一点。
例如,假设 IEventSource 定义为具有下列方法:

[id(1)] HRESULT MyEvent1([in] int value);
[id(2)] HRESULT MyEvent2([in] int value);
</div>

假定事件源具有以下形式:

[coclass, event_source(com)]
class CSource : public IEventSource {
public:
  __event __interface IEvents;

  HRESULT FireEvent() {
   MyEvent1(123);
   MyEvent2(123);
   return S_OK;
  }
};

</div>

则在事件接收器中,挂钩到 IEventSource 中的方法的任何处理程序必须与其名称和签名匹配,如下所示:

[coclass, event_receiver(com, true)]
class CReceiver {
public:
  HRESULT MyEvent1(int nValue) { // name and signature matches MyEvent1
   ...
  }
  HRES



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • c++ 端口扫描程序实现案例
  • 学好C++必须做到的50条 绝对经典!
  • 在C++程序中开启和禁用Windows设备的无线网卡的方法
  • 深入解析C++程序中激发事件和COM中的事件处理
  • 使用C++程序获取新浪行情数据的方法
  • 探究在C++程序并发时保护共享数据的问题
  • C++抽奖程序实现方法
  • C++键盘记录程序代码
  • C++实现闹钟程序的方法

相关文章

  • 2017-05-28dword ptr指令详细解析
  • 2017-05-28详解C语言编程中的函数指针以及函数回调
  • 2017-05-28MFC对话框中添加状态栏的方法
  • 2017-05-28C++中指向结构体变量的指针
  • 2017-05-28如何利用tinyxml操纵xml及注意问题
  • 2017-05-28C语言for语句用法详解
  • 2017-05-28C/C++中指针和引用之相关问题深入研究
  • 2017-05-28浅析内存对齐与ANSI C中struct型数据的内存布局
  • 2017-05-28DSP中浮点转定点运算--定点数的加减乘除运算
  • 2017-05-28VC++获得当前进程运行目录的方法

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 详解 linux c++的编译器g++的基本使用
    • C语言开发简易版扫雷小游戏
    • 详解C++编程中的sizeof运算符与typeid运算符
    • C/C++ 多线程的学习心得总结
    • win32使用openfilename浏览文件窗口示例
    • C++ 中重载和运算符重载加号实现矩阵相加实例代码
    • 基于Linux系统调用--getrlimit()与setrlimit()函数的方法
    • C++实现单链表删除倒数第k个节点的方法
    • 使用代码验证linux子进程与父进程的关系
    • 位运算实现十进制转换为二进制

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有