VC++开发Activex控件以及签名发布

前言 
      本人不懂C++,当前由于要做一个打印控件,使用Activex插件技术,所以在网络上搜索了相关技术文档,今天有空,遂将自己的当前学到的一些关于Activex技术整理之,进而和朋友们分享之。 
一、 开发环境 
开发工具:Visual Studio 2008 
开发语言:Visual C++

测试工具:IE 7+
二、 创建MFC ActiveX项目 
1、 打开VS2008新建MFC项目。这里我们取名为“PrintUtil”。

 

 
2、 输入项目名称为“PrintUtil”和项目位置。点击“确定”按钮,打开向导对话框。 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 
3、 选择“控件设置”选项卡,具体设置可参考上图。其它选项卡为默认设置。最后点击“完成”按钮保存设置。

 

三、 添加控件方法 
VC2005会为我们自动创建好MFC ActiveX程序框架,我们只要给该ActiveX控件添加方法即可。现在我们给控件添加一个“AddFun”方法,这个方法是将两个数相加并返回结果。 
1、 点击“视图”,打开“类视图”窗口。 


 
  
2、 展开“PrintUtilLib”项,选中“_DPrintUtil”项。点击鼠标右键,选择“添加”下的“添加方法”。 


 
 
3、 打开添加方法向导窗口。因为我们是添加一个加法方法,所以我们设置的返回类型为LONG型,方法名设为AddFun,添加两个LONG类型参数Add1,Add2。 

4、   其它为默认设置,点击“完成”按钮完成添加方法。接下来我们打开“解决方案资源管理器”打开“PrintUtilCtrl.cpp”文件。



5、 打开代码视图,我们会发现VC2005已经为我们添加了一个“AddFun”方法,我们在方法内添加“return Add1 + Add2;”语句。

 

四、 MFC Activex 安全问题 
1、在默认环境下,编译的MFC Activex控件,只能在本地代码中运行,即在http://localhost/xxx/xxx.htm中执行,而在http://127.0.0.1/xxx/xxx.htm中提示无相关属性,需要设置其初始化和脚本运行的安全性 
ActiveX在远程IE页面上执行,需要实现安全接口。 
在ATL写的ActiveX中,用IObjectSafety。 
http://support.microsoft.com/kb/168371/en-us 
在MFC写的ActiveX中,直接修改注册表。 
http://support.microsoft.com/kb/161873/en-us 
mfc实现的ocx,要在app实现文件中包括两个文件: 
在PrintUtil.h文件中实现以下方法:

Cpp代码  收藏代码
  1. // PrintUtil.cpp : CPrintUtilApp 和DLL 注册的实现。   
  2. #include "stdafx.h"   
  3. #include "PrintUtil.h"   
  4. #include <objsafe.h>   
  5.   
  6. #ifdef _DEBUG   
  7. #define new DEBUG_NEW   
  8. #endif   
  9.   
  10.   
  11. CPrintUtilApp theApp;   
  12.   
  13. const GUID CDECL BASED_CODE _tlid =   
  14. { 0x3C8F86CA, 0x6470, 0x4B7C, { 0xB2, 0x76, 0x3B, 0xEB, 0xF, 0xB0, 0x1B, 0x4E } };   
  15. const WORD _wVerMajor = 1;   
  16. const WORD _wVerMinor = 0;   
  17.   
  18.   
  19.   
  20. // CPrintUtilApp::InitInstance - DLL 初始化   
  21.   
  22. BOOL CPrintUtilApp::InitInstance()   
  23. {   
  24. BOOL bInit = COleControlModule::InitInstance();   
  25.   
  26. if (bInit)   
  27. {   
  28. // TODO: 在此添加您自己的模块初始化代码。   
  29. }   
  30.   
  31. return bInit;   
  32. }   
  33.   
  34.   
  35.   
  36. // CPrintUtilApp::ExitInstance - DLL 终止   
  37.   
  38. int CPrintUtilApp::ExitInstance()   
  39. {   
  40. // TODO: 在此添加您自己的模块终止代码。   
  41.   
  42. return COleControlModule::ExitInstance();   
  43. }   
  44.   
  45. // 创建组件种类     
  46. HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)   
  47. {      
  48.     ICatRegister* pcr = NULL ;      
  49.     HRESULT hr = S_OK ;      
  50.     hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);      
  51.     if (FAILED(hr)) return hr;      
  52.     // Make sure the HKCR\Component Categories\{..catid...}      
  53.     // key is registered.      
  54.     CATEGORYINFO catinfo;      
  55.     catinfo.catid = catid;      
  56.     catinfo.lcid = 0x0409 ; // english      
  57.     // Make sure the provided description is not too long.      
  58.     // Only copy the first 127 characters if it is.      
  59.     int len = wcslen(catDescription);      
  60.     if (len>127) len = 127;      
  61.     wcsncpy(catinfo.szDescription, catDescription, len);      
  62.     // Make sure the description is null terminated.      
  63.     catinfo.szDescription[len] = '\0';      
  64.     hr = pcr->RegisterCategories(1, &catinfo);      
  65.     pcr->Release();      
  66.     return hr;      
  67. }    
  68.   
  69. // 注册组件种类     
  70. HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)   
  71. {      
  72.     // Register your component categories information.      
  73.     ICatRegister* pcr = NULL ;      
  74.     HRESULT hr = S_OK ;      
  75.     hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);      
  76.     if (SUCCEEDED(hr)) {      
  77.       // Register this category as being "implemented" by the class.      
  78.       CATID rgcatid[1];      
  79.       rgcatid[0] = catid;      
  80.       hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);      
  81.     }      
  82.     if (pcr != NULL) pcr->Release();      
  83.     return hr;      
  84. }     
  85.   
  86. // 卸载组件种类     
  87. HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)   
  88. {      
  89.     ICatRegister* pcr = NULL ;      
  90.     HRESULT hr = S_OK ;      
  91.     hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,      
  92.             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);      
  93.     if (SUCCEEDED(hr)) {      
  94.       // Unregister this category as being "implemented" by the class.      
  95.       CATID rgcatid[1] ;      
  96.       rgcatid[0] = catid;      
  97.       hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);      
  98.     }      
  99.     if (pcr != NULL) pcr->Release();      
  100.     return hr;      
  101. }      
  102.   
  103.   
  104. // DllRegisterServer - 将项添加到系统注册表   
  105. STDAPI DllRegisterServer(void)   
  106. {      
  107.     HRESULT hr;      
  108.     AFX_MANAGE_STATE(_afxModuleAddrThis);      
  109.     if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))      
  110.         return ResultFromScode(SELFREG_E_TYPELIB);      
  111.     if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))      
  112.         return ResultFromScode(SELFREG_E_CLASS);      
  113.     // 标记控件初始化安全.      
  114.     // 创建初始化安全组件种类     
  115.     hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!");      
  116.     if (FAILED(hr)) return hr;      
  117.     // 注册初始化安全     
  118.     hr = RegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForInitializing);      
  119.     if (FAILED(hr)) return hr;      
  120.     // 标记控件脚本安全     
  121.     // 创建脚本安全组件种类     
  122.     hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");      
  123.     if (FAILED(hr)) return hr;      
  124.     // 注册脚本安全组件种类     
  125.     hr = RegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForScripting);      
  126.     if (FAILED(hr)) return hr;      
  127.     return NOERROR;      
  128. }      
  129.   
  130. // DllUnregisterServer - Removes entries from the system registry      
  131. STDAPI DllUnregisterServer(void)   
  132. {      
  133.     HRESULT hr;      
  134.     AFX_MANAGE_STATE(_afxModuleAddrThis);      
  135.     if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))      
  136.         return ResultFromScode(SELFREG_E_TYPELIB);      
  137.     if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))      
  138.         return ResultFromScode(SELFREG_E_CLASS);      
  139.     // 删除控件初始化安全入口.      
  140.     hr=UnRegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForInitializing);      
  141.     if (FAILED(hr)) return hr;      
  142.     // 删除控件脚本安全入口     
  143.     hr=UnRegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForScripting);      
  144.     if (FAILED(hr)) return hr;      
  145.     return NOERROR;      
  146. }    

  

现在控件就可以在自注册时就注册为安全控件了。 
2、设置项目属性 将配置类型设置成静态库(.lib) 

3、最后生成项目,ocx控件就产生了。 
五、 ActiveX发布步骤 
在这里简单说明下,打包activeX需要制作证书,具体用到makecert 、cert2spc 、signtool 这三个VS提供的工具,工具在VS文件夹里面,以下制作过程需要在工具所在的文件夹下完成! 
1、单击"开始"-->"运行(R)"-->输入"cmd"-->回车-->进入到操作的控件所在的目录(需要将上面所说的工具,和ocx控件放到一个文件夹下);


2、创建PVK文件(私人密匙文件),在命令行中输入" makecert -sk PrintUtil PrintUtil.pvk -n CN=XXXXXXX公司",然后回车; 
sk-表示主题的密钥容器位置,ss-主题的证书存储名称, n-证书颁发对象,r-证书存储位置; 

3、创建CER文件(公司证书),在命令行中输入" makecert -sk PrintUtil.pvk PrintUtil.cer ",然后回车,如图所示,若出现"Successed"提示,则会在C:\ PrintUtil目录下生成PrintUtil.cer文件; 
sk-表示主题的密钥容器位置,is-颁发者的证书存储名称, n-证书颁发对象,ic-颁发者的证书存储位置,-$-授权范围(用于代码签名);

 
4、创建SPC测试软件出版商证明书,在命令行中输入" cert2spc PrintUtil.cer PrintUtil.spc ",然后回车; 

5、创建INF文件,用记录本编辑以下信息:

Inf代码  收藏代码
  1. [version]   
  2. signature="$CHINA$"   
  3. AdvancedINF=1.0   
  4.   
  5. [Add.Code]   
  6. PrintUtil.ocx=PrintUtil.ocx   
  7.   
  8. [PrintUtil.ocx]   
  9. file=thiscab   
  10. clsid={ 1BABEDC3-3936-4850-B79B-2417E28A5655 }   
  11. FileVersion=1,0,0,0   
  12. RegisterServer=yes   
  13. DestDir=11   

 

6、创建CAB文件,在命令行中输入" cabarc -s 6144 n PrintUtil.cab PrintUtil.ocx PrintUtil.inf ",-s 选项表示在压缩文件中保留用于代码签名的空间,n命令指定希望创建 CAB 文件,然后回车; 

7、使用Code Signing Wizard签署一个CAB文件,首先双击运行工具集里面的signcode.exe(或在命令行里直接输入“signcode”后回车),系统会弹出如图所示的数字签名向导; 

8、单击"下一步(N)"按钮,选择要进行数字签名的且已做成CAB包的文件PrintUtil.cab文件; 

9、选择好CAB包后单击"下一步(N)"按钮,在选择想要的签名类型里选择"自定义(C)"并单击"下一步(N)"按钮; 

10、点击“从文件选择”签名证书 ( 公钥文件 ),如: PrintUtil.cer : 

11、在图20中单击“下一步(N)”按钮来到下图,然后在图里选择“CSP中的私钥(K)”。 

12、在上图中单击“下一步(N)”按钮,然后在下图中的散列算法中选择“shal”,并单击“下一步(N)”按钮。 

13、在“证书路径中的证书”中选择“证书路径中的所有证书,包括根证书(C)”,在“其它证书(可选)”中选择“包括在以下PKCS #7 证书(.p7b)文件中的证书(P):”,并单击“浏览(R)…”按钮选择PrintUtil.spc文件,选择完后单击“下一步(N)”按钮: 

14、接下来在弹出的“数据描述”窗口中输入公司的名称和网址并单击“下一步(N)”按: 

15、现大部份工作都已完成,在接下来的一步当中是可选的操作,其作用只是为CAB加入时间戳,此步骤完全可以不做。 

VeriSign:  http://timestamp.verisign.com/scripts/timstamp.dll 
Comodo:  http://timestamp.comodoca.com/authenticode 
GeoTrust/TrustCenter: http://www.trustcenter.de/codesigning/timestamp 
16、完成 

六、 运行 
编写jsp页面,test.jsp 

Html代码  收藏代码
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>   
  2. <%   
  3. String path = request.getContextPath();   
  4. String basePath = request.getScheme() + "://"   
  5. + request.getServerName() + ":" + request.getServerPort()   
  6. + path + "/";   
  7. %>   
  8. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">   
  9. <html>   
  10. <head>   
  11. <base href="<%=basePath%>">   
  12.   
  13. <title>My JSP 'index.jsp' starting page</title>   
  14. <meta http-equiv="pragma" content="no-cache">   
  15. <meta http-equiv="cache-control" content="no-cache">   
  16. <meta http-equiv="expires" content="0">   
  17. <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">   
  18. <meta http-equiv="description" content="This is my page">   
  19. <object id="printUtil"   
  20. classid="clsid:1BABEDC3-3936-4850-B79B-2417E28A5655"   
  21. codebase="<%=basePath%>/PrintUtil.cab#version=1,0,0,0"></object>   
  22. <script type="text/javascript">   
  23.     function add(arg1,args) {   
  24.         try {   
  25.             var v = printUtil.AddFun(arg1,args);   
  26.             alert(v);   
  27.         } catch (e) {   
  28.             alert(e.message)   
  29.         }   
  30.     }   
  31.     add(1,2);   
  32. </script>   
  33. </head>   
  34. <body>   
  35. </body>   
  36. </html>  

  
运行结果:



 
 好了,今天就写到这里了,如果朋友们有什么疑问或者更好的建议和意见,请Email Me。

 

Email:[email protected]

 

本文所用到的工具见附件:

 

转载请声明本文链接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章