博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

ActiveX 控件与Internet(转)

Posted on 2006-09-26 15:28  无言  阅读(1090)  评论(1编辑  收藏  举报
 ActiveX控件是一个自包含代码的组件,它有自己的永久状态,并且ActiveX控件与包容器之间通过COM接口进行通信,所以通常ActiveX控件具有普遍的适应性,换句话说,如果ActiveX控件在一个包容器程序中可以运行,那么通常它也可以运行在另一个包容器程序中。由于ActiveX控件是一种可独立发布的组件程序,又是一个永久对象,这些特性使得它非常适合于Internet环境。
从包容器IE而言。IE需要考虑一些与Internet环境有关的问题,如许可证检查,自动下载、远程数据获取等。
另一方面从ActiveX控件本身来看,用于桌面环境的ActiveX控件,为了获得更强的交互性能,通常它要实现各种ActiveX控件所要求的接口,所以组件规模通常很大。为了使程序代码量尽可能地小,Microsoft Visual C++提供了ATL模板库作为这类ActiveX控件的基本开发工具。
IE要求ActiveX控件必须支持自注册,以便在用户浏览包含ActiveX控件的WEB页面时可以动态地注册控件。所以作为ActiveX控件的DLL程序必须引出DllRegisterServer和DllUnregisterServer函数。

接口
功能与说明
IOleObject
如果控件要与包容器程序的站点对象进行通信,则须实现此接口
IOleInPlaceObject
IOleInPlaceActiveObject
如果控件支持实地激活特性,则须实现此接口
IOleControl
如果控件支持快捷键,或者访问包容器的环境属性,或者控件要求包容器处理事件,则须实现此接口。
IDataObject
如果控件提供数据对象的特性,则实现此接口
IViewObject2
如果控件在非实地激活状态下也需要显示信息,则实现此接口
IDispatch
如果控件有自定义的属性和方法,则实现此接口
IConnectionPointContainer
如果控件对象支持一个或多个出接口,则实现此接口。
IProvideClassInfo[2]
如果控件对象要直接通过GetClassInfo成员函数提供对象类型信息,则实现此接口
ISpecifyPropertyPages
如果控件对象支持属性页,则实现此接口
IPersistStream[Init]
IPersisStorage
或其它永久接口
如果控件对象支持永久特性的,则至少实现一个永久接口

从理论上讲,IE只要求被嵌入的对象(ActiveX控件以对象的形式被嵌入在页面中)实现IUnKnown接口,但实际上为了实现一定的功能,并更好地与IE程序进行交互,ActiveX控件还必须实现其它一些接口。对应的接口与功能对应关系如下:
一般的包容器程序通常只负责ActiveX控件的创建、运行和释放,但IE要做的事情更多一些。首先,当客户机上不存在ActiveX控件组件程序时,它必须根据HTML页面中指示的地点把组件程序下载过来,并注册在客户机上,然后再创建对象,此过程在后台自动完成,不需要执行其它命令。其次,当IE把组件程序下载到本地之后,它在创建控件对象时可以进行许可证检查,以保证系统安全性,用户也可拒绝对象或执行初始化。
ActiveX控件包装
通过CLSID指定ActiveX控件的类型,如果要在IE中正确显示包含ActiveX控件的页面,则必须事先在机器上注册相应的ActiveX控件,否则相应的ActiveX就不能显示。在Internet上使用时,页面设计者不能期望浏览器用户找到你指定的ActiveX控件并注册到客户机上,为了解次这个问题,我们可以用“codebase”属性指定控件的代码位置:
<OBJECT CLASSID=”CLSID:2885EE05-A26B-11d1-B49B-00c04F98EFE0”
         Codebase=http://webserver/Pollgon.dll
     ALIGN=”CENTER” WIDTH=200 HEIGHT=200 ID=”PolyCtl”> </OBJECT>
以上指定了Polygong控件程序“http://webserver/Pollgon.dll”,当浏览器碰到这样的描述时,它会把codebase指定的程序下载到本地(在系统目录的“Downloaded Program Files”子目录下),然后调用组件程序的自注册入口函数注册到当前系统中,以后的创建都在本地进行,不再涉及codebase属性。
 
因为ActiveX控件的程序代码需要在Internet上传输,所以使用压缩技术传输程序代码非常有意义。另一方面,如果ActiveX控件还调用到其它的DLL程序模块,那么IE也必须把这些程序下载到本地来,为此,Microsoft采用了惯用的CAB压缩方法,它把ActiveX控件程序以及相关的其它文件放到同一个CAB文件中,然后在codebase属性中指定CAB文件的URL路径。
 
IECAB文件的处理过程如下:
1. IE在解析“OBJECT”标记时,它继续查找codebase属性。
2. 如果找到了codebase属性,并且codebase指定了ActiveX控件的CAB文件,那么IE定位到CAB文件。
3. IE把CAB文件中的有关文件解压出来,并放到客户机的临时目录(系统目录的“Downloaded Program Files”子目录下)中。
4. IE注册有关的文件。
5. IE调用COM API函数创建ActiveX控件对象。
CAB文件包含了ActiveX控件注册和运行时所需要的必要信息。通常一个CAB文件包含一个INF文件,INF文件是一个文本文件,它描述了CAB文件的所有细节信息。如以下的INF文件例子。
[version]
Signature=”$CHICAGE$”
AdvancedINF=2.0
[Add.Code]
MyCtrl.ocx = MyCtrl.ocx
Msvcrt.dll = msvcrt.dll
Mfc42.dll = mfc42.dll
Olepro32.dll = olepro32.dll
[MyCtrl.ocx]
File-win32-x86=thiscab
Clsid = {2885EE05-A26B-11d1-B49B-00c04F98EFE0}
FileVersion = 1,0,0,0
RegisterServer = yes
 
[msvcrt.dll]
FileVersion = 4,20,0,6164
Hook = mfc42installer
[mfc42.dll]
FileVersion=4,2,0,6256
Hook=mfc42installer
[olepro32.dll]
FileVersion = 4,2,0,6068
Hook = mfc42installer
[mfc42installer]
File-win32-x86=http://activex.microsoft.com/controls/vc/mfc42.cab
Run = %EXTRACT_DIR% \mfc42.exe
 
[Version]给出了INF文件的基本版本信息,“signature=”一行说明此INF文件可适用于32位
Windows操作系统; “AdvancedINF=”一行要求IE必须装入2.0版以上的Advpack.dll模块才能解析此INF文件。
[Add.Code]是INF文件的主体部分,它列出了所有ActiveX控件需要的文件以及每个文件所对应的部分名称。MyCtrl控件是MFC开发的,所以它需要用到MFC的动态连接库文件,所以,这一部分中列出了MyCtrl控件所必须的四个文件:MyCtrl.ocx、msvcrt.dll、mfc42.dll和olepro32.dll。
[MyCtrl.ocx]部分描述了MyCtrl控件组件程序MyCtrl.ocx的信息,包括此程序所在的CAB文件位置(thiscab指自身)以及MyCtrl控件的CLSID信息。”FileVersion=”指明了MyCtrl.ocx的版本;”RegisterServer=yes”说明此文件在使用之前要预先被注册。
[msvcrt.dll] [mfc42.dll] [olepro32.dll]部分分别说明了相应的文件版本,并把进一步信息指向最后的[mfc42installer]部分。
[mfc42installer]部分中,“file-win32-x86=”指明了MFC42.CAB文件的URL路径,”run=”指明了运行的命令
 
可用Cabarc.exe工具生成CAB文件,如:
Cabarc.exe N MyCtrl.cab MyCtrl.ocx MyCtrl.inf
 
ATL产生的Activex控件所对应的INF文件如下:(可作为ATL开发的样板)
[version]
    Signature=”$CHICAGE$”
    AdvancedINF = 2.0
[Add.Code]
    Polygon.dll = polygon.dll
    Atl.dll = atl.dll
[atl.dll]
    File-win32-x86=thiscab
    FileVersion = 3,00,0,8166
    DestDir = 11
    RegisterServer=yes
 
[Polygon.dll]
    File-win32-x86=thiscab
    Clsid = {2885EE05-A26B-11d1-B49B-00c04F98EFE0}
    FileVersion=1,0,0,1
    RegisterServer=yes
 
这里新出现的标记为“DestDir=”,它是指文件下载过来之后存放的目标目录,“11”表示
Windows的系统目录(“Windows\System” 或 “WInnt\System32”);“10”指windows目录
(windows或winnt)。根据INF文件生成的CAB文件命令为:
Cabarc.exe N Polygon.cab  atl.dll Polygon.dll Polygon.inf
 
CAB文件也支持数字签名,我们在利用cabarc.exe工具生成CAB文件时可以用 –s命令行
参数预留数签名空间,然后运行实用工具SIGNCODE,加入数字签名即可。
 
许可证管理
    除了免费发行的ActiveX之外,大多数ActiveX控件都支持设计时刻运行时刻的许可
证检查。设计时刻许可证检查可以保证程序员在创建就用系统或者WEB页面时使用合法的
ActiveX控件;运行时刻许可证检查可以保证用户运行一个包含合法的控件的就用系统或者
显示一个包含合法控件的Web页面。
    由于许可证检查是在ActiveX控件被创建时进行的,所以不管是设计时刻许可检查还是
运行时刻许可检查,实现的关键在于ActiveX控件的类厂对象。如果ActiveX控件支持许可
检查,那么其类厂对象必须支持IClassFactory2接口。此接口是IClassFactory的扩展。
    许可证是一段文本信息,它可以存放在单独的文件中,也可以存放在组件程序二进制代
码中或者就用程序中。但作为ActiveX控件组件程序,它只需实现IClassFactory2接口的三
个成员函数,对于许可证的管理和用法取决于包容器程序。不同类型的包容器程序对许可证
的处理有所不同,并且设计时刻与运行时刻对许可证的处理也有所不同。
在创建包含ActiveX控件的应用程序时,包容器(VB或其它开发工具)调用
IClassFactory2::GetLicInfoRequestLicKey函数获取许可证,然后嵌入到应用程序的二进制
代码中。在运行应用程序时刻,作为包容器程序的应用程序在创建ActiveX控件时,调用
IClassFactory2::CreateInstanceLic函数创建控件对象,与设计时刻不同的是,它在bstrKey
参数中传递有效的许可证字符串(内嵌在程序中)而不是NULL。所以这样的程序可以
在任何一机器上运行,而不用担心许可问题
    对于IE这样的包容器程序,它也调用IClassFactory2的成员函数进行许可检查,但由于
ActiveX控件被包含在Web页面上,任何浏览器都可以访问到Web页面,并且IE在创建控
件之前已经把程序代码下载到本地,所以IE需要其它的方式把许可证隐藏起来,以避免许
可证被非法滥用。Microsoft为此引进了许可证包文件(license package file,文件名后缀为
LPK)
    许可证文件格式共分四部分:
1. LPK文件头。包含信息“LPK License Package”。
2. 版权信息。对版权的解释以及对非法拷贝的警告。
3. LPK文件的版本和GUID。文本信息,也标识了真正许可证数据的开始。
4. UUENCODED(Base64)码对许可证进行编码。包含多个对象(CLSID)与相应的许可证(UNICODE字符串)
IE包含一个许可证管理器组件,它负责解析LPK文件,并提取出每个CLSID的许可证。当
IE要显示ActiveX控件时,它通过许可证管理器组件从LPK文件提取出许可证,然后调用IClassFactory2::CreateInstanceLic函数创建ActiveX控件对象,如果它指定的许可与ActiveX控件内部的许可证相匹配,那么ActiveX控件就会被创建并在页面上显示。
创建许可证包文件可以使用Microsoft提供的实用工具LPK_TOOL.EXE。为所指定的ActiveX控件生成相应的LPK文件。一旦生成了LPK文件,并可在WEB页中使用,如:
<OBJECT CLASSID=”clsid: 2885EE05-A26B-11d1-B49B-00c04F98EFE0”>
<PARAM NAME=”LPKPATH” VALUE=”MyPage.lpk”>
</OBJECT>
LPK文件针对整个WEB页面,而不是单个ActiveX控件,所以每个WEB页面只能使用一个LPK文件。
 
WEB页面中ActiveX控件的初始化
在“OBJECT”标记的“DATA”属性中指定包含属性数据文件的URL文件名。如果DATA属性包含URL文件名,那么包容器就创建一个URL名字对象,并且调用ActiveX控件IPersistMoniker接口的Load成员函数执行初始化。ActiveX控件调用名字对象的IMoniker::BindToStorage函数以便获取属性数据并进行初始化。
如果ActiveX不支持IPersistMoniker接口,则IE会请求其它的永久接口,然后获取属性数据,必要时打包到流对象中,再调用永久接口的LOAD成员函数。于是ActiveX控件就可通过流对象得到属性数据。
以下HTML说明在Web页面中为ActiveX控件指定属性数据的方法
<OBJECT CLASSID=” 2885EE05-A26B-11d1-B49B-00c04F98EFE0”
         CODEBASE=”http://webServer/MyCtrl.cab
         Data=”http://webServer/Mydata.dat
         ID=”MyCtrl”></OBJECT>
有时候ActiveX控件的属性数据量很小,可以只用一些数值或字符串就把属性表达出来。这种情况下,使用流方式的属性表达式就没有必要,可以在HTML中使用“
PARAM”关键字对ActiveX控件的属性进行赋值。如:
<OBJECT CLASSID=” 2885EE05-A26B-11d1-B49B-00c04F98EFE0”
         CODEBASE=”http://webServer/MyCtrl.dll”>
         <PARAM NAME = “Sides” VALUE = 5>
</OBJECT>