回调方式进行COM组件对外消息传递
情景:被调用者--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组件对外消息传递的更多相关文章
- iOS_Swift初识之使用三种回调方式自定义Button
最近在学习Swift ,发现青玉伏案大神早期用OC写的一篇博客--IOS开发之自定义Button(集成三种回调模式) 很适合用来熟悉Swift的回调方式,于是我就用Swift翻版了一下,具体实现原理 ...
- WPF 海康威视网络摄像头回调方式实现断连提示,降低时延
原文:WPF 海康威视网络摄像头回调方式实现断连提示,降低时延 项目需要使用海康威视网络摄像头接入实时视频数据,使用海康威视官方SDK开发,发现没有断连提示的功能,故开发了一个断连提示的功能 在开发过 ...
- 多对多三种创建方式、forms组件、cookies与session
多对多三种创建方式.forms组件.cookies与session 一.多对多三种创建方式 1.全自动 # 优势:不需要你手动创建第三张表 # 不足:由于第三张表不是你手动创建的,也就意味着第三张表字 ...
- Vue3 SFC 和 TSX 方式调用子组件中的函数
在开发中会遇到这样的需求:获取子组件的引用,并调用子组件中定义的方法.如封装了一个表单组件,在父组件中需要调用这个表单组件的引用,并调用这个表单组件的校验表单函数或重置表单函数.要实现这个功能,首先要 ...
- Android简易实战教程--第四十七话《使用OKhttp回调方式获取网络信息》
在之前的小案例中写过一篇使用HttpUrlConnection获取网络数据的例子.在OKhttp盛行的时代,当然要学会怎么使用它,本篇就对其基本使用做一个介绍,然后再使用它的接口回调的方式获取相同的数 ...
- React组件导入的两种方式(动态导入组件的实现)
一. react组件两种导入方式 React组件可以通过两种方式导入另一个组件 import(常用) import component from './component' require const ...
- React-Native子组件修改父组件的几种方式,兄弟组件状态修改(转载)
子组件修改父组件的状态,在开发中非常常见,下面列举了几种方式.DeviceEventEmitter可以跨组件,跨页面进行数据传递,还有一些状态的修改.http://www.jianshu.com/p/ ...
- 使用回调方式写POI导入excel工具类
场景是这样的:为了做一个excel导入的功能,为了尽可能的写一个通用的工具类,将与poi有关的东西都封装起来,以便以其他人员只用关心自己的业务,不用和poi打交道. 写到最后,现在还是会有poi的东西 ...
- C/C++回调方式系列之一 函数指针和函数回调模式
一.函数指针 1. 函数的定义 return_type function_name(parameter list) { function_body } return_type: 返回值,函数一定有返回 ...
随机推荐
- VUE AntDesign DatePicker设置默认显示当前日期
1:main.js中引入依赖 import Vue from "vue"; import { DatePicker } from 'ant-design-vue'; import ...
- 1 linux性能优化之平均负载uptime
不知道onenote的笔记复制出来就是图片了...
- Resouce Pool的理解
本篇文章从现象到本质再到具象去理解 , 从理论到实战再到源码回顾去深化. 1.在开发中,无处不在的池. eg 网络通信连接池: HttpClient连接池 HttpClient通过PoolingHtt ...
- 找出二进制数中bit为1的最(高/低)索引
题1. 给定一个无符号整型数据(unsigned int),找出其对应二进制数据中bit位为1的最高/低索引. 比如:对于数据0,返回0:数据1,返回1:数据0x80000000,返回32: 题2. ...
- 【JVM】3、jvm参数和main方法参数
在实际应用中,我们经常会使用一些额外的参数定义不通的环境下jvm的启动设置 特别是springCloud的项目,因为yml配置文件的问题,如果我们要做负载的话,会同时启动一个jar当做2个服务 那么这 ...
- Jenkins版本迭代以及回滚
一.摘要 在上一篇文章,链接如下: https://www.cnblogs.com/xiao987334176/p/11434849.html 镜像打的是latest版,如果需要回滚的话,就比较麻烦了 ...
- WPF 很少人知道的科技
原文:WPF 很少人知道的科技 本文介绍不那么常见的 WPF 相关的知识. 本文内容 在 C# 代码中创建 DataTemplate 多个数据源合并为一个列表显示 使用附加属性做缓存,避免内存泄漏 使 ...
- Spring-Cloud之Eureka注册与发现-2
一.Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的.SpringCloud将它集成在其 ...
- 2019 猎豹移动java面试笔试题 (含面试题解析)
本人3年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.猎豹移动等公司offer,岗位是Java后端开发,最终选择去了猎豹移动. 面试了很多家公司,感觉大部分公司考察的点 ...
- MySql表、字段、库的字符集修改及查看方法
这篇文章主要介绍了MySql表.字段.库的字符集修改及查看方法,本文分别给们它的修改及查看语句,需要的朋友可以参考下 修改数据库字符集: 代码如下: ALTER DATABASE db_name DE ...