前言
本人不懂C++,当前因为要作一个打印控件,使用Activex插件技术,因此在网络上搜索了相关技术文档,今天有空,遂将本身的当前学到的一些关于Activex技术整理之,进而和朋友们分享之。
1、 开发环境
开发工具:Visual Studio 2008
开发语言:Visual C++javascript
测试工具:IE 7+
2、 建立MFC ActiveX项目
一、 打开VS2008新建MFC项目。这里咱们取名为“PrintUtil”。html

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

三、 选择“控件设置”选项卡,具体设置可参考上图。其它选项卡为默认设置。最后点击“完成”按钮保存设置。算法
3、 添加控件方法
VC2005会为咱们自动建立好MFC ActiveX程序框架,咱们只要给该ActiveX控件添加方法便可。如今咱们给控件添加一个“AddFun”方法,这个方法是将两个数相加并返回结果。
一、 点击“视图”,打开“类视图”窗口。

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

三、 打开添加方法向导窗口。由于咱们是添加一个加法方法,因此咱们设置的返回类型为LONG型,方法名设为AddFun,添加两个LONG类型参数Add1,Add2。

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

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

4、 MFC Activex 安全问题
一、在默认环境下,编译的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文件中实现如下方法:app
Cpp代码 框架

- // PrintUtil.cpp : CPrintUtilApp 和DLL 注册的实现。
- #include "stdafx.h"
- #include "PrintUtil.h"
- #include <objsafe.h>
-
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
-
-
- CPrintUtilApp theApp;
-
- const GUID CDECL BASED_CODE _tlid =
- { 0x3C8F86CA, 0x6470, 0x4B7C, { 0xB2, 0x76, 0x3B, 0xEB, 0xF, 0xB0, 0x1B, 0x4E } };
- const WORD _wVerMajor = 1;
- const WORD _wVerMinor = 0;
-
-
-
- // CPrintUtilApp::InitInstance - DLL 初始化
-
- BOOL CPrintUtilApp::InitInstance()
- {
- BOOL bInit = COleControlModule::InitInstance();
-
- if (bInit)
- {
- // TODO: 在此添加您本身的模块初始化代码。
- }
-
- return bInit;
- }
-
-
-
- // CPrintUtilApp::ExitInstance - DLL 终止
-
- int CPrintUtilApp::ExitInstance()
- {
- // TODO: 在此添加您本身的模块终止代码。
-
- return COleControlModule::ExitInstance();
- }
-
- // 建立组件种类
- HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)
- {
- ICatRegister* pcr = NULL ;
- HRESULT hr = S_OK ;
- hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
- if (FAILED(hr)) return hr;
- // Make sure the HKCR\Component Categories\{..catid...}
- // key is registered.
- CATEGORYINFO catinfo;
- catinfo.catid = catid;
- catinfo.lcid = 0x0409 ; // english
- // Make sure the provided description is not too long.
- // Only copy the first 127 characters if it is.
- int len = wcslen(catDescription);
- if (len>127) len = 127;
- wcsncpy(catinfo.szDescription, catDescription, len);
- // Make sure the description is null terminated.
- catinfo.szDescription[len] = '\0';
- hr = pcr->RegisterCategories(1, &catinfo);
- pcr->Release();
- return hr;
- }
-
- // 注册组件种类
- HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
- {
- // Register your component categories information.
- ICatRegister* pcr = NULL ;
- HRESULT hr = S_OK ;
- hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
- if (SUCCEEDED(hr)) {
- // Register this category as being "implemented" by the class.
- CATID rgcatid[1];
- rgcatid[0] = catid;
- hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
- }
- if (pcr != NULL) pcr->Release();
- return hr;
- }
-
- // 卸载组件种类
- HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
- {
- ICatRegister* pcr = NULL ;
- HRESULT hr = S_OK ;
- hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
- NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
- if (SUCCEEDED(hr)) {
- // Unregister this category as being "implemented" by the class.
- CATID rgcatid[1] ;
- rgcatid[0] = catid;
- hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);
- }
- if (pcr != NULL) pcr->Release();
- return hr;
- }
-
-
- // DllRegisterServer - 将项添加到系统注册表
- STDAPI DllRegisterServer(void)
- {
- HRESULT hr;
- AFX_MANAGE_STATE(_afxModuleAddrThis);
- if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
- return ResultFromScode(SELFREG_E_TYPELIB);
- if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
- return ResultFromScode(SELFREG_E_CLASS);
- // 标记控件初始化安全.
- // 建立初始化安全组件种类
- hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!");
- if (FAILED(hr)) return hr;
- // 注册初始化安全
- hr = RegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForInitializing);
- if (FAILED(hr)) return hr;
- // 标记控件脚本安全
- // 建立脚本安全组件种类
- hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");
- if (FAILED(hr)) return hr;
- // 注册脚本安全组件种类
- hr = RegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForScripting);
- if (FAILED(hr)) return hr;
- return NOERROR;
- }
-
- // DllUnregisterServer - Removes entries from the system registry
- STDAPI DllUnregisterServer(void)
- {
- HRESULT hr;
- AFX_MANAGE_STATE(_afxModuleAddrThis);
- if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
- return ResultFromScode(SELFREG_E_TYPELIB);
- if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
- return ResultFromScode(SELFREG_E_CLASS);
- // 删除控件初始化安全入口.
- hr=UnRegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForInitializing);
- if (FAILED(hr)) return hr;
- // 删除控件脚本安全入口
- hr=UnRegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForScripting);
- if (FAILED(hr)) return hr;
- return NOERROR;
- }
如今控件就能够在自注册时就注册为安全控件了。
二、设置项目属性 将配置类型设置成静态库(.lib)

三、最后生成项目,ocx控件就产生了。
5、 ActiveX发布步骤
在这里简单说明下,打包activeX须要制做证书,具体用到makecert 、cert2spc 、signtool 这三个VS提供的工具,工具在VS文件夹里面,如下制做过程须要在工具所在的文件夹下完成!
一、单击"开始"-->"运行(R)"-->输入"cmd"-->回车-->进入到操做的控件所在的目录(须要将上面所说的工具,和ocx控件放到一个文件夹下);jsp
二、建立PVK文件(私人密匙文件),在命令行中输入" makecert -sk PrintUtil PrintUtil.pvk -n CN=XXXXXXX公司",而后回车;
sk-表示主题的密钥容器位置,ss-主题的证书存储名称, n-证书颁发对象,r-证书存储位置;

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

四、建立SPC测试软件出版商证实书,在命令行中输入" cert2spc PrintUtil.cer PrintUtil.spc ",而后回车;

五、建立INF文件,用记录本编辑如下信息:
Inf代码

- [version]
- signature="$CHINA$"
- AdvancedINF=1.0
-
- [Add.Code]
- PrintUtil.ocx=PrintUtil.ocx
-
- [PrintUtil.ocx]
- file=thiscab
- clsid={ 1BABEDC3-3936-4850-B79B-2417E28A5655 }
- FileVersion=1,0,0,0
- RegisterServer=yes
- DestDir=11
六、建立CAB文件,在命令行中输入" cabarc -s 6144 n PrintUtil.cab PrintUtil.ocx PrintUtil.inf ",-s 选项表示在压缩文件中保留用于代码签名的空间,n命令指定但愿建立 CAB 文件,而后回车;

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

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

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

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

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

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

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

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

1五、现大部份工做都已完成,在接下来的一步当中是可选的操做,其做用只是为CAB加入时间戳,此步骤彻底能够不作。
VeriSign: http://timestamp.verisign.com/scripts/timstamp.dll
Comodo: http://timestamp.comodoca.com/authenticode
GeoTrust/TrustCenter: http://www.trustcenter.de/codesigning/timestamp
1六、完成

6、 运行
编写jsp页面,test.jsp
Html代码

- <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
- <%
- String path = request.getContextPath();
- String basePath = request.getScheme() + "://"
- + request.getServerName() + ":" + request.getServerPort()
- + path + "/";
- %>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <base href="<%=basePath%>">
-
- <title>My JSP 'index.jsp' starting page</title>
- <meta http-equiv="pragma" content="no-cache">
- <meta http-equiv="cache-control" content="no-cache">
- <meta http-equiv="expires" content="0">
- <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
- <meta http-equiv="description" content="This is my page">
- <object id="printUtil"
- classid="clsid:1BABEDC3-3936-4850-B79B-2417E28A5655"
- codebase="<%=basePath%>/PrintUtil.cab#version=1,0,0,0"></object>
- <script type="text/javascript">
- function add(arg1,args) {
- try {
- var v = printUtil.AddFun(arg1,args);
- alert(v);
- } catch (e) {
- alert(e.message)
- }
- }
- add(1,2);
- </script>
- </head>
- <body>
- </body>
- </html>
运行结果:

好了,今天就写到这里了,若是朋友们有什么疑问或者更好的建议和意见,请Email Me。
读完本篇能够参考 【经常使用博客系列】中的ActiveX 中相关的系列文章,详细深刻学习
原文连接有相关的工具 makeCAB.rar 下载项。