1、ActiveX控件概述
ActiveX控件是基於組件對象模型 (COM) 的可重用軟件組件,廣泛應用於桌面及Web應用中。在Windows操作系統以OCX結尾的文件,OCX代表“對象鏈接與嵌入控件”(OLE),這個技術是Microsoft提出的程序技術,用於處理桌面文件的混合使用。在VC下ActiveX控件的開發可以分為三種:
一種是直接用COM的API來開發,這樣做顯然非常的麻煩,對程序員要求也非常高,因此一般是不予考慮的;
一種是基於傳統的MFC,采用面向對象的方式將COM的基本功能封裝在若干MFC的C++類中,開發者通過繼承這些類得到COM支持功能。MFC為廣大VC程序員所熟悉,易於上手學習,但缺點是MFC封裝的東西比較多,因此用MFC開發出來的控件相對會比較大,因此比較適於開發桌面ActiveX控件,尤其是有GUI界面的控件;
第三種就是基於ATL的,ATL可以說是專門面向COM開發的一套框架,使用了C++的模板技術,在運行時不需要依賴於類似MFC程序所需要的龐大的代碼模塊,更適合於Web應用開發。
本文介紹的是采用第二種方式,即應用MFC進行桌面可視控件開發的方法步驟,開發環境則是基於VC2008。
2、創建基於MFC的ActiveX控件的工程
2.1 ActiveX控件工程的創建
打開VC2008后,我們要先創建一個名稱為StudyActiveX的解決方案,在該解決方案中按圖1新建一個名為ActiveXDemo項目,這里在新建項目頁的左側選擇Visual C++ 下的MFC,在右側選擇MFC ActiveX控件,填上項目名稱“ActiveXDemo”。
圖1
接下來進入控件向導頁,在向導的第二頁(如圖2中)有個運行時許可證,選中這個的話會在生成控件的同時生成一個許可證文件ActiveXDemo.lic,其他用戶在使用這個控件的時候必須同時附有這個許可證文件,當該控件在注冊時必須含有該許可證文件才能夠正確的被注冊上,在此我們保持默認狀態,不選。
圖2
下一頁是關於項目中各部分的命名問題,可以根據需要自定義,這里就按默認的情況不做修改了。
圖3
下一頁是選擇控件基於哪種控件的擴展以及控件的一些基本特性。如果新建的控件是基於某種特定控件的話,就在創建的控件基於下選擇所要繼承的控件名,否則就保持none。下方的附加功能根據實際需要進行選擇,並且可以將鼠標放置於選項上方,功能的說明會自動顯示在動態出現的小提示信息窗口中。選擇完畢點擊完成,向導就根據你的選擇生成新項目,這里我們選擇了none。
圖4
點擊“完成”按鈕后進入開發環境,我們可以先看一下類視圖,如圖5所示:
圖5
(1)其中的ActiveXDemoApp.cpp是我們這個控件的主程序模塊,定義了控件的注冊 (DllRegisterServer)、卸載(DllUnregisterServer)等功能,一般不用動,如有需要我們可以在其中的CActiveXDemoApp::InitInstance()和CActiveXDemoApp::ExitInstance() 中定義我們自己的初始化和終止操作代碼,一般也就是一些資源的初始化和銷毀工作。
(2)CActiveXDemoCtrl是控件類,我們要做的控件功能基本上就是要在這個類中實現。需要提一下的是在這個類中重寫了父類的OnDraw函數,
圖6
有如下兩句代碼:
pdc->FillRect(rcBounds,CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
pdc->Ellipse(rcBounds);
也就是在控件上畫了一個橢圓,實際控件開發中可以根據功能需要修改重寫這個函數來繪制控件界面。
(3)CActiveXDemoPropPage是屬性頁類,這個類實現了一個在開發時設定控件屬性的對話框。
(4)ActiveXDemoLib是為客戶程序提供本控件的屬性、方法以及可能響應的事件的接口的庫節點,在添加控件的這些功能的時候會用得到。
接下來編譯生成ActiveXDemo工程,則會在工程目錄下的Debug目錄下生成ActiveXDemo.ocx。在編譯的工程快要完成的時候,細心的話你會注意到如下注冊信息:
VC會調用系統的regsvr32.exe程序來注冊我們剛才生成的ActiveXDemo.ocx控件。
2.2 在MFC的對話框中使用控件
在解決方案StudyActiveX中添加一個新“MFC應用程序”工程,名稱為TestActiveX,如圖7所示:
圖7
在接下來的向導中,選擇“基於對話框”的應用程序類型,如圖8所示:
圖8
將窗口切換到TestActiveX工程的窗口資源中,如圖9所示:
圖9
接下來我們會將剛才創建的ActiveXDemo.ocx控件添加到我們的測試窗口中,添加的方法有兩種:
一種是在窗口資源中直接鼠標右鍵選擇“插入ActiveX控件(X)”,如圖10所示,在接下來選擇剛才編寫和注冊的ActiveXDemo Control,然后確定即可。
圖10
另一種方法是現將控件添加到工具箱中,然后再從工具箱中將控件拖到窗口中,添加到工具箱的方法是在工具箱窗口的任意一個控件上鼠標右擊選擇“選擇項(I)…”,在彈出的“選擇工具箱項”中選擇“COM組件”屬性頁中,選擇我們先前創建的“ActiveXDemo Control”控件后確定。
圖11
這樣在我們的工具箱的最下面就會有一個我們剛剛添加進來的示例控件了,如圖12所示。這樣我們就可以像使用按鈕控件一樣來使用這個控件了。
圖12
接下來我們編譯測試工程TestActiveX工程吧,運行后的結果如圖13所示:
圖13
2.2 在HTML網頁中使用控件
在實際應用中我們需要在傳統的HTML網頁中插入ActiveX控件,由ActiveX控件來滿足需求功能。每一個ActiveX Control都會有一個對應的CLSID,該ID是唯一的。例如我們剛才的ActiveXDemo控件的CLSID值為圖16所示位置的值:
圖14
通過OBJECT的CLASSID屬性指定ActiveX Control的ID,然后IE就可以根據CLSID找到相應的ActiveXControl。為了能夠找到ActiveX Control,每一個ActiveX Control都必須先注冊,再使用。ActiveX Contorl的注冊和卸載可以通過實用工具regsvr32來完成,其注冊和卸載命令如下:
下面我們新建一個index.html文件,在文件中寫入如下調用ActiveXDemo控件的代碼:
<HTML> <HEAD> <TITLE>Test ActiveX Page</TITLE> </HEAD> <BODY>
<OBJECT WIDTH=50 HEIGHT=50 CLASSID="CLSID:85C74353-9593-471D-B8AB-8AFAF951548B"> </OBJECT>
</BODY> </HTML> |
然后用IE瀏覽器打開index.html網頁后的效果如圖15(a)所示,此時ActiveX控件要被阻止執行,我們鼠標右鍵允許后,效果如圖15(b)所示。
圖15(b)
圖15(b)
3、ActiveX控件的打包步驟
OCX:OCX稱為對象類別擴充組件(Object Linking and Embedding (OLE) Control Extension);
CAB:壓縮包文件。存儲多個壓縮文件的單個壓縮包文件。這些文件通常用於軟件安裝,還用來減小文件大小和縮短 Web 內容的相關下載時間。
制作CAB文件時需要將所有的相關文件都包含進去,一般需要將OCX做CAB打包即為ocx的開發者本人明確知道所依賴的動態鏈接庫,如果不了解OCX依賴於那些動態鏈接庫,可以通過Depends(VC自帶的)檢查需要的文件,然后使用inf文件將這些東西都寫進去。
3.1 制作inf文件
在此處不對INF文件本身的格式做額外說明,如有興趣可自行上網搜索。
此OCX控件CAB打包的INF文件如下書寫,首先此控件不僅僅只有一個ocx文件,還具備其它的動態鏈接庫,同時還有ini配置文件:
[version] signature="$CHICAGO$" AdvancedINF=2.0 [Add.Code] CCEA.ocx=CCEA.ocx DesktopAgent.dll=DesktopAgent.dll ProxySock.dll=ProxySock.dll Web2Agent.dll=Web2Agent.dll Config.ini=Config.ini [CCEA.ocx] file-win32-x86=thiscab clsid={6F82C754-6C31-43EA-9818-E95AD4E872FC} FileVersion=1,6,0,44 RegisterServer=yes DestDir=10 [DesktopAgent.dll] file-win32-x86=thiscab FileVersion=1,6,2,27 DestDir=10 [ProxySock.dll] file-win32-x86=thiscab FileVersion=1,6,0,1 DestDir=10 [Web2Agent.dll] file-win32-x86=thiscab FileVersion=1,0,0,0 DestDir=10 [Config.ini] file-win32-x86=thiscab FileVersion=1,0,0,2 DestDir=10 |
下面對以上INF文件的內容做詳細說明:
[Version]區的內容可以不考慮,接下來就是最重要的[Add.Code]區,格式為XXXX=XXXX;前面是要下載的文件名,后面是對應這個文件的區域名,可以是任何名字,不過一般都是和文件的名字相同,這樣方便維護。
再接下來是各個文件的區域,[XXX]其中XXX為[Add.Code]區中的文件名,其中[CCEA.ocx]文件區域的參數比其它文件多,這是因為其為此CAB的核心,其它文件均依賴於它且它需要自動注冊,首先來講解[CCEA.ocx]部分:
(1)file-win32-x86=thiscab
這個值告訴ie到哪里去得到這個ocx, file一共包括三個部分,第一部分是file,這個永遠都是這樣的;第二部分告訴聲明支持的OS,win32表示windows,mac就是蘋果MAC OX了;第三部分是CPU類型,比如說x86、mips等。
file的值可以取三個:一個URL、ignore和thiscab,如果是URL則說明到URL所在的位置去下;如果是ignore說明對於這種OS和CPU,不需要下載這個文件;如果是thiscab就在當前的cab文件中了;
(2)clsid={6F82C754-6C31-43EA-9818-E95AD4E872FC}
此處需要填寫該ocx的class guid;
(3)RegisterServer=yes
此處可以取兩個值yes和no,如果為yes則說明ie要注冊該ocx,如果是no就不必注冊;
(4)DestDir=10
此處的值是ocx將要存到本地硬盤的位置,
如果它的值是10,則將ocx放到\Windows或者\WinNT下;
如果是11,則放到\Windows\System或者\WinNT\System32下;
如果是空(就是沒有值)則會放到\Windows或者\WinNT下的Downloaded Program Files目錄下;
此處選為10是放在\Windows是考慮\Windows下文件量小易於操作便於卸載;
(5)FileVersion=1,6,0,44
此處說明了ocx的版本號,目前ocx版本號為1.6.0.44,此處也是CAB自動升級的判斷依據,其它文件區域內容標識與[CCEA.ocx]部分,此處不再贅敘。
3.2 制作CAB文件
在此之前你需要實現ActiveX控件安全的初始化和腳本,相關信息可以查閱ActiveX控件實現安全的初始化和腳本利用iexpress.exe(windows提供的一個向導式cab制作工具)進行打包,進入CMD鍵入iexpress回車即顯示如下界面:
選“Create new Self Extraction Directive file”,點“下一步”,出現如下框:
選擇“Create compressed files only(ActiveX Installs)”,點擊下一步,出現如下框圖,點擊Add,添加INF中標注的所有文件:
點擊下一步,點擊Browse,選擇CCEA.CAB文件的存放地址並命名CAB文件名,此文件名在IE加載時html標簽時使用,並且要選中“Store files using Long File Name inside Package“:
點擊下一步:
此處選擇“Don’t save”,一直點擊下一步,直到完成,最后在前面選擇的位置會出現以前面所取名字一致的CAB文件:
至此CAB的打包工作已經完成。
4 CAB增加數字簽名
此處不做說明,可以申請測試證書供測試,也可以自己寫證書,只不過根證書需要重新安裝,如果是商業化應用的話還是購買微軟認證機構的代碼簽名,這樣不需要額外的操作即可正常使用增加簽名的CAB文件,只在第一次使用時安裝部署后續的再次使用沒有任何提示報警即可加載,一般購買機構會提供簽名的工具,可能是批處理工具也可能給相應文檔,最終使用的還是signtool.exe簽名工具。
5CAB升級方式
5.1 OCX及依賴DLL升級
如果CAB文件中ocx機器附屬dll文件需要更新,那么只可能是版本更新,要么是ocx版本升級要么是dll文件版本升級,無論哪一種形式ocx的版本號均需要通過正常的發布流程發布,所以這兩種形式可視為一致。
此時需要升級CAB打包過程中INF文件中相應的文件區域中的版本號與有更新的文件的文件版本號保持一致,比如此時ocx和DeskAgent.dll有更新,此時新發布的版本中版本號分別分別更新為1.6.0.45和1.6.2.28,INF文件中相應區域應修改為:
[CCEA.ocx] file-win32-x86=thiscab clsid={6F82C754-6C31-43EA-9818-E95AD4E872FC} FileVersion=1,6,0,45 RegisterServer=yes DestDir=10 [DesktopAgent.dll] file-win32-x86=thiscab FileVersion=1,6,2,28 DestDir=10 |
重新打包簽名替換原本用來分發的舊CAB包,同時在html標簽中CAB的版本號要升級為與CAB文件中OCX文件的版本號一致。
以上是一種標准的升級方式有助於在每次升級過程中明確相應的版本關系而不至於在多次升級之后版本號的混亂,同時能夠保證簽名之后的CAB文件在安裝之后即可正常使用不再有下載安裝的步驟,但實際上只要升級了OCX的版本號並且將html里的版本號一並升級之后無論其它依賴的文件是否更新、版本號是否升級,所有文件均重新下載安裝注冊替換為新CAB文件中的文件,這點是需要強調注意的(至於html標簽怎么寫后面會有說明)。
5.2 只更新INI配置文件
目前沒有找到有效的方法在不更新OCX文件及其附屬dll的前提下自動更新,目前的建議的方法是將更換了新的ini配置文件后重新打包CAB並簽名,不更改INF文件的前提條件下更新html中標簽的版本,更新完之后所有坐席均保證做一次業務系統登錄以更新CAB文件,之后再將html標簽中的版本改回原先的版本號,此舉是保證坐席之后每次登錄均不再需要重新下載安裝即可直接使用,保證良好的適用性。
5.3 CAB加載的HTML實現
原先第三方業務系統使用OCX控件需要在業務系統的html實現如下代碼:
<OBJECT id="UsbossViewer" name="objocx" classid="clsid:6F82C754-6C31-43EA-9818-E95AD4E872FC" width="100%" height="250">
</OBJECT>
若要在OCX文件直接加載時初始化屬性,需要在OBJECT標簽之內初始化屬性,具體結構變為如下結構:
<OBJECT id="UsbossViewer" name="objocx" classid="clsid:6F82C754-6C31-43EA-9818-E95AD4E872FC" width="100%" height="250">
<PARAM NAME="XXXX" VALUE="XXXX"/></OBJECT>
下面講述第三方業務系統在html標簽中如何使用CAB文件,html標簽實例如下:
<OBJECT ID= "UsbossViewer " name="objocx" CLASSID= "CLSID:6F82C754-6C31-43EA-9818-E95AD4E872FC" CODEBASE= "CCEAOCX.CAB#version=1,6,0,44" width="100%" height="250"> </OBJECT>
此處"objocx"可任意命名,在之后使用控件的接口或者屬性則以objocx. 方法名或者objocx. 屬性即可,“CODEBASE=”是一個比較重要的key,其中CCEAOCX.CAB是CAB文件打包時的命名,而之后1,6,0,44則是此CAB的版本號,但是CAB本身是沒有版本號的,因此一般來說將此版本號設置得與CAB文件中ocx的版本號一致,這也是建議的一種方式,在更新CAB文件中有相當大的作用。
若要像OCX文件直接加載時初始化屬性,其方式是一樣的,同樣在OBJECT標簽之內初始化屬性:
<OBJECT ID= "UsbossViewer " name="objocx" CLASSID= "CLSID:6F82C754-6C31-43EA-9818-E95AD4E872FC" CODEBASE= "CCEAOCX.CAB#version=1,6,0,44" width="100%" height="250"><PARAM NAME="XXXX" VALUE="XXXX"/> </OBJECT>
5.4 使用URL的CAB部署方式
CAB文件的使用描述的CAB部署方式是必須在加載頁面的的本級目錄下部署CAB文件,若要指定路徑的話其格式應該是:
<OBJECT ID= "UsbossViewer " name="objocx" CLASSID= "CLSID:6F82C754-6C31-43EA-9818-E95AD4E872FC" CODEBASE= "http://10.130.40.220:9081/CAB/OCXold.CAB#version=1,6,0,44" width="100%" height="250"> </OBJECT>
其中http://10.130.40.220:9081/CAB/OCXold.CAB即為CAB放置的絕對路徑,http://10.130.40.220:9081/CAB/為測試環境的路徑。