回调方式进行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: 返回值,函数一定有返回 ...
随机推荐
- WebGL学习笔记二——绘制基本图元
webGL的基本图元点.线.三角形 gl.drawArrays(mode, first,count) first,代表从第几个点开始绘制即顶点的起始位置 count,代表绘制的点的数量. mode,代 ...
- 小甲鱼汇编语言学习笔记——day03
手动编译并执行第一个汇编程序过程: 1.用notepad++写一个简单的汇编程序(文件命名为:1.asm): assume cs:abc abc segment mov ax, 2 add ax, a ...
- activiti学习5:开启流程和流程前进
目录 activiti学习5:开启流程和流程前进 一.流程和任务的关系 二.开启流程 2.1根据流程定义key开启流程 三.查询用户任务 3.1 TaskQuery 四.完成任务 activiti学习 ...
- 【LOJ502】[LibreOJ β Round] ZQC 的截图 (随机化)
真的是神仙题目啊-- 题目 LOJ502 官方题解 我认为官方题解比我讲得好. 分析 这是一道蒙特卡洛算法的好题 上面那个奇奇怪怪的词是从官方题解里看到的,意思大概就是随机化算法 -- ? 一句话题意 ...
- git第一次上传push失败解决
第一次上传有可能会遇到push失败的情况,那是因为跟SVN一样,github上有一个README.md 文件没有下载下来 .我们得先 git pull --rebase origin master ...
- ZYNQ笔记(3):GPIO的使用(MIO、EMIO)——led灯
一.GPIO原理 1.GPIO介绍 程序员通过软件代码可以独立和动态地对每个 GPIO 进行控制,使其作为输入.输出或中断. (1)通过一个加载指令,软件可以读取一个 GPIO 组内所有 GPIO 的 ...
- 【读书笔记】胡说IC
- vue-cli输入命令vue ui没效果
最近用vue-cli脚手架很顺口,特别是UI控制台,在这里,创建项目和搭建本地环境,连接服务端变得很容易,页面ui也是一流 要怎么启动呢?在终端输入命令行vue ui,启动UI控制台,然后往浏览器输入 ...
- 对于Node中Express框架的中间件概念的感知
中间件是什么呢? 中间件就是客户端http请求发起传送到服务器和服务器返回响应之间的一些处理函数. 为什么要使用中间件? 通过中间件,可以对数据进行操作使得我们能方便地操作请求数据编写服务器响应.如b ...
- Spring中的ApplicationListener的使用详解案例
本文链接:https://blog.csdn.net/u010963948/article/details/83507185 1.ApplicationContext Spring的核心,Contex ...