[.NET] 使用 .NET Framework 開發 ActiveX Control (1)–背景知識
ActiveX的歷史與技術基礎
只要是有八年以上程式開發經驗的開發人員,多多少少都會聽過ActiveX控制項(Control)這個東西,這個是只存活在Internet Explorer上的可程式化元件(Programmable Component),它可以允許在瀏覽器上執行低階層次的系統呼叫與存取工作,在Web應用程式平台發展的初期,當時網景公司(Netscape)的Navigator瀏覽器正和Internet Explorer打得火熱的時候,微軟為了要能對抗在Navigator內的Plug-in技術,在Internet Explorer內也加入了允許開發人員在網頁內加入具有動態效果的使用者介面元件的技術,ActiveX技術就這樣誕生了,在第一輪的瀏覽器大戰由微軟勝出後,許多的ActiveX控制項也如雨後春筍般的冒出來,也因為ActiveX控制項是目前唯一可以在IE瀏覽器上繞過瀏覽器沙箱(Browser Sandbox)而直接與系統層次溝通的元件,所以現在仍廣為金融界所應用(開發網路ATM),國內除了金融界以外,政府單位也是大客戶(應用自然人憑證驗證機制)。
ActiveX技術是1996年出現的,它的核心是COM(Component Object Model),當時COM和OLE是兩個不同的技術,而微軟為了要讓OLE可以在Internet上使用,特別在COM以及OLE中加入一些特別的介面,讓應用程式可以透過一個簡單的介面來存取在元件內的所有功能,以往要開發一個COM元件,必須要實作IUnknown介面以及應用程式自己的介面,並將介面註冊到COM Registry Databases(HKEY_CLASS_ROOT)內,而用戶端程式使用COM Client Library先自元件取得IUnknown介面以及呼叫由元件所實作的QueryInterface()方法取得元件自己的介面後,才可以呼叫自己的介面,而且沒有可以間接呼叫的方式,這種模式不利於在Internet上使用,而且當時Visual Basic 4.0也提供了OCX的控制項(OLE Control)開發能力,微軟也想要讓VB可以開發COM元件,因此微軟在COM介面中加入了一個新的介面-IDispatch介面,並且由COM Client Library直接支援,大家最常用的Office應用程式的核心部份就是利用IDispatch來實作各類物件,除了可以在應用程式間使用OLE來分享資料外,還可以讓VB或其他程式語言透過COM介面來存取Office的物件模型,這樣的作法讓COM獲得了巨大的支持,除了VB可開發COM元件外,其他的程式語言也可以遵循IDispatch介面實作來支援COM元件的開發。這樣的技術後來整合了OLE的部份技術後,稱為COM Automation(COM自動化)。
NOTE
在ActiveX推出的時候,微軟為了要支援開發ActiveX Control,另外提供了一個小工具:ActiveX Control Pad,可用來測試開發完成的控制項。您可以到此懷舊一下ActiveX Control Pad:http://msdn.microsoft.com/en-us/library/ms975966.aspx
後來在Visual Basic 6.0推出(1998年)時,微軟的各式Internet應用程式開發成員皆已到位,像ASP/ADO這類的基礎元件,以及Visual Studio 6.0套裝開發工具等,讓微軟的Internet開發技術紅極一時,當時作為核心技術的ActiveX也被提升到市場行銷上,許多COM/OLE技術都被改為ActiveX技術,像ActiveX Document(原本是OLE Document)、ActiveX DLL(原本是COM DLL)、ActiveX EXE(原本是COM EXE)等。後來到了Microsoft .NET時代,ActiveX控制項的發展也開始走下坡,同一時期的Flash則是開始竄起,第二次瀏覽器大戰更讓IE的市佔率開始下降,相對的ActiveX控制項也開始式微-因為它只有IE這個舞台。不過它可以存取硬體,且可由簡單的程式語言開發的優點仍然受到開發人員歡迎,所以只要特殊的應用環境不消失,ActiveX控制項也不會消失(因為在IE上的Flash本身也是ActiveX控制項)。
.NET時代的ActiveX控制項
在微軟宣布全力支援Microsoft .NET平台的發展與Visual Basic經過本質上的變化(VBàVB.NET)後,ActiveX控制項的開發就停頓在C++(MFC/ATL)、VB 6.0以及Delphi等開發工具,且COM本身也已經趨於穩定,只有很少量的基礎變化,所以開發ActiveX控制項的方法也沒有再繼續進化,目前開發ActiveX控制項的作法其實和八年前沒什麼兩樣,欽定的開發工具仍然是C++以及VB 6.0,反觀.NET Framework本身因為龐大的.NET Framework Class Libraries的關係,無法像C++/VB 6.0一樣可以產生輕薄短小的封裝檔,且在當時COM Interoperability仍然不夠成熟的情況下,原則上微軟並不建議使用.NET Framework來開發ActiveX控制項的(但鼓勵在.NET應用程式內使用ActiveX控制項,以保有原本的技術投資),不過近幾年來CPU以及運算能力的強化,COM Interoperability的效能損耗逐漸降低,只要能夠避免將.NET Framework一起封裝的情況下,.NET Framework也可以用來開發ActiveX控制項。
要使用.NET Framework來開發ActiveX控制項,則必須要先了解.NET Framework如何將自己的資訊開放給COM,既然都要讓COM來存取了,那麼當然也要將自己的型別資訊開放給COM知道。其實要開放.NET Framework物件給COM這件事不難,只要在專案的內容中,在『建置』頁籤中,將『註冊COM Interop』核取起來,這樣Visual Studio會在建置時另外產生一個型別函式庫(Type Library),並且使用Regasm.exe將組件註冊到COM Registry Database中,讓COM用戶端應用程式可以看到這個COM元件。
接著,要設定COM用戶端程式可以看到這個組件的多少物件,若是只要看到自己設定的物件類別時,則在物件類別上設定ComVisibleAttribute特徵項(attribute),若是要讓COM用戶端看到組件內的所有公開類別時,就要設定讓此組件為COM Visible,方法是打開專案內的Assembly.cs程式,並將下列指令的false改為true:
[C#]
[assembly: ComVisible(true)]
然後要為類別設定COM Visible,以及設定一個自己使用的GUID值,這個值會在登錄介面時寫入COM Registry Database內,而COM用戶端程式就依據這個值和由編譯器自動產生的Programmable ID(ProgID)進行對應,以正確呼叫你的組件。
[Guid("C90E96C1-8534-4243-9530-960D9AF982CB")]
[ComVisible(true)]
public class MyDateControl
設定完後編譯專案,即可將組件開放給COM用戶端。
[.NET] 使用 .NET Framework 開發 ActiveX Control (2) - 使用 C# 開發 ActiveX 控制項
本文將會開始以 C# 實作控制項,讓你可以有開發控制項的經驗。
準備工作
在我們開始用開發ActiveX控制項前,必須要先做一些準備工作,以便在開發完成時順利測試控制項,最重要的是Internet Explorer的安全性設定,在開發時期基本上我們不會進行元件的安全設定(例如簽章),為了要讓測試工作可以順利,我們要對IE的安全性做一些設定。
首先,我們要先把網站加入受信任的網站,我們可以由控制項的網際網路選項(或是Internet選項)中,在『安全性』頁籤中,選取『信任的網站』,然後按『網站』按鈕:
將本機的網址(本文為http://localhost),加入信任網站中:
加入完成後,一樣在『安全性』頁籤的『信任的網站』,按下『自訂等級』按鈕,會顯示安全等級的細部設定視窗:
請依下表設定安全層級:
選項 | 值 |
下載未簽署的ActiveX控制項 | 提示(Prompt) |
允許程式碼片段 | 提示(Prompt) |
啟始不標示為安全的ActiveX控制項 | 提示(Prompt) |
設定好以後,我們就可以來開始開發我們的控制項了。
使用C#開發ActiveX控制項-基本功能
本文將使用C#以及Visual Studio 2008作為開發環境,但這個方法可以在Visual Studio 2005以後的開發工具使用(但我只試過VS2008)。同時,我不會在這裡說明細部的操作程序,因此我假定你對Visual Studio的操作已經有基本的瞭解。
首先,先建立一個空白的方案:
然後,在方案中新增一個C#的類別庫專案(我的專案命名是MyControl),這個專案會產生DLL檔案,也是作為控制項的專案之一。您也可以用Windows Forms控制項專案來做,但因為我們不一定會需要使用者介面,因此由類別庫專案來開發會比較簡單。
當專案產生後,請將專案內容打開,並在『建置』頁籤中,將『註冊COM Interop』核取起來後存檔。然後把預設的Class1.cs檔案更名為MyDateControl.cs(若Visual Studio提示更改類別名稱,請接受它),接著將它打開,加入下列程式碼:
using System.Runtime.InteropServices;
namespace MyControl
{
[Guid("C90E96C1-8534-4243-9530-960D9AF982CB")]
[ComVisible(true)]
public class MyDateControl
{
public DateTime Today { get { return DateTime.Today; } }
public string GetTodayDateString() {
return DateTime.Today.ToString("yyyy/MM/dd HH:mm:ss");
}
}
}
這段程式碼會把MyDateControl類別登錄到COM Registry Database中,設定它的GUID,並且開放一個屬性與方法。加入完成後請建置它,此時組件會被登錄,要檢查它是否被登錄,你可以開啟Visual Studio 2008命令提示字元:
並輸入oleview指令:
此時會出現OLE View應用程式視窗,請由左邊展開Type Libraries,你可以在節點中找到MyControl這個節點,表示組件已經登錄到COM Registry Database內:
現在,我們再於方案中新增一個ASP.NET網站或應用程式專案(作法我就不贅述),或是打開一個既有的Web應用程式專案,然後在根目錄中加入一個新的HTML網頁,並加入下列HTML碼:
<html>
<head>
<title></title>
<script language="javascript" type="text/javascript">
function displayDateFromProperty() {
alert(document.getElementById("myControl").Today);
}
function displayDate() {
alert(document.getElementById("myControl").GetTodayDateString());
}
</script>
</head>
<body>
<input type="button" value="Display Property" οnclick="displayDateFromProperty()" /><input type="button" value="Invoke Method" οnclick="displayDate()" /><br />
<object id="myControl" classid="clsid:C90E96C1-8534-4243-9530-960D9AF982CB" width="0px" height="0px" />
</body>
</html>
此段HTML碼是一個簡單的網頁,並在網頁內放了一個ActiveX控制項,這個控制項的CLSID要和類別所設定的GUID一致,否則IE會無法載入此控制項。在這個網頁中內含了兩個JavaScript指令碼,它會呼叫在控制項內開放的屬性和方法。
NOTE
classid=”clsid:{GUID}”內的GUID值必須要和類別的GUID一致。
現在,我們可以來測試這個控制項了,請用瀏覽器瀏覽這個網頁,你應該會看到這個畫面:
當你按下Display Property和Invoke Method時,應該都會看到顯示今天日期的訊息對話盒,但第一次按時,應該會看到這個訊息:
這表示你目前的控制項是不安全的,要按下『是』,才可以順利執行:
NOTE
我們會在後面告訴你怎麼讓這個交互作用警告的對話盒不再出現。
使用C#開發ActiveX控制項-產生使用者介面
在完成了上面的控制項後,你應該會對用C#開發ActiveX控制項有一點感覺了,我們再來寫一個具有使用者介面的控制項,基本上作法差不多,但這次要新增的是Windows Forms使用者控制項(我的控制項命名為MyDateControlUI)。
新增完成時,Visual Studio會開啟Designer視窗,請在上面放兩個按鈕,如同前一個範例一樣,其中一個是顯示今日的日期(cmdDisplayToday),但另一個會讀取本機上的登錄資料庫(cmdGetOSVer),以取得目前的作業系統資訊:
畫面設定完成後,請開啟控制項的程式碼,加入對COM Interoperability以及Microsoft.Win32的命名空間參考:
using System.Runtime.InteropServices;
using Microsoft.Win32;
請為按鈕填入下列程式碼(分別是cmdDisplayToday按鈕以及cmdGetOSVer按鈕的Click事件常式):
private void cmdDisplayToday_Click(object sender, EventArgs e)
{
MessageBox.Show(DateTime.Today.ToString("yyyy/MM/dd"), "Today");
}
private void cmdGetOSVer_Click(object sender, EventArgs e)
{
RegistryKey key = Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
MessageBox.Show(key.GetValue("BuildLabEx").ToString(), "OS Build Ver");
key = null;
}
然後依照上一步的程序,在類別上加入ComVisible和GUID的設定:
namespace MyControl
{
[Guid("1C267377-9034-4919-A2F8-C1D8961DDDB8")]
[ComVisible(true)]
public partial class MyDateControlUI : UserControl
{
public MyDateControlUI()
{
InitializeComponent();
}
...
}
}
接著,我們修改上一程序所用的HTML網頁,先將原本的<body></body>內的指令移除或註解起來,再加入下面的指令(CLSID值一樣要和類別相同),這裡用的雖然也是<object>標籤,但有設定寬度和高度,以配合控制項。
<object id="myControl" classid="clsid:1C267377-9034-4919-A2F8-C1D8961DDDB8" width="325px" height="97px" />
現在,我們再以瀏覽器來瀏覽此網頁,你看到的應該會是這樣:
同時,按下Display Today會得到今天的日期,而按下Get OS Version,會出現作業系統的Build版本資訊,此版本資訊是來自於登錄資料庫,因此可證明ActiveX控制項具有與作業系統互動的能力(Flash和Silverlight in-browser application就沒辦法做到):
宣告控制項是安全的
我們一開始設計的MyControl控制項在執行時都會出現潛在安全性問題的提示訊息,這是因為Internet Explorer內建的安全性機制使然,就算把提示的設定改為啟用(Enabled),仍然會出現這個訊息,要將此訊息關閉,你必須要在你的控制項實作一個特別的介面,向IE宣告你的控制項與JavaScript互動時是安全的。
NOTE
只要你的控制項會和JavaScript互動,就必須要實作這個介面。
這個介面是IObjectSafety,它是COM原生函式庫內的一個介面,當IE在載入你的控制項時,會在控制項內搜尋是否有這個介面的存在(即控制項是否有實作此介面),如果沒有找到的話,就會顯示潛在安全性問題的訊息,因此我們需要實作這個介面。請在專案內加入一個類別檔案,命名為IObjectSafety.cs檔,並將下列程式加入:
/// <summary>
/// 針對 ActiveX Control 的 IObjectSafety 介面引用。
/// </summary>
[ComImport]
[Guid("CB5BDC81-93C1-11cF-8F20-00805F2CD064")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IObjectSafety
{
/// <summary>
/// 取得物件的安全選項。
/// </summary>
/// <param name="riid">介面代碼。</param>
/// <param name="pdwSupportedOptions">支援的安全性選項。</param>
/// <param name="pdwEnabledOptions">啟用選項。</param>
void GetInterfaceSafetyOptions(int riid, out int pdwSupportedOptions, out int pdwEnabledOptions);
/// <summary>
/// 設定物件的安全選項。
/// </summary>
/// <param name="riid">介面代碼。</param>
/// <param name="pdwSupportedOptions">支援的安全性選項。</param>
/// <param name="pdwEnabledOptions">啟用選項。</param>
void SetInterfaceSafetyOptions(int riid, int pdwSupportedOptions, int pdwEnabledOptions);
}
/// <summary>
/// IObjectSafety 使用的列舉值。
/// </summary>
public class IObjectSafetyEnums
{
/// <summary>
/// 對未受信任的呼叫者宣布此介面為安全。
/// </summary>
public const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x0000001;
/// <summary>
/// 對未受信任的資料宣布此介面為安全。
/// </summary>
public const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x0000002;
}
這個介面有兩個方法:
方法 | 功能 |
GetInterfaceSafetyOptions | 由COM用戶端取得此元件的安全選項。 |
SetInterfaceSafetyOptions | 由COM用戶端設定此元件的安全選項。 |
如果控制項內沒有特別要針對不同的介面做設定,那麼我們可以直接以下列程式實作:
public void GetInterfaceSafetyOptions(int riid, out int pdwSupportedOptions, out int pdwEnabledOptions)
{
pdwSupportedOptions = IObjectSafetyEnums.INTERFACESAFE_FOR_UNTRUSTED_CALLER | IObjectSafetyEnums.INTERFACESAFE_FOR_UNTRUSTED_DATA;
pdwEnabledOptions = IObjectSafetyEnums.INTERFACESAFE_FOR_UNTRUSTED_CALLER | IObjectSafetyEnums.INTERFACESAFE_FOR_UNTRUSTED_DATA;
}
public void SetInterfaceSafetyOptions(int riid, int pdwSupportedOptions, int pdwEnabledOptions)
{
}
如同上面的說明,請在MyControl程式中指示要實作IObjectSafety,並且加入上面的實作,完成的類別程式碼應該會像這樣:
[Guid("C90E96C1-8534-4243-9530-960D9AF982CB")]
[ComVisible(true)]
public class MyDateControl : IObjectSafety
{
public DateTime Today { get { return DateTime.Today; } }
public string GetTodayDateString() { return DateTime.Today.ToString("yyyy/MM/dd HH:mm:ss"); }
public void GetInterfaceSafetyOptions(int riid, out int pdwSupportedOptions, out int pdwEnabledOptions)
{
pdwSupportedOptions = IObjectSafetyEnums.INTERFACESAFE_FOR_UNTRUSTED_CALLER | IObjectSafetyEnums.INTERFACESAFE_FOR_UNTRUSTED_DATA;
pdwEnabledOptions = IObjectSafetyEnums.INTERFACESAFE_FOR_UNTRUSTED_CALLER | IObjectSafetyEnums.INTERFACESAFE_FOR_UNTRUSTED_DATA;
}
public void SetInterfaceSafetyOptions(int riid, int pdwSupportedOptions, int pdwEnabledOptions)
{
}
}
完成後請編譯此組件,然後修改HTML網頁使用MyControl控制項,然後以瀏覽器瀏覽該網頁,並按下網頁中的按鈕,你會發現潛在安全性的訊息不再出現。
[.NET] 使用 .NET Framework 開發 ActiveX Control (3) - 封裝,簽章與部署
本文將會把最後的程序給完成,當完成這個程序後,你就可以把你的控制項部署出去了。
封裝,簽章與部署
在你精心製作完了一個ActiveX控制項後,一定迫不及待的想要部署出去給大家用(例如自然人憑證的元件),但是ActiveX控制項不像我們一般在開發的.NET Framework應用程式,做個安裝檔就可以丟出去的,而是要走幾個步驟:
1. 建立一個安裝程式,將元件封裝到MSI檔內。
2. 設定安裝資訊檔(INF)。
3. 將元件封裝到CAB檔案內。
4. 使用程式碼簽章,簽署元件。
5. 設定網頁引用的codebase路徑,讓用戶端可以自動下載安裝。
首先,我們先為控制項專案建立一個安裝程式,我的安裝專案命名為MyControlInstaller:
建立完成後,請將控制項專案的主要輸出加入安裝專案中,此時安裝專案會將.NET Framework以及控制項的主要檔案加入封裝內,請檢查主要輸出的Register屬性設定是否為vsdrpCOM,這會讓安裝程式在安裝時將組件登錄到用戶端電腦的COM Registry Database內。
檢查完後,請建置這個安裝檔,以產生setup.exe以及MyControlInstaller.msi檔案。
NOTE
如果你看到這個訊息:
無需理會,直接關閉即可。
建置完成後,我們就得到了setup.exe以及MyControlInstaller.msi檔案,接著我們要編寫一個INF資訊檔案,以讓IE在下載CAB解壓縮後,可以得到必要的安裝指令。INF是一個類似以前INI格式的資料檔(可用記事本編輯),它的長相類似於下列指令:
[version]
signature="$CHICAGO$"
AdvancedINF=2.0
[Add.Code]
MyControlInstaller.msi=MyControlInstaller.msi
setup.exe=setup.exe
[MyControlInstaller.msi]
file-win32-x86=thiscab
clsid={C90E96C1-8534-4243-9530-960D9AF982CB}
hook=hook1
[setup.exe]
file-win32-x86=thiscab
[Setup Hooks]
hook1=hook1
[hook1]
run=msiexec.exe /i "%EXTRACT_DIR%\MyControlInstaller.msi" /qn
這個檔案最重要的有幾個地方:
1. [version]區段是給IE來識別,只要IE發現這個區段,就會自動解析這個INF檔案。其中的AdvancedINF=2.0是表示要IE對每個部份依序解析。
2. [Add.Code]區段會提示要將CAB中的哪些檔案加入暫存區,如果封裝中有其他檔案要加入的話,就必須要在這個區段中指明,但我們建議直接將要安裝的檔案全部加入安裝專案即可,讓這個區段只需登記安裝程式所要的檔案即可。
3. [MyControlInstaller.msi]以及[setup.exe]是針對檔案所設定,必須要有一個安裝的執行檔會對應到網頁中的GUID,以上例而言,MyControlInstaller.msi會對應到元件的GUID,IE如果在檔案的設定中發現元件的GUID時,就會讀取這個檔案的其他設定,像是要啟動的安裝程式,或是登錄此檔案(RegisterServer=yes)。
4. [Setup Hook]是指示IE要由什麼指令來啟動安裝程式。本例是[hook1]自訂區段。
5. [hook1]是自訂區段,它會指示IE執行run所設定的指令。
NOTE
你的控制項要視你的控制項需求來編寫這個INF,本例的INF只保證可以安裝此控制項。
有了INF檔案後,接下來我們要將它封裝到CAB檔案,以允許IE自動下載安裝,但很不幸的是,Visual Studio內建的封包專案所產生的CAB檔無法讓IE自動啟動安裝程式,所以我們只能靠以前的Cabinet SDK來做。
NOTE
然而微軟的下載中心已不再提供Cabinet SDK,因此只能由外面的網站來找,像是這裡:
http://www.pixelsplasher.com/_downloads/software/Microsoft-Cabinet-SDK/cabsdk.exe
請將Cabinet SDK下載並解壓縮,會得到SDK的必要資源,其中的cabarc.exe是我們需要的壓縮程式,透過它將setup.exe, MyControlInstaller.msi以及Install.inf(元件的INF檔)封裝成CAB檔,它的指令是:
cabarc n [CAB File Name] [Add File1] [Add File2] [Add File3] …
其執行結果如下圖:
現在,我們已經擁有了一個MyControl.cab檔案,此時,我們就可以將它複製到網站專案中,然後在<object>中加入這個CAB檔案的codebase路徑,如下列指令:
<object id="myControl" classid="clsid:C90E96C1-8534-4243-9530-960D9AF982CB" codebase="MyControl.cab" width="0px" height="0px" />
現在找一台未安裝此元件的電腦來瀏覽此網頁(不可以使用開發電腦,因為這樣無法進行部署測試),理論上應該可以下載控制項,但是你會看到這個提示:
這表示因為Internet Explorer安全性設定所致,基本上我們無法要求用戶端把我們的網站設為受信任網站(內部網站也許可以,但公開網站不可能),要讓Internet Explorer不封鎖的話,只有一個辦法,就是對封裝檔進行數位簽章。雖然我們現階段不可能購買商用的數位簽章(以Verisign的簽章來說,一年要499美元),但我們可以使用makecert.exe來產生一個測試用的自我簽章(Self-signed Certificate):
makecert -sr LocalMachine -n "CN=MyCert" -$ commercial -ss MyCertStore -in MyCert -sv MyCert.pvk -a sha1 MyCert.cer
NOTE
makecert.exe的詳細資訊可參考:http://msdn.microsoft.com/zh-tw/library/bfsktky3(VS.80).aspx
NOTE
您在以-sv參數設定輸出私密金鑰時,會被要求設定密碼:
基本上我們建議你一定要為私密金鑰設密碼,否則一旦私密金鑰被盜取,犯罪者可用它來偽造身份。
當你執行完上述的指令後,你會得到一個公鑰檔(MyCert.cer)以及私鑰檔(MyCert.pvk),私鑰檔是很重要的簽署檔案,開發人員必須要妥善的保護它。
在我們使用簽章工具簽署CAB檔之前,我們還要執行兩個程序,一個是將cer轉換成spc(Software Publisher Certificate),這個可以利用cert2spc.exe來做,它的指令很簡單:
cert2spc [Cert1.cer Cert2.cer Cert3.cer ...] [Output.spc]
本例的指令是:
cert2spc MyCert.cer MyCert.spc
再來是將私密金鑰以及SPC檔合併成PFX(Personal Information Exchange)檔,這個可以用pvk2pfx.exe來做,它的指令則是:
pvk2pfx –pvk [Private Key File] –pi [PVK Password] –spc [SPC file] –pfx [PFX File] –po [PFX Password]
本例的指令是:
pvk2pfx –pvk MyCert.pvk –spc MyCert.spc –pfx MyCert.pfx
當整個程序完成後,我們會得到MyCert.cer,MyCert.pvk,MyCert.spc以及MyCert.pfx檔案,此時我們就可以使用簽章工具signtool來簽署CAB檔案,請使用下列指令:
signtool sign /f MyCert.pfx MyControl.cab
NOTE
如果你對signtool.exe的指令用法不熟,可以用signtool signwizard來啟動數位簽章精靈的對話盒,再依指示做簽署即可。
不過就算你完成了簽署,IE仍然會阻擋你的封裝,因為目前的簽章是不被根憑證授權的,所以你需要在測試用戶端上安裝剛才產生的MyCert.cer到根憑證授權單位。方法是先將MyCert.cer複製到測試用戶端,然後在憑證上按兩下,再按『安裝憑證』,在匯入精靈的第二個步驟中,選擇憑證存放區為『信任的根憑證授權』:
然後完成精靈,你會看到這個提示:
請按『是』接受,此憑證就會安裝到受信任根憑證區。現在請重新瀏覽測試網頁,上方的資訊提示列會改變:
這就表示數位簽章檢查已經通過,此時就能按照一般程序來安裝。然後測試元件是否與在開發電腦般正常運作。
針對Windows Vista以及Windows 7作業系統的電腦
前述的作法可以在Windows XP(瀏覽器為IE6)上正常運作,同時使用者也無須額外的程序,但到了Windows Vista以及Windows 7作業系統,由於ActiveX的安裝行為改變了,再也無法使用msiexec.exe /qn的方式在背景安裝,此時我們就只能修改INF的指令,由setup.exe來啟動安裝程式,下列的INF內容即為可在Windows Vista(IE7)與Windows 7(IE8)上執行ActiveX控制項安裝的INF:
[version]
signature="$CHICAGO$"
AdvancedINF=2.0
[Add.Code]
Installer.msi=Installer.msi
setup.exe=setup.exe
[Installer.msi]
file-win32-x86=thiscab
clsid={…}
hook=hook1
[setup.exe]
file-win32-x86=thiscab
[Setup Hooks]
hook1=hook1
[hook1]
run=%EXTRACT_DIR%\setup.exe
結語
本系列的文章帶領你完成整個 .NET Framework 開發 ActiveX Control 的程序,有了這個程序,你可以再變化它來開發不同的進階控制項 (ex: 自然人憑證控制項)。