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

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

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

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

  

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

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

  

接口类对象:

class ATL_NO_VTABLE Cvv :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<Cvv, &CLSID_vv>,
public Ivv
{
public:
Cvv()
{
for(int i=0; i<10; i++) // 初始化所有的回调接口为 NULL
{
m_pCallBack[i] = NULL;
}
} DECLARE_REGISTRY_RESOURCEID(IDR_VV) BEGIN_COM_MAP(Cvv)
COM_INTERFACE_ENTRY(Ivv)
END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct()
{
return S_OK;
} void FinalRelease()
{
} public: private:
Iww * m_pCallBack[10];
public:
STDMETHOD(Advise)(Iww* pCallBack, LONG* pdwCookie);
STDMETHOD(UnAdvise)(LONG dwCookie);
STDMETHOD(Add)(LONG n1, LONG n2);
}; OBJECT_ENTRY_AUTO(__uuidof(vv), Cvv) STDMETHODIMP Cvv::Advise(Iww* pCallBack, LONG* pdwCookie)
{
// TODO: Add your implementation code here
if( NULL == pCallBack )
return E_INVALIDARG; for( int i=0; i<10; i++) // 寻找一个保存该接口指针的位置
{
if( NULL == m_pCallBack[i] ) // 找到了
{
m_pCallBack[i] = pCallBack; // 保存到数组中
m_pCallBack[i]->AddRef(); // 指针计数器 +1 *pdwCookie = i + 1; // cookie 就是数组下标
// +1 的目的是避免使用0,因为0表示无效 return S_OK;
}
}
return E_OUTOFMEMORY; // 超过10个连接,内存不够用啦
} STDMETHODIMP Cvv::UnAdvise(LONG dwCookie)
{
// TODO: Add your implementation code here
if( dwCookie<1 || dwCookie>10 ) // 这是谁干的呀?乱给参数
return E_INVALIDARG; if( NULL == m_pCallBack[ dwCookie - 1 ] ) // 参数错误,或该接口指针已经无效了
return E_INVALIDARG; m_pCallBack[ dwCookie -1 ]->Release(); // 指针计数器 -1
m_pCallBack[ dwCookie -1 ] = NULL; // 空出该下标的数组元素 return S_OK;
} STDMETHODIMP Cvv::Add(LONG n1, LONG n2)
{
// TODO: Add your implementation code here
long nResult = n1 + n2;
for( int i=0; i<10; i++)
{
if( m_pCallBack[i] ) //如果回调接口有效
m_pCallBack[i]->Fire_Result( nResult ); // 则发出事件/通知
} return S_OK;
}

  

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

class CSink :public Iww
{
public:
CSink(void);
~CSink(void); STDMETHOD(QueryInterface)(const struct _GUID &iid,void ** ppv);
ULONG __stdcall CSink::AddRef(void);
ULONG __stdcall CSink::Release(void);
STDMETHOD(raw_Fire_Result)(long);
};
CSink::CSink(void)
{
} CSink::~CSink(void)
{
}
// STDMETHODIMP 是宏,等价于 long __stdcall
STDMETHODIMP CSink::QueryInterface(const struct _GUID &iid,void ** ppv)
{
*ppv=this;
return S_OK;
} ULONG __stdcall CSink::AddRef(void)
{ return 1; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的 ULONG __stdcall CSink::Release(void)
{ return 0; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的 STDMETHODIMP CSink::raw_Fire_Result(long nResult)
{
// 如果完成了连接,当计算有结果后,该函数会被调用。完成组件通知的功能
CString str;
str.Format(_T("%d"),nResult);
MessageBox(str);
return S_OK;
}

  

4.调用步骤

CSink m_sink;
IvvPtr m_spCom;
DWORD m_dwCookie; HRESULT hr = m_spCom.CreateInstance(__uuidof(vv) );
if( FAILED( hr ) )
{
AfxMessageBox( _T("COM对象初始化失败") );
CDialog::OnCancel();
}
hr = m_spCom->Advise( &m_sink, (long *)&m_dwCookie );
if( SUCCEEDED( hr ) )
{
AfxMessageBox( _T("Advise调用成功。已经正确连接") );
}
else
{
AfxMessageBox( _T("Advise 调用失败") );
}
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. 关于【vue + element-ui Table的数据多选,多页选择数据回显,分页记录保存选中的数据】的优化

    之前写的[vue + element-ui Table的数据多选,多页选择数据回显,分页记录保存选中的数据]这篇博客.功能虽然实现了相对应的功能.但是用起来很不爽.所以进行了优化. 备注:最近可能没时 ...

  2. Emiya 家今天的饭

    \(dp_{i,j,k}\)表示前\(i\)种烹饪方法,假设最多的是食材\(j\),食材\(j\)比其他食材多\(k\)次出现 其中\(i \in [1,n],j \in [1,m],k \in [- ...

  3. 1.2 lvm镜像卷

    镜像能够分配物理分区的多个副本,从而提高数据的可用性.当某个磁盘发生故障并且其物理分区变为不可用时,您仍然可以访问可用磁盘上的镜像数据.LVM 在逻辑卷内执行镜像.  系统版本: # cat /etc ...

  4. Spring AOP的常用方法

    转  https://blog.csdn.net/u014745069/article/details/84887765

  5. SpringBoot+Vue前后端分离项目,maven package自动打包整合

    起因:看过Dubbo管控台的都知道,人家是个前后端分离的项目,可是一条打包命令能让两个项目整合在一起,我早想这样玩玩了. 1. 建立个maven父项目 next 这个作为父工程,next Finish ...

  6. 小白的C++之路——结构体

    结构体与数组不同的是结构体能包含不同类型的数据,像一个综合性的仓库,更加灵活. #include <iostream> #include <string> #include & ...

  7. php 函数篇

    1.array_values($data); 注:将关联数组转化为索引数组 <?php $a=array("Name"=>"Bill"," ...

  8. 测试代码的练习——python编程从入门到实践

    11-1 城市和国家:编写一个函数,它接受两个形参:一个城市名和一个国家名.这个函数返回一个格式为City,Country的字符串,如Santiago,Chile.这个函数存储在一个名为city_fu ...

  9. HTML登录注册页面简单实现

    github:传送门 , 码云: 传送门 效果参考: 登录页面,注册页面 使用了bootstrap,jQuery. 后端使用的CGI处理表单,存入MySQL数据库.(之后更新) 登录页面源码 < ...

  10. golang微服务框架go-micro 入门笔记1.搭建 go-micro环境

    微服务的本质是让专业的人做专业的事情,做出更好的东西. golang具备高并发,静态编译等特性,在性能.安全等方面具备非常大的优势.go-micro是基于golang的微服务编程框架,go-micro ...