睿丰德科技 专注RFID识别技术和条码识别技术与管理软件的集成项目。质量追溯系统、MES系统、金蝶与条码系统对接、用友与条码系统对接
本文阅读基础:有一定的C++基础知识(了解继承、回调函数),对MFC的消息机制有一定了解,对COM的基础知识有一定了解,对ActiveX控件有一定了解。
一. 前言
ActiveX控件和它的容器程序如何通讯是一个值得研究的问题,因为这涉及到ActiveX控件和它的容器程序如何交互的问题。VC知识库的杨老师写了一系列博客介绍了一些通讯方式。链接如下:
COM 组件设计与应用(十三)--事件和通知(VC6.0)
COM 组件设计与应用(十四)--事件和通知(vc.net)
COM 组件设计与应用(十五)--事件和通知(VC6.0)
COM 组件设计与应用(十六)--事件和通知(vc.net)
这些文章写得真的很好,语言幽默风趣,深入浅出。我看后决心把它应用在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,生成时注意选择是注册表形式,具体如下图:

然后在idl文件的开头下加入以下内容:
[cpp] view plaincopy