情景:被调用者--COM组件;调用者---外部程序
作用:COM组件 到 外部程序 的消息传递
方法:
1.外部程序通过接口类对象,访问接口类的方法。COM对象通过连接点方式,进行消息的反向传递。
2.外部程序通过接口类对象,访问接口类的方法。外部程序对接口类设置回调指针,进行消息的回调。

本文讲第二种方法。
直接上代码:

1.添加新的接口类Iww,作为回调函数类。类似连接点对象的作用。

  1. interface Iww : IUnknown{
  2. [helpstring("method Fire_Result")] HRESULT Fire_Result([in] LONG nResult);
  3. };

  

2.原有COM对象接口类,添加一个设置回调函数的方法Advise。

  1. interface Ivv : IUnknown{
  2. [helpstring("method Advise")] HRESULT Advise(Iww* pCallBack, [out] LONG* pdwCookie);
  3. [helpstring("method UnAdvise")] HRESULT UnAdvise(LONG dwCookie);
  4. [helpstring("method Add")] HRESULT Add(LONG n1, LONG n2);
  5. };

  

接口类对象:

  1. class ATL_NO_VTABLE Cvv :
  2. public CComObjectRootEx<CComSingleThreadModel>,
  3. public CComCoClass<Cvv, &CLSID_vv>,
  4. public Ivv
  5. {
  6. public:
  7. Cvv()
  8. {
  9. for(int i=0; i<10; i++) // 初始化所有的回调接口为 NULL
  10. {
  11. m_pCallBack[i] = NULL;
  12. }
  13. }
  14.  
  15. DECLARE_REGISTRY_RESOURCEID(IDR_VV)
  16.  
  17. BEGIN_COM_MAP(Cvv)
  18. COM_INTERFACE_ENTRY(Ivv)
  19. END_COM_MAP()
  20.  
  21. DECLARE_PROTECT_FINAL_CONSTRUCT()
  22.  
  23. HRESULT FinalConstruct()
  24. {
  25. return S_OK;
  26. }
  27.  
  28. void FinalRelease()
  29. {
  30. }
  31.  
  32. public:
  33.  
  34. private:
  35. Iww * m_pCallBack[10];
  36. public:
  37. STDMETHOD(Advise)(Iww* pCallBack, LONG* pdwCookie);
  38. STDMETHOD(UnAdvise)(LONG dwCookie);
  39. STDMETHOD(Add)(LONG n1, LONG n2);
  40. };
  41.  
  42. OBJECT_ENTRY_AUTO(__uuidof(vv), Cvv)
  43.  
  44. STDMETHODIMP Cvv::Advise(Iww* pCallBack, LONG* pdwCookie)
  45. {
  46. // TODO: Add your implementation code here
  47. if( NULL == pCallBack )
  48. return E_INVALIDARG;
  49.  
  50. for( int i=0; i<10; i++) // 寻找一个保存该接口指针的位置
  51. {
  52. if( NULL == m_pCallBack[i] ) // 找到了
  53. {
  54. m_pCallBack[i] = pCallBack; // 保存到数组中
  55. m_pCallBack[i]->AddRef(); // 指针计数器 +1
  56.  
  57. *pdwCookie = i + 1; // cookie 就是数组下标
  58. // +1 的目的是避免使用0,因为0表示无效
  59.  
  60. return S_OK;
  61. }
  62. }
  63. return E_OUTOFMEMORY; // 超过10个连接,内存不够用啦
  64. }
  65.  
  66. STDMETHODIMP Cvv::UnAdvise(LONG dwCookie)
  67. {
  68. // TODO: Add your implementation code here
  69. if( dwCookie<1 || dwCookie>10 ) // 这是谁干的呀?乱给参数
  70. return E_INVALIDARG;
  71.  
  72. if( NULL == m_pCallBack[ dwCookie - 1 ] ) // 参数错误,或该接口指针已经无效了
  73. return E_INVALIDARG;
  74.  
  75. m_pCallBack[ dwCookie -1 ]->Release(); // 指针计数器 -1
  76. m_pCallBack[ dwCookie -1 ] = NULL; // 空出该下标的数组元素
  77.  
  78. return S_OK;
  79. }
  80.  
  81. STDMETHODIMP Cvv::Add(LONG n1, LONG n2)
  82. {
  83. // TODO: Add your implementation code here
  84. long nResult = n1 + n2;
  85. for( int i=0; i<10; i++)
  86. {
  87. if( m_pCallBack[i] ) //如果回调接口有效
  88. m_pCallBack[i]->Fire_Result( nResult ); // 则发出事件/通知
  89. }
  90.  
  91. return S_OK;
  92. }

  

3.外部程序,新建一个类继承Iww,并实现raw_Fire_Result方法。
#import "..\ee.tlb" no_namespace

  1. class CSink :public Iww
  2. {
  3. public:
  4. CSink(void);
  5. ~CSink(void);
  6.  
  7. STDMETHOD(QueryInterface)(const struct _GUID &iid,void ** ppv);
  8. ULONG __stdcall CSink::AddRef(void);
  9. ULONG __stdcall CSink::Release(void);
  10. STDMETHOD(raw_Fire_Result)(long);
  11. };
  12. CSink::CSink(void)
  13. {
  14. }
  15.  
  16. CSink::~CSink(void)
  17. {
  18. }
  19. // STDMETHODIMP 是宏,等价于 long __stdcall
  20. STDMETHODIMP CSink::QueryInterface(const struct _GUID &iid,void ** ppv)
  21. {
  22. *ppv=this;
  23. return S_OK;
  24. }
  25.  
  26. ULONG __stdcall CSink::AddRef(void)
  27. { return 1; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的
  28.  
  29. ULONG __stdcall CSink::Release(void)
  30. { return 0; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的
  31.  
  32. STDMETHODIMP CSink::raw_Fire_Result(long nResult)
  33. {
  34. // 如果完成了连接,当计算有结果后,该函数会被调用。完成组件通知的功能
  35. CString str;
  36. str.Format(_T("%d"),nResult);
  37. MessageBox(str);
  38. return S_OK;
  39. }

  

4.调用步骤

  1. CSink m_sink;
  2. IvvPtr m_spCom;
  3. DWORD m_dwCookie;
  4.  
  5. HRESULT hr = m_spCom.CreateInstance(__uuidof(vv) );
  6. if( FAILED( hr ) )
  7. {
  8. AfxMessageBox( _T("COM对象初始化失败") );
  9. CDialog::OnCancel();
  10. }
  11. hr = m_spCom->Advise( &m_sink, (long *)&m_dwCookie );
  12. if( SUCCEEDED( hr ) )
  13. {
  14. AfxMessageBox( _T("Advise调用成功。已经正确连接") );
  15. }
  16. else
  17. {
  18. AfxMessageBox( _T("Advise 调用失败") );
  19. }
  20. m_spCom->Add(1,5);

  

回调方式进行COM组件对外消息传递的更多相关文章

  1. iOS_Swift初识之使用三种回调方式自定义Button

    最近在学习Swift ,发现青玉伏案大神早期用OC写的一篇博客--IOS开发之自定义Button(集成三种回调模式)  很适合用来熟悉Swift的回调方式,于是我就用Swift翻版了一下,具体实现原理 ...

  2. WPF 海康威视网络摄像头回调方式实现断连提示,降低时延

    原文:WPF 海康威视网络摄像头回调方式实现断连提示,降低时延 项目需要使用海康威视网络摄像头接入实时视频数据,使用海康威视官方SDK开发,发现没有断连提示的功能,故开发了一个断连提示的功能 在开发过 ...

  3. 多对多三种创建方式、forms组件、cookies与session

    多对多三种创建方式.forms组件.cookies与session 一.多对多三种创建方式 1.全自动 # 优势:不需要你手动创建第三张表 # 不足:由于第三张表不是你手动创建的,也就意味着第三张表字 ...

  4. Vue3 SFC 和 TSX 方式调用子组件中的函数

    在开发中会遇到这样的需求:获取子组件的引用,并调用子组件中定义的方法.如封装了一个表单组件,在父组件中需要调用这个表单组件的引用,并调用这个表单组件的校验表单函数或重置表单函数.要实现这个功能,首先要 ...

  5. Android简易实战教程--第四十七话《使用OKhttp回调方式获取网络信息》

    在之前的小案例中写过一篇使用HttpUrlConnection获取网络数据的例子.在OKhttp盛行的时代,当然要学会怎么使用它,本篇就对其基本使用做一个介绍,然后再使用它的接口回调的方式获取相同的数 ...

  6. React组件导入的两种方式(动态导入组件的实现)

    一. react组件两种导入方式 React组件可以通过两种方式导入另一个组件 import(常用) import component from './component' require const ...

  7. React-Native子组件修改父组件的几种方式,兄弟组件状态修改(转载)

    子组件修改父组件的状态,在开发中非常常见,下面列举了几种方式.DeviceEventEmitter可以跨组件,跨页面进行数据传递,还有一些状态的修改.http://www.jianshu.com/p/ ...

  8. 使用回调方式写POI导入excel工具类

    场景是这样的:为了做一个excel导入的功能,为了尽可能的写一个通用的工具类,将与poi有关的东西都封装起来,以便以其他人员只用关心自己的业务,不用和poi打交道. 写到最后,现在还是会有poi的东西 ...

  9. C/C++回调方式系列之一 函数指针和函数回调模式

    一.函数指针 1. 函数的定义 return_type function_name(parameter list) { function_body } return_type: 返回值,函数一定有返回 ...

随机推荐

  1. DDD分层架构的三种模式

    引言 在讨论DDD分层架构的模式之前,我们先一起回顾一下DDD和分层架构的相关知识. DDD DDD(Domain Driven Design,领域驱动设计)作为一种软件开发方法,它可以帮助我们设计高 ...

  2. RSA非对称式加解密笔记

    1.服务器生成[公钥]和[私钥],成对生成: 2.客户端生成证书信息,使用[公钥]进行加密,前提是有公钥,并生成证书信息: 3.客户端发送自身的计算机名.MAC.用户名.证书内容给服务器: 4.服务器 ...

  3. Python实现树

    树 (tree) 是一种非常高效的非线性存储结构.树,可以很形象的理解,有根,有叶子,对应在数据结构中就是根节点.叶子节点,同一层的叶子叫兄弟节点,邻近不同层的叫父子节点,非常好理解. 注:定义来自百 ...

  4. 在linux系统下安装两个nginx以及启动、停止、重起

    如果没有安装过nginx请看:linux下nginx部署以及配置详解 1.第一个nginx已经安装完成后,现在安装第二个nginx 启动:sudo /usr/sbin/nginx3 重起:sudo / ...

  5. kubernetes-dashboard登录出现forbidden 403

    登录k8s dashboard https://xxxxx:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard ...

  6. netcore 实现跨应用的分布式session

    需求场景 网站a,域名为 a.site.com 网站b, 域名为 b.site.com 需要在a.b两个站点之间共享session 解决方案 使用redis作为分布式缓存存储 设置sessionId ...

  7. 4_PHP流程控制语句_1_条件控制语句

    以下为学习孔祥盛主编的<PHP编程基础与实例教程>(第二版)所做的笔记. PHP流程控制共有3种类型:条件控制结构.循环结构以及程序跳转和终止语句. 4.1 条件控制语句 4.1.1 if ...

  8. python写文件无法换行的问题

    python写文件无法换行的问题,用'\n'  不行,直接打印的出来了. 网上查了查,都说是用  ‘\r\n’ ,但是这样打出来,不仅换行了,还加了一个空行. windows平台最后结果是    直接 ...

  9. Matlab工厂模式

    工厂模式定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类.工厂模式主要分为简单工厂模式.工厂方法模式以及抽象工厂模式. Obj.m classdef Obj ...

  10. 【DATAGUARD】物理dg配置客户端无缝切换 (八.2)--Fast-Start Failover 的配置

    [DATAGUARD]物理dg配置客户端无缝切换 (八.2)--Fast-Start Failover 的配置 一.1  BLOG文档结构图       一.2  前言部分   一.2.1  导读 各 ...