vc6开发activex并发布全攻略(二)(初级篇)
http://flashaway.blog.163.com/blog/static/95624576200942202812353/
上一篇中我们做好了一个activeX。现在我们就来发布。
下面转载一篇发布activeX的博文,在后面我会对出现的问题做补充,原文地址
http://blog.csdn.net/zougangx/archive/2008/07/30/2738147.aspx
[背景] 做过ActiveX控件的朋友都知道,要想把自己做的ActiveX控件功能放在自己的网页上使用,那么用户在客户端就必须进行本地的注册,也就是说用户 得首先要把该ActiveX控件(test.ocx)放在本机的%system%/system32下,然后运行DOS工具里面运行regsvr32 test.ocx命令进行注册。但如果真是这么去做的话,那么代表着你处于危险之中了,因为您是通过让用户自己去部署设置环境来达到你的目的,这就失去软 件项目本身所存在的价值。那么面对这种情况,我们应该如何解决呢?聪明的你一定会很快就想到,我们可以使用户在客户端自动下载安装该ActiveX控件, 这样一来即可以实现我们所想要的功能,又不需要用户自己去部署设置环境,这岂不是一举两得。 [必备条件] 一、用于将ActiveX控件进行打包并加数据鉴名的工具集: makecert.exe 制作cer格式的证书,即X.509证书,同时可以创建私钥和公钥。 cert2spc.exe 将cer格式证书转换成spc格式证书,即PKCS #7证书。 cabarc.exe 将ocx打包成cab。 signcode.exe 将证书签署到ocx上去。 chktrust.exe 检查签署证书后的ocx是否正确。 certmgr.exe 是管理证书用的。
二、用于进行打包用的ocx控件evS1300.ocx。 三、用于查看ocx控件的工具ActvxDoc。 [制作过程] 一、环境设置 1、下载makeCAB包,解压到本地目录(如E盘根目录),如查看到如图1所示的工具集,则表示已下载成功: (图1:makeCAB包的工具集) 2、设置系统环境变量,右键单击“我的电脑”à选择“属性”à选择“高级”选项卡,打开如图2所示的系统属性面版块: (图2:系统属性版块) 3、在系统属性版块里单击“环境变量(N)”按钮,打开图3: (图3:系统变量) 4、选择“系统变量(S)”里的“新建(W)”按钮,打开“编辑系统变量”对话框,如图4所示,然后在“变量值(V)”里加入“;E\makeCAB”: (图4:编辑系统变量)
二、 将用于打包的OCX控件放在E盘根目录下(本文档使用名为evS1300.ocx的控件来进行介绍),如图5所示,其中evS1300.ocx是本文档进 行操作的控件对象,而mfc71.dll、msvcp71.dll、msvcr71.dll这三个文件通常是进行打包时一并打包的文件,但不是必须(推荐 一起打包),其可在系统中的system32目录下找到,请自行准备。 (图5;用于操作的OCX控件路径)
三、ActiveX发布步骤 1、单击“开始”à“动行(R)”à输入“cmd”à回车à进入到操作的控件所在的目录,如图6所示: (图6:进入E:\evS1300目录) 2、创建PVK文件(私人密匙文件),在命令行中输入“makecert -sk evS1300 evS1300.pvk -n CN=XXXXXXX公司”,然后回车,如图7所示: (图7:创建PVK文件) 3、创建CER文件(公司证书),在命令行中输入“makecert -sk evS1300.pvk evS1300.cer”,然后回车,如图8所示,若出现“Successed”提示,则会在E:\evS1300目录下生成evS1300.cer文 件,如图9所示: (图8:创建CER文件)
(图9:生成evS1300.cer) 4、创建SPC测试软件出版商证明书,在命令行中输入“cert2spc evS1300.cer evS1300.spc”,然后回车,如图10所示: (图10:创建SPC测试软件出版商证明书) 5、创建INF文件,用记录本编辑以下信息
如图11所示,并保存为E:\evS1300\evS1300.inf,如图12所示
(图11:evS1300.inf)
(图12:保存evS1300.inf) 在evS1300.inf的内容里,[version]和[Add.Code]项是必须的,[Add.Code]的键值项的多少取决于以下你所配制项的多 少。[msvcr71.dll]、[mfc71.dll]、[msvcp71.dll]就是上面我所说不是必须的项,只要你想把msvcr71.dll、 mfc71.dll、msvcp71.dll包括在发布包里,那这么三项就必须写在inf里,而这三项的具体内容是固定的,可复制过去即可。最为关键的就 是[evS1300.ocx]项,其中有clsid和FileVersion就是evS1300.ocx的classId和version,这要求必须一 至,否我们发布出去的CAB包时不能在客户端自动更新下载安装。说到这里,那我们如何才能知道evS1300.ocx里面的classId和 version呢?我在上面的必备条件里介绍到有一个用于查看ocx控件的工具ActvxDoc,对,就是用它,我们双击这个文件运行它,此时可以看到图 13所示的界面: (图13:ActiveX Documenter) 在图13的界面里,点击“File”à“Open…”,打开您所要查看的OCX控件,如图14所示: (图14:打开控件) 打开了控件之后,我们在界面的右边部位“Class”的下拉框里选择“”就可以看到我们想要查找的FileVersion和classId,如图15所示: (图15:控件属性)
6、创建CAB文件,在命令行中输入“cabarc -s 6144 n evS1300.cab msvcr71.dll mfc71.dll msvcp71.dll evS1300.ocx evS1300.inf”,然后回车,如图16所示:
(图16:创建CAB文件)
7、使用Code Signing Wizard签署一个CAB文件,首先双击运行工具集里面的signcode.exe(或在命令行里直接输入“signcode”后回车),系统会弹出如图17所示的数字签名向导: (图17:数字签名向导)
8、单击“下一步(N)”按钮,来到图18所示,选择要进行数字签名的且已做成CAB包的文件evS1300.cab文件。 (图18:选择CAB包) 9、选择好CAB包后单击“下一步(N)”按钮,在选择想要的签名类型里选择“自定议(C)”并单击“下一步(N)”按钮,如图19所示:
10、接下来单击“从文件选择(F)”按钮,选择刚刚制作的evS1300.cer,如图20所示:
(图20:选择CER证书) 11、在图20中单击“下一步(N)”按钮来到图21,然后在图21里选择“CSP中的私钥(K)”。 (图21:选择私钥的位置) 12、在图21中单击“下一步(N)”按钮,然后在图22中的散列算法中选择“shal”,并单击“下一步(N)”按钮。 (图22:选择散列算法) 13、在“证书路径中的证书”中选择“证书路径中的所有证书,包括根证书(C)”,在“其它证书(可选)”中选择“包括在以下PKCS #7 证书(.p7b)文件中的证书(P):”,并单击“浏览(R)…”按钮选择evS1300.spc文件,选择完后单击“下一步(N)”按钮,如图23所 示: (图23:选择其它证书) 14、接下来在弹出的“数据描述”窗口中输入公司的名称和网址并单击“下一步(N)”按钮,如图24所示: (图24:输入数据描述) 15、现大部份工作都已完成,在接下来的一步当中是可选的操作,其作用只是为CAB加入时间戳,此步骤完全可以不做,如图25所示: (这里我提拱三个免费的代码签名时间戳地址) VeriSign: http://timestamp.verisign.com/scripts/timstamp.dll Comodo: http://timestamp.comodoca.com/authenticode GeoTrust/TrustCenter: http://www.trustcenter.de/codesigning/timestamp
(图25:给数据盖时间戳) 16、完成,在图25中单击“下一步(N)”按钮便可来到数字签名向导的最后一步,即操作总览,如图26所示,单击“完成”按钮便可大功告成,如图27所示: (图26,完成操作总览)
(图27:签名成功提示) |
###########以下是针对上一篇我们自己开发的ActiveX发布时出现的问题补充############
呵呵,不要以为这样发布就会成功。 博文中说用工具查看我们自己开发的ActiveX控件GUID,但我的好像查看不了。 其实我们在vc工程中就能查看到。双击DMyActiveX接口类,
找到 [ uuid(743F39F2-E3A5-4550-A203-4A1CFAE9ABCF), helpstring("MyActiveX Control"), control ] coclass MyActiveX { [default] dispinterface _DMyActiveX; [default, source] dispinterface _DMyActiveXEvents; };
方法中743F39F2-E3A5-4550-A203-4A1CFAE9ABCF就是我们ActiveX的GUID.
|
还有一种方法就是打开VC的工具OLEView,懒的敲字了,看图吧:
我的MyActiveX.inf如下:
[version]
signature="$CHINA$"
AdvancedINF=1.0
[Add.Code]
MyActiveX.ocx=MyActiveX.ocx
msvcr71.dll=msvcr71.dll
mfc71.dll=mfc71.dll
msvcp71.dll=msvcp71.dll
[MyActiveX.ocx]
file=thiscab
clsid={743F39F2-E3A5-4550-A203-4A1CFAE9ABCF}
FileVersion=1,0,0,0
RegisterServer=yes
[msvcr71.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=11
FileVersion=7,10,3052,4
[mfc71.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=11
FileVersion=7,10,3077,0
[msvcp71.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=11
FileVersion=7,10,3077,0
按照上面的方法,用cabarc -s 6144 n MyActiveX.cab msvcr71.dll mfc71.dll msvcp71.dll MyActiveX.ocx MyActiveX.inf命令制作好MyActiveX..cab。
文件目录:
我们来写个测试页面,代码如下:
<object id='test1' codeBase='http://10.79.108.108/MyActiveX.cab#version=1,0,0,0' classid='clsid: 743F39F2-E3A5-4550-A203-4A1CFAE9ABCF ' height=0 width=0 ></object>
<script>
a=test1.test(2,1);
alert(a);
</script>
注意:链接IP改成你机子的IP
将它保存为test.html格式存放到IIS下,同时把MyActiveX也拷贝到IIS下,也就是C:\Inetpub\wwwroot下。
打开页面测试下:
http://10.79.108.108/test.html
弹出对话框:
选择是:
呵呵,弹出计算值3。算是成功了一半。那为什么系统没有提示下载控件呢?这是因为VS在编译的时候已经帮我们把控件注册到系统中了。
那现在首要的问题,就是先解决上面那个是否允许activex运行的提示框。
在网上查了下资料,说是要实现ISafeObject接口。那好,我们下面就来实现:打开工程,找到CMyActiveXCtr类,双击打开文件:
在文件中添加引用:
#include "comcat.h"
#include "Objsafe.h"
两个头文件。
并在DECLARE_DYNCREATE(CMyActiveXCtro)后添加如下代码:
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART(ObjSafe, IObjectSafety)
STDMETHOD_(HRESULT, GetInterfaceSafetyOptions) (
/* [in] */ REFIID riid,
/* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
/* [out] */ DWORD __RPC_FAR *pdwEnabledOptions
);
STDMETHOD_(HRESULT, SetInterfaceSafetyOptions) (
/* [in] */ REFIID riid,
/* [in] */ DWORD dwOptionSetMask,
/* [in] */ DWORD dwEnabledOptions
);
END_INTERFACE_PART(ObjSafe);
效果如图:
在工程目录中切换到FileView模式,打开MyActiveXCtrl.cpp文件,
然后将以下代码添加到构造函数CMyActiveXCtrl:: CMyActiveXCtrl ()上面,CMyActiveXCtrl替换为你的控件名称:
/
// Interface map for IObjectSafety
BEGIN_INTERFACE_MAP( CMyActiveXCtrl, COleControl )
INTERFACE_PART(CMyActiveXCtrl, IID_IObjectSafety, ObjSafe)
END_INTERFACE_MAP()
/
// IObjectSafety member functions
// Delegate AddRef, Release, QueryInterface
ULONG FAR EXPORT CMyActiveXCtrl::XObjSafe::AddRef()
{
METHOD_PROLOGUE(CMyActiveXCtrl, ObjSafe)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CMyActiveXCtrl::XObjSafe::Release()
{
METHOD_PROLOGUE(CMyActiveXCtrl, ObjSafe)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT CMyActiveXCtrl::XObjSafe::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CMyActiveXCtrl, ObjSafe)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
const DWORD dwSupportedBits =
INTERFACESAFE_FOR_UNTRUSTED_CALLER |
INTERFACESAFE_FOR_UNTRUSTED_DATA;
const DWORD dwNotSupportedBits = ~ dwSupportedBits;
/
// CStopLiteCtrl::XObjSafe::GetInterfaceSafetyOptions
// Allows container to query what interfaces are safe for what. We're
// optimizing significantly by ignoring which interface the caller is
// asking for.
HRESULT STDMETHODCALLTYPE
CMyActiveXCtrl::XObjSafe::GetInterfaceSafetyOptions(
/* [in] */ REFIID riid,
/* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
/* [out] */ DWORD __RPC_FAR *pdwEnabledOptions)
{
METHOD_PROLOGUE(CMyActiveXCtrl, ObjSafe)
HRESULT retval = ResultFromScode(S_OK);
// does interface exist?
IUnknown FAR* punkInterface;
retval = pThis->ExternalQueryInterface(&riid,
(void * *)&punkInterface);
if (retval != E_NOINTERFACE) { // interface exists
punkInterface->Release(); // release it--just checking!
}
// we support both kinds of safety and have always both set,
// regardless of interface
*pdwSupportedOptions = *pdwEnabledOptions = dwSupportedBits;
return retval; // E_NOINTERFACE if QI failed
}
/
// CStopLiteCtrl::XObjSafe::SetInterfaceSafetyOptions
// Since we're always safe, this is a no-brainer--but we do check to make
// sure the interface requested exists and that the options we're asked to
// set exist and are set on (we don't support unsafe mode).
HRESULT STDMETHODCALLTYPE
CMyActiveXCtrl::XObjSafe::SetInterfaceSafetyOptions(
/* [in] */ REFIID riid,
/* [in] */ DWORD dwOptionSetMask,
/* [in] */ DWORD dwEnabledOptions)
{
METHOD_PROLOGUE(CMyActiveXCtrl, ObjSafe)
// does interface exist?
IUnknown FAR* punkInterface;
pThis->ExternalQueryInterface(&riid, (void * *)&punkInterface);
if (punkInterface) { // interface exists
punkInterface->Release(); // release it--just checking!
}
else { // interface doesn't exist
return ResultFromScode(E_NOINTERFACE);
}
// can't set bits we don't support
if (dwOptionSetMask & dwNotSupportedBits) {
return ResultFromScode(E_FAIL);
}
// can't set bits we do support to zero
dwEnabledOptions &= dwSupportedBits;
// (we already know there are no extra bits in mask )
if ((dwOptionSetMask & dwEnabledOptions) !=
dwOptionSetMask) {
return ResultFromScode(E_FAIL);
}
// don't need to change anything since we're always safe
return ResultFromScode(S_OK);
}
效果如下图,注意画红框的地方:
F7编译以后,按前面的步骤重新发布。
打开测试页面http://10.79.108.108/test.html,呵呵那个讨厌的对话框消失了。
现在这个ActiveX是完全做好了,下一步我们来看看怎样让用户下载安装。
先在本地电脑测试:
因为我们用VC编译时,VC已经帮我们把ActiveX注册到系统中了,所以我们想看到下载安装画面,先必须删除注册信息。
打开运行窗口,输出regedit命令,查找我们的控件GUI: 743F39F2-E3A5-4550-A203-4A1CFAE9ABCF
我这里找到三项,那全部删除。
在打开测试页面之前,我们还得做个工作,就是设置IE安全。打开IE工具->Internet选项,如果是局域网,设置本地Intrance,允许下载未签名和已签名的ActiveX。如果是外网,方法一样。
现在打开测试页http://10.79.108.108/test.html
成功弹出下载ActiveX对话框。
点击安装,程序正常运行。OK,我们已经成功了一半。
上面只是在本地测试成功。现在在其他计算机上访问测试页,不要忘了IE的安全设置。打开页面后也是弹出上面的安装界面。可是,点安装后,程序无法正常运行。而且每次刷新页面,安装对话框总是弹出,很是郁闷。
经过Baidu,又找到了方法。原来是其他计算机上没有安装我们activeX运行所需的库文件。那我们就想办法让用户把这用到的DLL全部下载。
那首先得知道我们的activeX用到了哪些库。如下图,打开VC的工具Depends
选择我们的MyActiveX.ocx控件,如下图:
那 我们可以看到我们用到的DLL有6个,一般Kernel32.DLL和OLEAUT32.DLL文件每个操作系统都有,所以剩下的4个DLL,在你机子上 全盘搜索,找到这4个dll后将他们放入你的MyActiveX.ocx相同文件夹下,编辑MyActiveX.inf, 这些dll的版本信息FileVersion可以在此dll上点击右键->属性中得到:
[version]
signature="$CHINA$"
AdvancedINF=1.0
[Add.Code]
MyActiveX.ocx=MyActiveX.ocx
msvcr71.dll=msvcr71.dll
mfc71.dll=mfc71.dll
msvcp71.dll=msvcp71.dll
MFC42D.dll=MFC42D.dll
MSVCRTD.DLL=MSVCRTD.DLL
gdi32.dll=gdi32.dll
MFCO42D.DLL=MFCO42D.DLL
[MyActiveX.ocx]
file=thiscab
clsid={743F39F2-E3A5-4550-A203-4A1CFAE9ABCF}
FileVersion=1,0,0,0
RegisterServer=yes
[msvcr71.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=11
FileVersion=7,10,3052,4
[mfc71.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=11
FileVersion=7,10,3077,0
[msvcp71.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=11
FileVersion=7,10,3077,0
[MFC42D.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=11
FileVersion=6.0.9782.0
[MSVCRTD.DLL]
file-win32-x86=thiscab
RegisterServer=no
DestDir=11
FileVersion=6.0.9782.0
[gdi32.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=11
FileVersion=5.2.3790.2542
[MFCO42D.DLL]
file-win32-x86=thiscab
RegisterServer=no
DestDir=11
FileVersion=6.0.9782.0
保存后文件目录如下:
用 cabarc -s 6144 n MyActiveX.cab msvcr71.dll mfc71.dll msvcp71.dll MFC42D.dll MSVCRTD.DLL gdi32.dll MFCO42D.DLL MyActiveX.ocx MyActiveX.inf
命令生成MyActiveX.cab文件。
在其他计算机上打开测试页。安装ActiveX成功,并且运行正常。
就此,一个简单的ActiveX发布成功了。
后面,我们还将对我们的ActiveX增加新的功能。敬请关注。
呵呵,好累啊~~~~
打完收工…………………….