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. }    
// 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;    
}  

  

現在控件就可以在自注冊時就註冊爲安全控件了。
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>  
<%@ 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。

 

Email:[email protected]


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

 

轉載請聲明本文鏈接

  • 大小: 29.9 KB
  • 大小: 26.9 KB
  • 大小: 27 KB
  • 大小: 18.5 KB
  • 大小: 6.7 KB
  • 大小: 6 KB
  • 大小: 82.1 KB
  • 大小: 9.4 KB
  • 大小: 27 KB
  • 大小: 18.4 KB
  • 大小: 13 KB
  • 大小: 8.8 KB
  • 大小: 13.7 KB
  • 大小: 17.9 KB
  • 大小: 32.9 KB
  • 大小: 25.3 KB
  • 大小: 7.6 KB
  • 大小: 7.7 KB
  • 大小: 8.6 KB
  • 大小: 9.6 KB
  • 大小: 10.8 KB
  • 大小: 18.4 KB
  • 大小: 21 KB
  • 大小: 17.2 KB
  • 大小: 26.9 KB
  • 大小: 13.2 KB
  • 大小: 20 KB
  • 大小: 14.7 KB
  • 大小: 12.9 KB
  • 大小: 19.3 KB
  • 大小: 10.2 KB
  • 大小: 31.7 KB
  • 大小: 20.6 KB
  • 大小: 35.3 KB
  • 大小: 12.5 KB
  • 大小: 21.3 KB
  • 大小: 21.1 KB
  • 大小: 36.6 KB
  • 大小: 14.5 KB
  • 大小: 23.3 KB
  • 大小: 7.8 KB
  • 大小: 6.4 KB
  • 大小: 6.2 KB
發佈了5 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章