使用回调接口实现ActiveX控件和它的容器程序的通讯

本文阅读基础:有一定的C++基础知识(了解继承、回调函数),对MFC的消息机制有一定了解,对COM的基础知识有一定了解,对ActiveX控件有一定了解。
一. 前言
    ActiveX控件和它的容器程序如何通讯是一个值得研究的问题,因为这涉及到ActiveX控件和它的容器程序如何交互的问题。VC知识库的杨老师写了一系列博客介绍了一些通讯方式。链接如下:
COM 组件设计与应用(十三)--事件和通知(VC6.0)
COM 组件设计与应用(十四)--事件和通知(vc)
COM 组件设计与应用(十五)--事件和通知(VC6.0) 达州普光气田
COM 组件设计与应用(十六)--事件和通知(vc)
这些文章写得真的很好,语言幽默风趣,深入浅出。我看后决心把它应用在ActiveX控件的回调实现上,经过实践,觉得有些地方语焉不详,自己做些摸索,写就此文,算是对杨老师文章的一点补充。
二.通知的方法
      ActiveX控件是一个窗口,它的容器程序自然也有一个父窗口;同时ActiveX控件是一个接口;ActiveX控件本质是一个COM组件,COM组件的客户端和服务器端本身有自己的通讯方式。从这两点我们可以想到二者之间的几种通讯方式:


我和我的同事曾争论ActiveX控件接口能否像一般C++的DLL那样在导出函数参数列表里设置一个回调函数指针那样实现回调,那时我认为是不行的。现 在我看了ActiveX控件接口的参数类型,更加坚定了我的看法。其实从COM的初衷来看应该也是不行的,因为COM的初衷之一是提供一种跨语言的调用接 口,而回调函数指针只对客户端是C++程序是有意义,对于VB、C#则无回调函数指针一说的。
三.实践检验
      现在我们编一个这样的小程序:在ActiveX控件上画直线,在画直线的同时把坐标传给客户端的视图,在客户端的视图区上依据传进来的坐标信息,绘制出相应的直线。
在动手之前我简要介绍我的思路:所谓基于COM的回调虚接口实现 ActiveX控件和客户端程序的通讯,大致是这样的,就是在ActiveX工程的内部的idl文件定义一个虚接口,在客户端程序定义一个虚接口的派生类 来实现回调函数,在客户端程序传递派生类对象指针给ActiveX控件,在控件内部调用这个虚接口的函数来激发客户端程序的派生类的对应的回调函数。这里 其实有一个关键问题,就是定义在idl文件中回调虚接口如何被ActiveX工程和
客户端程序识别,而不至于成为未定义类型(说实话,这个问题折磨了我两 个晚上,之所以这么麻烦,大概因为这个接口是定义在idl文件,而不是C++源文件中),下面我将介绍如何解决这个问题。
      首先我们创建一个MFC ActiveX Control的工程:DataX,具体如下图:
    接着在idl文件添加回调接口。这一步需要手动编辑idl文件。首先实现使用GUIDGEN.EXE(该工具在$\Microsoft Visual Studio 9.0\Common7\Tools路径下,在VC6.0,VC 8.0都有这个工具)产生一个IID,生成时注意选择是注册表形式,具体如下图:
epin11
      然后在idl文件的开头下加入以下内容:

国际篮球规则

view plaincopy to clipboardprint?
import "oaidl.idl"; 
import "ocidl.idl"; 
湖南确诊h5n6[ 
object, 
uuid(87C3DA69-C915-41f5-8142-D77816F22004), // 这个IID 可以用GUDIGEN.EXE 产生 
helpstring("ICallBack 接口"), 
pointer_default(unique) 

interface ICallBack : IUnknown { 
[id(1),helpstring("回调接口,响应鼠标按下")] HRESULT FireLButtonDown([in] LONG x,LONG y); 
[id(2),helpstring("回调接口,响应鼠标移动")] HRESULT FireMouseMove([in] LONG x,LON
G y); 
[id(3),helpstring("回调接口,响应鼠标按下")] HRESULT FireLButtonUp([in] LONG x,LONG y); 
}; 
import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(87C3DA69-C915-41f5-8142-D77816F22004), // 这个IID 可以用GUDIGEN.EXE 产生 helpstring("ICallBack 接口"), pointer_default(unique) ] interface ICallBack : IUnknown { [id(1),helpstring("回调接口,响应鼠标按下")] HRESULT FireLButtonDown([in] LONG x,LONG y); [id(2),helpstring("回调接口,响应鼠标移动")] HRESULT FireMouseMove([in] LONG x,LONG y); [id(3),helpstring("回调接口,响应鼠标按下")] HRESULT FireLButtonUp([in] LONG x,LONG y); };

由于画图不是本文描述的重点,这里暂且略过。下面我们开始在ActiveX控件上实现绘图和添加传递回调接口的函数。这里所说的传递回调接口实现的功能是把客户端程序的回调接口派生类对象的指针传到ActiveX控件内部。具体如下:
      这里介绍一下添加COM接口,首先在对应的接口选择:Add Method,如下图:
然后开始填充返回类型、参数等信息:
        我发现必须选择下拉列表的参数类型,不选择的话就会出错:
2018台湾选举结果
      这时我们需要要SetCallBackPtr函数中的IUnknown全部替换为ICallBack。为什么要进行替换?一方面ICallBack*类型 才是我们真正要传递的指针类型;另一方面如果不进行替换,外部的客户端程序将不能识别ICallBack这个类型。我发现在idl文件定义的类型,似乎要 在library ***
{
三聚氰胺}
      这一段出现过的类型外部才能识别,不过这个没有得到验证,有空得研究一个idl文件。这里大致要替换的地方包括三处,控件窗口类中的头文件的声明、cpp 文件中的定义以及在idl文件中的声明。这一步算是解决了回调接口ICallBack的外部识别问题。
现在我们在CDrawView定义一个
ICallBack* m_pCallBack;的数据成员,以及它的赋值接口函数:

view plaincopy to clipboardprint?
void CDrawView::SetCallBack(ICallBack*  pCallBack) 

if (NULL!=pCallBack) 

m_pCallBack = pCallBack; 


void CDrawView::SetCallBack(ICallBack* pCallBack) { if (NULL!=pCallBack) { m_pCallBack = pCallBack; } }

本文发布于:2024-09-22 22:26:22,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/231495.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:接口   回调   控件   类型   文件   客户端程序   实现   问题
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议