ActiveX控件以前也叫做OLE控件,它是微軟IE支持的一種軟件組件或對象,可以將其插入到Web頁面中,實現在浏覽器端執行動態程序功能,以增強浏覽器端的動態處理能力。通常ActiveX控件都是用C++或VB語言開發,本文介紹另一種方式,在.NET Framework平台上,使用C#語言開發ActiveX控件。
雖然本文通篇都在講如何使用C#語言開發ActiveX控件,但我並不極力推薦使用這種技術,因為該技術存在明顯的局限,即需要浏覽器端安裝.NET Framework(版本取決於開發ActiveX控件使用的.NET Framework版本),該局限對於挑剔的互聯網用戶,幾乎是不可接受的。所以,我建議以下幾條均滿足時,方可考慮使用該技術:
另外,我建議如果不是因為控件的依賴庫基於更高版本的.NET Framework,或需要更高版本的.NET Framework提供的擴展功能(如需要WCF等),盡量在.NET Framework 2.0上開發ActiveX控件,因為.NET Framework 2.0只有20M,相比300M的.NET Framework 3.5和40M的.NET Framework 4.0都要小很多,對客戶端操作系統的要求也要低很多,並且隨著Windows版本的不斷升級換代,Windows Vista以後的版本已經內置了.NET Framework 2.0。等到Windows XP系統壽終正寢之時,也將迎來該技術的春天。所以,別被我上面的建議夯退了,掌握該技術其實還是蠻有實用價值的,畢竟,C#高效的開發效率很有吸引力。
本文接下來將使用C#語言開發一個ActiveX控件,實現對浏覽器端的MAC地址遍歷功能;另外,提供一個在Web靜態頁面中調用該控件的測試實例。本實例的開發環境為Visual Studio 2010旗艦版(SP1),目標框架為.NET Framework 2.0;浏覽器端測試環境為Windows 7旗艦版,IE8。
使用C#進行ActiveX控件開發過程其實很簡單。首先,在解決方案中添加一個類庫項目,目標框架使用.NET Framework 2.0,如圖1所示:
圖1創建ActiveX控件類庫
此處有一個關鍵操作,需要設置類庫項目屬性->程序集信息->使程序集COM可見,如圖2所示:
圖2設置ActiveX控件類庫程序集COM可見
ActiveX類庫的內容大致包括兩部分,IObjectSafety接口和實現該接口的控件類。考慮所有控件類都要實現IObjectSafety接口,可以將該接口的實現抽象為一個控件基類。
一、IObjectSafety接口
為了讓ActiveX控件獲得客戶端的信任,控件類還需要實現一個名為“IObjectSafety”的接口。先創建該接口(注意,不能修改該接口的GUID值),接口內容如下:
[ComImport, Guid( GetInterfaceSafetyOptions( Guid riid, [MarshalAs(UnmanagedType.U4)] pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] SetInterfaceSafetyOptions( Guid riid, [MarshalAs(UnmanagedType.U4)] dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] }
二、ActiveXControl控件基類
IObjectSafety 成員 _IID_IDispatch = _IID_IDispatchEx = _IID_IPersistStorage = _IID_IPersistStream = _IID_IPersistPropertyBag = INTERFACESAFE_FOR_UNTRUSTED_CALLER = INTERFACESAFE_FOR_UNTRUSTED_DATA = S_OK = E_FAIL = (() E_NOINTERFACE = (() _fSafeForScripting = _fSafeForInitializing = GetInterfaceSafetyOptions( Guid riid, pdwSupportedOptions, Rslt = strGUID = riid.ToString( pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | Rslt = pdwEnabledOptions = (_fSafeForScripting == pdwEnabledOptions = Rslt = pdwEnabledOptions = (_fSafeForInitializing == pdwEnabledOptions = Rslt = SetInterfaceSafetyOptions( Guid riid, dwOptionSetMask, Rslt = strGUID = riid.ToString( (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == Rslt = (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == Rslt = Rslt = }
三、MacActiveX控件類
[Guid( mc = ManagementClass( mos = sb = (ManagementObject mo macAddress = mo[ (macAddress != }
注意,第一行指定的Guid值即為該ActiveX控件的唯一標識,請保證其唯一性。Guid的生成有多種方法,你可以在系統目錄的Program Files目錄搜索一個名為guidgen.exe的工具,用該工具產生;也可以寫一段測試代碼,調用Guid.NewGuid()方法產生;有的Visual Studio版本也提供了快捷方式,在“工具->生成GUID”菜單下。另外,訪問MAC需要添加對System.Management系統組件的引用。
到此,控件類庫的開發工作就做完了,整個實現過程確實很簡單。
C#開發的ActiveX控件類庫不像OCX那樣可以直接通過regsvr32.exe注冊(實際上,微軟提供了替工具regasm.exe,但由於這種方式要不能實現自動升級,所以本文就不介紹了),要使控件類庫運行於浏覽器端,可以采取兩種方式,一種是將控件類庫打包為MSI安裝包,然後直接在浏覽器端安裝;另一種是將MSI再封裝為一個CAB包,這個CAB包就是一個ActiveX控件了,可以將它隨應用程序一並發布,浏覽器端訪問包含有該控件的頁面時,就會自動提示安裝了。接下來就後一種發布方式進行詳細講解。
一、安裝項目
在解決方案中添加一個安裝項目,如圖3所示:
圖3添加安裝項目
右鍵點擊新添加的安裝項目,依次選擇“添加->項目輸出”菜單,打開添加項目輸出組對話框,並選擇ActiveX控件類庫“CSharpActiveX”作為主輸出,如圖4所示:
圖4添加項目輸出
雙擊安裝項目檢測到的依賴項“Microsoft .NET Framework”,打開安裝項目的啟動條件界面,選中“.NET Framework”項,如圖5所示:
圖5安裝項目啟動條件
按F4快捷鍵,打開屬性窗口,設置.NET Framework項的Version為“.NET Framework 2.0”,如圖6所示:
圖6設置安裝項目的依賴框架
下面這步很關鍵,選中“主輸出來自CSharpActiveX(活動)”項,如圖7所示:
圖7主輸出內容項
設置主輸出項內容的Register屬性值為vsdrpCOM,如圖8所示:
圖8設置主輸出項屬性
二、制作CAB包
Visual Studio 2010提供了CAB項目模板,但非常遺憾,無論我怎麼設置,其生成的CAB安裝包都不能在終端成功安裝,最終只能放棄,轉而選擇了makecab.exe工具。源碼提供了該打包工具,位於CAB目錄下,共包含makecab.exe、cab.ddf、installer.inf和makecab.bat四個文件,其中cab.ddf和installer.inf文件需要簡單說明下。
cab.ddf文件定義了CAB文件的打包行為,內容包括打包參數,打包內容項以及輸出文件等。需要指出的是,使用C#開發的ActiveX控件CAB包中需要包含MSI文件和installer.inf安裝文件兩部分。cab.ddf文件內容如下:
====6144="."==7=21="CSharpActiveX.CAB" "installer.inf" "CSharpActiveX.msi"
installer.inf文件定義了CAB文件的安裝行為,作為控件的一部分打入CAB包中,其內容如下:
=== "$CHICAGO$"=2.0
makecab.bat文件是調用makecab.exe進行打包的批處理文件,內容如下:
makecab.exe /f "cab.ddf"
當生成安裝項目後,將CSharpActiveX.msi文件拷貝到CAB目錄下,就可以雙擊makecab.exe文件進行打包了,執行完成後會輸出CSharpActiveX.CAB文件,這就是所謂的ActiveX控件了。
三、簽名
IE采用了AuthentiCode代碼簽名技術,對浏覽器端安裝ActiveX控件行為進行了控制。上面生成的ActiveX控件如果想在浏覽器端成功安裝,需要對浏覽器進行設置,具體操作參見部署章節。
讓所有用戶都對IE進行設置,顯得不太友好,為此,我們可以考慮使用AuthentiCode技術對ActiveX控件進行簽名。Visual Studio 2010附帶的signtool.exe(以前版本的VS提供的是另一個工具signcode.exe)代碼簽名工具可以完成該工作(注意,並非一定要用微軟提供的工具進行簽名,只要按照AuthentiCode技術標准,使用 PKCS#7標准定義的數據結構生成待簽名文件的數字簽名,並加入到待簽名文件的PE結構中即可)。但需要先准備一個PKCS#12(證書及私鑰)文件(.pfx),注意,該證書的增強型密鑰用法須包含代碼簽名這項,如圖9所示:
圖9代碼簽名證書
本文源碼提供了一份測試PKCS#12文件Apollo.pfx,PIN碼為11111111。在Visual Studio命令提示(2010)中,進入源碼的CAB目錄,輸入如下命令即可對ActiveX控件進行簽名操作了:
signtool sign –f Apollo.pfx –p 11111111 CSharpActiveX.CAB
圖10對比了簽名前後的ActiveX控件文件屬性,可以看出,簽名後的ActiveX控件屬性中已經多了一項數字簽名,表示該文件已經過簽名。
圖10簽名前後的ActiveX控件屬性對比
出於方便考慮,本文源碼的CAB目錄下提供了一份signtool.exe工具的拷貝,這樣就可以將簽名命令加入makecab.bat文件中,修改後的makecab.bat我將其命名為makecabsigned.bat,內容如下:
makecab.exe /f "cab.ddf"11111111 CSharpActiveX.CAB
ActiveX控件用於HTML靜態頁面,執行於IE浏覽器端。需要以<object>標簽的形式引入頁面文件,然後使用Javascript語言調用它。測試代碼如下:
CSharpActiveX測試
注意,<object>標簽的classid屬性值即為MacActiveX類的Guid特性值。
ActiveX控件在IE浏覽器端的部署會因ActiveX控件是否簽名而有所區別。下面就以此分類進行說明。當然,首先需要將test.htm和CSharpActiveX.CAB文件部署到服務器上,假設部署後的訪問地址為http://192.168.1.1/test.htm。
一、部署未簽名的ActiveX控件
未簽名的ActiveX控件不受浏覽器端信任,默認是不被允許安裝的。需要先將站點添加為可信站點,具體步驟為:依次打開IE“工具->Internet選項”,在“安全”選項卡中,選中“可信站點”,如圖11所示:
圖11 Internet安全選項
點擊“站點”按鈕,打開可信站點管理對話框,將服務器站點添加到可信站點列表中,如圖12所示:
圖12可信站點對話框
回到“Internet選項”對話框,點擊“自定義級別”選項卡,打開可信站點的安全設置對話框,如圖13所示:
圖13可信站點安全設置對話框
確認“對未標記為可安全執行腳本的ActiveX控件初始化並執行腳本”項設置為“啟用”,“下載未簽名的ActiveX控件”項設置為“提示”。
IE設置完成後,訪問http://192.168.1.1/test.htm測試頁面(注意,Windows 7需要“以管理員身份運行”IE方可成功安裝ActiveX控件),IE便會提示加載ActiveX控件,如圖14所示:
圖14首次訪問提示加載ActiveX控件
點擊“為此計算機上的所有用戶安裝此加載項”,IE將彈出安全警告,確認是否要安裝該ActiveX控件,如圖15所示:
圖15 ActiveX控件安裝安全警告
點擊“安裝”按鈕,確認安裝該ActiveX控件,待IE狀態欄進度條完成,說明控件已安裝完成,可以通過查看“卸載或更改程序”項來確認是否安裝成功,如圖16所示:
圖16確認ActiveX控件成功安裝
我們可以從ActiveX控件安裝過程看出,浏覽器端其實是以靜默安裝的方式完成對CAB包中的MSI安裝文件的安裝(有點拗口J)。安裝完成後,頁面成功調用ActiveX控件,彈出接口調用結果(注意Windows 7需要重啟IE,且不能用“以管理員身份運行”方式啟動,否則會再次提示安裝ActiveX控件,但其實控件已經成功安裝了,這個問題很奇怪),效果如圖17所示:
圖17成功調用ActiveX控件接口
二、部署已簽名的ActiveX控件
因為IE默認允許安裝並運行收信任的已簽名ActiveX控件,所以通過對ActiveX控件簽名,可以有效簡化浏覽器端的配置工作。你僅需要安裝簽名所用的證書及其證書鏈文件(本文源碼提供的簽名文件所含證書是自簽名證書,所以它的證書鏈就只是它自己)。打開源碼CAB目錄下的Apollo.cer(與Apollo.pfx文件對應的數字證書文件)代碼簽名證書文件,如圖18所示:
圖18簽名證書文件
點擊“安裝證書”按鈕,將該證書安裝到“受信任的根證書頒發機構”,如圖19所示:
圖19安裝代碼簽名證書
打開IE的“工具->Internet選項”對話框,選擇“內容”選項卡,點擊“證書”按鈕,打開IE證書對話框,確認在“受信任的根證書頒發機構”選項卡中包含剛才導入的代碼簽名證書,如圖20所示:
圖20成功導入代碼簽名證書
此時,再訪問測試頁面http://192.168.1.1/test.htm,IE就會提示安裝ActiveX控件了,而不再需要將站點添加到可信站點並設置IE選項了。
但是,如果用戶不能接受初次安裝需要導入代碼簽名證書及其證書鏈的方式,怎麼辦呢?從圖20可以看到,Windows其實默認內置了一些權威的CA機構證書,可以向這些機構申請一份代碼簽名證書及私鑰文件來對ActiveX控件簽名,這樣就可以避免該問題了。但是,向權威的CA機構申請證書是需要付費的,所以需要權衡成本和易用性後,再做出選擇。
要使C#編寫的ActiveX控件支持自動升級,需要做四件事情,即升級ActiveX控件庫版本、升級安裝項目版本、設置安裝項目注冊表項版本和升級網頁<object>版本。
一、升級ActiveX控件版本
打開ActiveX控件項目的“程序集信息”對話框,升級程序集版本和文件版本,如圖21所示:
圖21升級ActiveX控件版本
二、升級安裝項目版本
選中安裝項目,按F4快捷鍵打開安裝項目的屬性窗口,升級安裝項目的版本,如圖22所示:
圖22升級安裝項目版本
注意,此處還有一項關鍵工作要做,就是設置RemovePreviousVersions屬性值為True,這樣就會在升級時先自動卸載之前版本的控件。
三、設置安裝項目注冊表項版本
浏覽器端檢測ActiveX控件是否需要升級,是通過比對<object>標簽的codebase屬性值和本地HKEY_CLASSES_ROOT/CLSID/{GUID}/InstalledVersion鍵值是否相等來判斷的。所以,如果要實現自動更新,需要手動添加該注冊表項,並在每次升級控件時,相應更改該項鍵值。
右鍵點擊安裝項目,依次選擇“視圖->注冊表”菜單,打開安裝項目的注冊表編輯界面,並在HKEY_CLASSES_ROOT節點下,建立CLSID/{GUID}/InstalledVersion注冊表鍵路徑,如圖23所示:
圖23創建注冊表鍵路徑
右鍵點擊InstalledVersion鍵節點,選擇“新建->字符串值”菜單,新建一個名稱為空(空名稱會顯示為“(默認值)”),值為當前控件版本號的鍵值,如圖24所示:
圖24添加InstalledVersion默認鍵值
該步驟有幾個地方需要特別說明。首先,{GUID}指的是ActiveX控件類的GUID,對應本文MacActiveX類指定的GUID,且該項需要包括左右花括號;其次,如果該安裝項目用於發布多個ActiveX控件(類),需要創建多個{GUID}/InstalledVersion路徑;最後,InstalledVersion的默認鍵值的主次版本號間是用“,”分隔,而不是“.”,後續升級時,需要同步升級該鍵值版本號。
四、升級網頁<object>版本
最後,需要升級網頁中的ActiveX對象引用版本號,如下用下劃線標識部分:
"
重新生成安裝程序,打CAB包,將升級的頁面及ActiveX控件(CAB包)更新到服務器。此時,浏覽器端重新訪問時,就會提示/自動升級ActiveX控件了。
本文是《使用C#開發ActiveX控件》一文的升級版本,從ActiveX控件的開發、發布、應用、部署和升級整個生命周期,系統地介紹了使用C#開發ActiveX控件技術的方方面面,對整個過程中可能遇到的一些技術難點進行了逐一講解,並對其中涉及的一些知識進行了簡單介紹。希望本文能夠解答自上一篇文章發布以來眾多網友提出的種種問題,幫助大家成功掌握這門技術。
附件下載:示例源碼+本文PDF版本