服务器应用程序
容器应用程序
ActiveX控件可以看成是一个极小的服务器应用程序
OCX是ActiveX控件的一种后缀名
典型的ActiveX控件,具有方法、属性、事件这三种特性
一个文件可以包含多个ActiveX控件.
我们常用的word就是一个容器应用程序,例如,若在word文档中可以嵌入或链接一个Excel表格对象,则这时的Excel就是服务器应用程序。 在双击word文档中嵌入或链接的这个Excel表格对象后,将启动Excel程序来完成对这个表格的编辑工作。Excel就是拥有这个表格对象的服务器应用程序,而word程序则是可以容纳这个表格对象的容器应用程序。另外,我们也可以在word文档中嵌入或链接一个Excel文档对象,因此对word来说,它不仅仅只是一个容器应用程序,同时它也是一个服务器应用程序。
MFC ActiveX ControlWizard生成3个类
CClockApp
CClockCtrl 消息映射、调度映射、事件映射
CClockPropPage
调度映射是指DISPATCH_MAP
这个是把你的成员方法映射到Invoke,使得脚本语言也能够使用你的接口。
事件映射是指EVENT_MAP
这个是自动生成一个连接点事件的方法(该方法是给你调用,由COM客户来实现),并发布该事件,是COM客户可以使用连接点订阅你的事件以得到相关通知
两个映射都可以用类向导生成
另外,读者可以看到在该工程中还有两项内容:_DClock和_DClockEvents,前面都有一个像平放着小勺一样的图标(),该图标表示对应的项是接口,接口是控件与外部程序进行通信的协议。
可以把接口看作是函数的集合,外部程序通过这个接口所暴露出来的方法去访问控件的属性和方法。
实际上,可以把接口看作是一个抽象基类,在此接口中定义的所有函数都是纯虚函数,这些函数的实现是在CClockCtrl类中完成的。MFC通过底层的封装,让CClockCtrl类继承自接口:_DClock,所以通过该接口调用的函数实际上是调用CClockCtrl类中真正实现的函数。
ActiveX控件中的接口与计算机机硬件的接口是类似的,例如,在计算机硬件中,主板与显卡间的通信是通过主板上的插槽完成的,这个插槽就是主板与显卡进行通信的接口,一旦我们制定了这个接口,就可以任意地选择一块主板与一块显卡进行通信。因为该接口是标准的,所以选择任一厂商生产的主板,任一厂商生产的显示都是可以的,只要它们的接口遵从共同的标准。主板通过该接口所暴露出来的方法去调用显卡的显示功能,而显卡需要实现该接口所暴露出来的方法。
显卡就相当于这里的ActiveX控件,而主板就相当于与控件通信的外部容器。如果两个通信实体要通过接口进行通信,那么肯定是其中的一个实体实现该接口所暴露出来的方法,而另一个实体通过接口调用这些方法。这里,就是ActiveX控件实现接口所暴露出来的方法,而容器调用这些方法。
这里,我们利用Build(F7)命令生成Clock控件程序,然后在该工程所在目录的Debug目录下,可以看到生成了一个Clock.ocx文件,这就是程序生成的ActiveX控件文件。在使用时,只需要将这个文件传递给使用方,经过注册后就可以使用该控件了。
ActiveX控件不能独立运行,它必须嵌入到一个容器中运行。
所有的ActiveX控件必须在注册后才能使用
生成ActiveX控件时,VC++编译器会调用regsvr32程序去注册clock控件。将该控件的所有信息,包括其所在路径,都写入注册表中。
invalidate函数,使窗口无效,这样就可以使窗口重绘。
属性
属性是由ActiveX控件和控件所在的客户端展示提供的。共有四种基本属性:
1、Ambient属性是由容器向控件提供的。为了适应需要,控件必须使用这些属性。常用的ambient属性有容器的背景颜色、默认字体以及前景色等。
2、extended属性是由容器实现的,但看起来是由控件生成的。例如,容器中各种各样控件的制表顺序便属于extended属性。
3、stock属性是由ActiveX控件开发工具实现的控件属性。Stock属性的例子有控件的字体、标题文本和前景色及背景色等。
4、custom属性是由用户实现的控件属性。
事件
事件是用于向控件的容器发送通知信息的。例如当点击鼠标或发生其他事件时,控件用事件通知容器。共有两种基本类型的事件:
1、 stock事件是由ActiveX控件开发工具实现的,可以像调用fireError等函数那样调用stock事件。
2、 custom事件是由用户实现的,尽管在实现过程中MFC和ATL类库以及Visual C++做了大量的工作。
方法
由ActiveX控件实现的方法类似于自动化中所述的自动化实现的方法。实际上,方法主要是使用IDispatch接口通过自动化来实现的。
用MFC构件的ActiveX控件总是通过IDispatch来提供它的方法,而用ATL构建的控件为了提供组件的方法,既可以使用双工接口,也可以使用定制接口。
事件前面多了一个source,这表明事件是一个源接口,这表明控件将用这个源接口向容器来发送通知事件,这个接口中实现的代码需要用户在容器上编写,而不是在控件内部。
控件上子定义属性设置的长期有效性:
对于自定义属性值,如果在VB程序中设置好了值后,关闭工程,当再次打开工程的时候,发现原先设置好的属性值没有被保存下来。
在CCtrl类中的DoPropExchange方法中提供了属性值保存的长期有效性,在其中可以调用以PX打头大方法让用户自定义的属性值长期有效。调用哪种PX打头的方法取决于自定义属性所对应的内部成员变量的类型,这里以PX_SHORT举例,第一个参数是DoPropExchange方法中参数指针,第二个参数是属性的外部名称,第三个是属性所对应的内部成员变量名称。第四个是属性的默认填充值。
还有一个问题,对于自定义的属性,发现如果在属性页中对属性值进行了修改,但在容器的对应属性框中该值没有相应的改变,但系统属性是可以的。在属性通知方法OnIntervalChanged内调用BoundPropertyChanged方法即可,参数是属性ID,可以在类视图中双击属性名称即可看到(id(XXX),XXX即为属性ID)。
检测容器的环境属性:
检测控件是在容器的运行模式
还是在设计模式下可调用方法:AmbientUserMode。关于ActiveX的详细学习可以参考MSDN中COleControl页,点击页面下方的ActiveX链接。
VC调用ActiveX控件:
方法一:直接在对话框上右键选择Insert ActiveX Control
方法二:菜单project->add to project->component and controls,选择已经注册的ActiveX控件。向导会自动添加一个关于控件的类,在该类中有ActiveX控件定义好的属性和方法,它Create方法可以动态创建一个ActiveX控件,其操作过程很动态创建button很类似。至于给控件添加事件,可以在控件上右键选择Event即可。