1、ActiveX控件概述
ActiveX控件是基于组件对象模型 (COM) 的可重用软件组件,广泛应用于桌面及Web应用中。在Windows操作系统以OCX结尾的文件,OCX代表“对象链接与嵌入控件”(OLE),这个技术是Microsoft提出的程序技术,用于处理桌面文件的混合使用。在VC下ActiveX控件的开发可以分为三种:
一种是直接用COM的API来开发,这样做显然非常的麻烦,对程序员要求也非常高,因此一般是不予考虑的;
一种是基于传统的MFC,采用面向对象的方式将COM的基本功能封装在若干MFC的C++类中,开发者通过继承这些类得到COM支持功能。MFC为广大VC程序员所熟悉,易于上手学习,但缺点是MFC封装的东西比较多,因此用MFC开发出来的控件相对会比较大,因此比较适于开发桌面ActiveX控件,尤其是有GUI界面的控件;
第三种就是基于ATL的,ATL可以说是专门面向COM开发的一套框架,使用了C++的模板技术,在运行时不需要依赖于类似MFC程序所需要的庞大的代码模块,更适合于Web应用开发。
本文介绍的是采用第二种方式,即应用MFC进行桌面可视控件开发的方法步骤,开发环境则是基于VC2008。
2、创建基于MFC的ActiveX控件的工程
2.1 ActiveX控件工程的创建
打开VC2008后,我们要先创建一个名称为StudyActiveX的解决方案,在该解决方案中按图1新建一个名为ActiveXDemo项目,这里在新建项目页的左侧选择Visual C++ 下的MFC,在右侧选择MFC ActiveX控件,填上项目名称“ActiveXDemo”。
图1
接下来进入控件向导页,在向导的第二页(如图2中)有个运行时许可证,选中这个的话会在生成控件的同时生成一个许可证文件ActiveXDemo.lic,其他用户在使用这个控件的时候必须同时附有这个许可证文件,当该控件在注册时必须含有该许可证文件才能够正确的被注册上,在此我们保持默认状态,不选。
图2
下一页是关于项目中各部分的命名问题,可以根据需要自定义,这里就按默认的情况不做修改了。
图3
下一页是选择控件基于哪种控件的扩展以及控件的一些基本特性。如果新建的控件是基于某种特定控件的话,就在创建的控件基于下选择所要继承的控件名,否则就保持none。下方的附加功能根据实际需要进行选择,并且可以将鼠标放置于选项上方,功能的说明会自动显示在动态出现的小提示信息窗口中。选择完毕点击完成,向导就根据你的选择生成新项目,这里我们选择了none。
图4
点击“完成”按钮后进入开发环境,我们可以先看一下类视图,如图5所示:
图5
(1)其中的ActiveXDemoApp.cpp是我们这个控件的主程序模块,定义了控件的注册 (DllRegisterServer)、卸载(DllUnregisterServer)等功能,一般不用动,如有需要我们可以在其中的CActiveXDemoApp::InitInstance()和CActiveXDemoApp::ExitInstance() 中定义我们自己的初始化和终止操作代码,一般也就是一些资源的初始化和销毁工作。
(2)CActiveXDemoCtrl是控件类,我们要做的控件功能基本上就是要在这个类中实现。需要提一下的是在这个类中重写了父类的OnDraw函数,
图6
有如下两句代码:
pdc->FillRect(rcBounds,CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
pdc->Ellipse(rcBounds);
也就是在控件上画了一个椭圆,实际控件开发中可以根据功能需要修改重写这个函数来绘制控件界面。
(3)CActiveXDemoPropPage是属性页类,这个类实现了一个在开发时设定控件属性的对话框。
(4)ActiveXDemoLib是为客户程序提供本控件的属性、方法以及可能响应的事件的接口的库节点,在添加控件的这些功能的时候会用得到。
接下来编译生成ActiveXDemo工程,则会在工程目录下的Debug目录下生成ActiveXDemo.ocx。在编译的工程快要完成的时候,细心的话你会注意到如下注册信息:
VC会调用系统的regsvr32.exe程序来注册我们刚才生成的ActiveXDemo.ocx控件。
2.2 在MFC的对话框中使用控件
在解决方案StudyActiveX中添加一个新“MFC应用程序”工程,名称为TestActiveX,如图7所示:
图7
在接下来的向导中,选择“基于对话框”的应用程序类型,如图8所示:
图8
将窗口切换到TestActiveX工程的窗口资源中,如图9所示:
图9
接下来我们会将刚才创建的ActiveXDemo.ocx控件添加到我们的测试窗口中,添加的方法有两种:
一种是在窗口资源中直接鼠标右键选择“插入ActiveX控件(X)”,如图10所示,在接下来选择刚才编写和注册的ActiveXDemo Control,然后确定即可。
图10
另一种方法是现将控件添加到工具箱中,然后再从工具箱中将控件拖到窗口中,添加到工具箱的方法是在工具箱窗口的任意一个控件上鼠标右击选择“选择项(I)…”,在弹出的“选择工具箱项”中选择“COM组件”属性页中,选择我们先前创建的“ActiveXDemo Control”控件后确定。
图11
这样在我们的工具箱的最下面就会有一个我们刚刚添加进来的示例控件了,如图12所示。这样我们就可以像使用按钮控件一样来使用这个控件了。
图12
接下来我们编译测试工程TestActiveX工程吧,运行后的结果如图13所示:
图13
2.2 在HTML网页中使用控件
在实际应用中我们需要在传统的HTML网页中插入ActiveX控件,由ActiveX控件来满足需求功能。每一个ActiveX Control都会有一个对应的CLSID,该ID是唯一的。例如我们刚才的ActiveXDemo控件的CLSID值为图16所示位置的值:
图14
通过OBJECT的CLASSID属性指定ActiveX Control的ID,然后IE就可以根据CLSID找到相应的ActiveXControl。为了能够找到ActiveX Control,每一个ActiveX Control都必须先注册,再使用。ActiveX Contorl的注册和卸载可以通过实用工具regsvr32来完成,其注册和卸载命令如下:
下面我们新建一个index.html文件,在文件中写入如下调用ActiveXDemo控件的代码:
<HTML> <HEAD> <TITLE>Test ActiveX Page</TITLE> </HEAD> <BODY>
<OBJECT WIDTH=50 HEIGHT=50 CLASSID="CLSID:85C74353-9593-471D-B8AB-8AFAF951548B"> </OBJECT>
</BODY> </HTML> |
然后用IE浏览器打开index.html网页后的效果如图15(a)所示,此时ActiveX控件要被阻止执行,我们鼠标右键允许后,效果如图15(b)所示。
图15(b)
图15(b)
3、ActiveX控件的打包步骤
OCX:OCX称为对象类别扩充组件(Object Linking and Embedding (OLE) Control Extension);
CAB:压缩包文件。存储多个压缩文件的单个压缩包文件。这些文件通常用于软件安装,还用来减小文件大小和缩短 Web 内容的相关下载时间。
制作CAB文件时需要将所有的相关文件都包含进去,一般需要将OCX做CAB打包即为ocx的开发者本人明确知道所依赖的动态链接库,如果不了解OCX依赖于那些动态链接库,可以通过Depends(VC自带的)检查需要的文件,然后使用inf文件将这些东西都写进去。
3.1 制作inf文件
在此处不对INF文件本身的格式做额外说明,如有兴趣可自行上网搜索。
此OCX控件CAB打包的INF文件如下书写,首先此控件不仅仅只有一个ocx文件,还具备其它的动态链接库,同时还有ini配置文件:
[version] signature="$CHICAGO$" AdvancedINF=2.0 [Add.Code] CCEA.ocx=CCEA.ocx DesktopAgent.dll=DesktopAgent.dll ProxySock.dll=ProxySock.dll Web2Agent.dll=Web2Agent.dll Config.ini=Config.ini [CCEA.ocx] file-win32-x86=thiscab clsid={6F82C754-6C31-43EA-9818-E95AD4E872FC} FileVersion=1,6,0,44 RegisterServer=yes DestDir=10 [DesktopAgent.dll] file-win32-x86=thiscab FileVersion=1,6,2,27 DestDir=10 [ProxySock.dll] file-win32-x86=thiscab FileVersion=1,6,0,1 DestDir=10 [Web2Agent.dll] file-win32-x86=thiscab FileVersion=1,0,0,0 DestDir=10 [Config.ini] file-win32-x86=thiscab FileVersion=1,0,0,2 DestDir=10 |
下面对以上INF文件的内容做详细说明:
[Version]区的内容可以不考虑,接下来就是最重要的[Add.Code]区,格式为XXXX=XXXX;前面是要下载的文件名,后面是对应这个文件的区域名,可以是任何名字,不过一般都是和文件的名字相同,这样方便维护。
再接下来是各个文件的区域,[XXX]其中XXX为[Add.Code]区中的文件名,其中[CCEA.ocx]文件区域的参数比其它文件多,这是因为其为此CAB的核心,其它文件均依赖于它且它需要自动注册,首先来讲解[CCEA.ocx]部分:
(1)file-win32-x86=thiscab
这个值告诉ie到哪里去得到这个ocx, file一共包括三个部分,第一部分是file,这个永远都是这样的;第二部分告诉声明支持的OS,win32表示windows,mac就是苹果MAC OX了;第三部分是CPU类型,比如说x86、mips等。
file的值可以取三个:一个URL、ignore和thiscab,如果是URL则说明到URL所在的位置去下;如果是ignore说明对于这种OS和CPU,不需要下载这个文件;如果是thiscab就在当前的cab文件中了;
(2)clsid={6F82C754-6C31-43EA-9818-E95AD4E872FC}
此处需要填写该ocx的class guid;
(3)RegisterServer=yes
此处可以取两个值yes和no,如果为yes则说明ie要注册该ocx,如果是no就不必注册;
(4)DestDir=10
此处的值是ocx将要存到本地硬盘的位置,
如果它的值是10,则将ocx放到\Windows或者\WinNT下;
如果是11,则放到\Windows\System或者\WinNT\System32下;
如果是空(就是没有值)则会放到\Windows或者\WinNT下的Downloaded Program Files目录下;
此处选为10是放在\Windows是考虑\Windows下文件量小易于操作便于卸载;
(5)FileVersion=1,6,0,44
此处说明了ocx的版本号,目前ocx版本号为1.6.0.44,此处也是CAB自动升级的判断依据,其它文件区域内容标识与[CCEA.ocx]部分,此处不再赘叙。
3.2 制作CAB文件
在此之前你需要实现ActiveX控件安全的初始化和脚本,相关信息可以查阅ActiveX控件实现安全的初始化和脚本利用iexpress.exe(windows提供的一个向导式cab制作工具)进行打包,进入CMD键入iexpress回车即显示如下界面:
选“Create new Self Extraction Directive file”,点“下一步”,出现如下框:
选择“Create compressed files only(ActiveX Installs)”,点击下一步,出现如下框图,点击Add,添加INF中标注的所有文件:
点击下一步,点击Browse,选择CCEA.CAB文件的存放地址并命名CAB文件名,此文件名在IE加载时html标签时使用,并且要选中“Store files using Long File Name inside Package“:
点击下一步:
此处选择“Don’t save”,一直点击下一步,直到完成,最后在前面选择的位置会出现以前面所取名字一致的CAB文件:
至此CAB的打包工作已经完成。
4 CAB增加数字签名
此处不做说明,可以申请测试证书供测试,也可以自己写证书,只不过根证书需要重新安装,如果是商业化应用的话还是购买微软认证机构的代码签名,这样不需要额外的操作即可正常使用增加签名的CAB文件,只在第一次使用时安装部署后续的再次使用没有任何提示报警即可加载,一般购买机构会提供签名的工具,可能是批处理工具也可能给相应文档,最终使用的还是signtool.exe签名工具。
5CAB升级方式
5.1 OCX及依赖DLL升级
如果CAB文件中ocx机器附属dll文件需要更新,那么只可能是版本更新,要么是ocx版本升级要么是dll文件版本升级,无论哪一种形式ocx的版本号均需要通过正常的发布流程发布,所以这两种形式可视为一致。
此时需要升级CAB打包过程中INF文件中相应的文件区域中的版本号与有更新的文件的文件版本号保持一致,比如此时ocx和DeskAgent.dll有更新,此时新发布的版本中版本号分别分别更新为1.6.0.45和1.6.2.28,INF文件中相应区域应修改为:
[CCEA.ocx] file-win32-x86=thiscab clsid={6F82C754-6C31-43EA-9818-E95AD4E872FC} FileVersion=1,6,0,45 RegisterServer=yes DestDir=10 [DesktopAgent.dll] file-win32-x86=thiscab FileVersion=1,6,2,28 DestDir=10 |
重新打包签名替换原本用来分发的旧CAB包,同时在html标签中CAB的版本号要升级为与CAB文件中OCX文件的版本号一致。
以上是一种标准的升级方式有助于在每次升级过程中明确相应的版本关系而不至于在多次升级之后版本号的混乱,同时能够保证签名之后的CAB文件在安装之后即可正常使用不再有下载安装的步骤,但实际上只要升级了OCX的版本号并且将html里的版本号一并升级之后无论其它依赖的文件是否更新、版本号是否升级,所有文件均重新下载安装注册替换为新CAB文件中的文件,这点是需要强调注意的(至于html标签怎么写后面会有说明)。
5.2 只更新INI配置文件
目前没有找到有效的方法在不更新OCX文件及其附属dll的前提下自动更新,目前的建议的方法是将更换了新的ini配置文件后重新打包CAB并签名,不更改INF文件的前提条件下更新html中标签的版本,更新完之后所有坐席均保证做一次业务系统登录以更新CAB文件,之后再将html标签中的版本改回原先的版本号,此举是保证坐席之后每次登录均不再需要重新下载安装即可直接使用,保证良好的适用性。
5.3 CAB加载的HTML实现
原先第三方业务系统使用OCX控件需要在业务系统的html实现如下代码:
<OBJECT id="UsbossViewer" name="objocx" classid="clsid:6F82C754-6C31-43EA-9818-E95AD4E872FC" width="100%" height="250">
</OBJECT>
若要在OCX文件直接加载时初始化属性,需要在OBJECT标签之内初始化属性,具体结构变为如下结构:
<OBJECT id="UsbossViewer" name="objocx" classid="clsid:6F82C754-6C31-43EA-9818-E95AD4E872FC" width="100%" height="250">
<PARAM NAME="XXXX" VALUE="XXXX"/></OBJECT>
下面讲述第三方业务系统在html标签中如何使用CAB文件,html标签实例如下:
<OBJECT ID= "UsbossViewer " name="objocx" CLASSID= "CLSID:6F82C754-6C31-43EA-9818-E95AD4E872FC" CODEBASE= "CCEAOCX.CAB#version=1,6,0,44" width="100%" height="250"> </OBJECT>
此处"objocx"可任意命名,在之后使用控件的接口或者属性则以objocx. 方法名或者objocx. 属性即可,“CODEBASE=”是一个比较重要的key,其中CCEAOCX.CAB是CAB文件打包时的命名,而之后1,6,0,44则是此CAB的版本号,但是CAB本身是没有版本号的,因此一般来说将此版本号设置得与CAB文件中ocx的版本号一致,这也是建议的一种方式,在更新CAB文件中有相当大的作用。
若要像OCX文件直接加载时初始化属性,其方式是一样的,同样在OBJECT标签之内初始化属性:
<OBJECT ID= "UsbossViewer " name="objocx" CLASSID= "CLSID:6F82C754-6C31-43EA-9818-E95AD4E872FC" CODEBASE= "CCEAOCX.CAB#version=1,6,0,44" width="100%" height="250"><PARAM NAME="XXXX" VALUE="XXXX"/> </OBJECT>
5.4 使用URL的CAB部署方式
CAB文件的使用描述的CAB部署方式是必须在加载页面的的本级目录下部署CAB文件,若要指定路径的话其格式应该是:
<OBJECT ID= "UsbossViewer " name="objocx" CLASSID= "CLSID:6F82C754-6C31-43EA-9818-E95AD4E872FC" CODEBASE= "http://10.130.40.220:9081/CAB/OCXold.CAB#version=1,6,0,44" width="100%" height="250"> </OBJECT>
其中http://10.130.40.220:9081/CAB/OCXold.CAB即为CAB放置的绝对路径,http://10.130.40.220:9081/CAB/为测试环境的路径。
6 MFC Activex 安全问题