C# Activex開發、打包、簽名、發佈

1、前言
      最近有這樣一個需求,須要在網頁上面啓動客戶端的軟件,軟件之間的通訊、調用,單單依靠HTML是沒法實現了,所以必須借用Activex來實現。因爲本人主要擅長C#,天然本文給出了用C#實現的範例,本文的預期效果是有必定Winform基礎的人可都輕鬆讀懂本文。javascript

文章主要介紹瞭如下幾個部分:
 
一、用C#製做Activex控件,併發布爲msi安裝文件
 
二、將exe打包爲cab,達到瀏覽器自動安裝的效果
 
三、給cab數字簽名(可選)
 
四、將Activex應用到網頁上
 
2、用C#製做Activex控件,併發布爲msi安裝文件
 
一、新建window用戶控件項目EasyActivex。其實VS2010並無提供專門的Activex項目模板,所謂的Activex,只要符合com標準便可。
 html

 
 
 
2)在EasyActivex項目添加IObjectSafety接口
 java

 
在IObjectSafety接口代碼以下,值得注意的是Guid不能隨便改,必須爲一下代碼給出的Guid:
 
 
 windows

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;瀏覽器

namespace EasyActivex
{安全

    [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
        [PreserveSig]
        int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);服務器

        [PreserveSig()]
        int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
    }
}
View Code
 數據結構

3)在EasyActivex項目添加EUserControl控件,在控件中實現IObjectSafety接口。
 併發

 
在控件上面添加按鈕,命名爲btnOpenNote
 框架

 
控件的後臺代碼必須實現IObjectSafety接口
 
 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace EasyActivex
{
    //這個Guid,網頁調用的時候用到,Mark
    [Guid("685F0A47-944D-4145-BF4E-76A02A422B02")]
    //這裏要實現IObjectSafety接口
    public partial class EUserControl : UserControl, IObjectSafety 
    {
        public EUserControl()
        {
            InitializeComponent();
        }
        #region IObjectSafety  接口成員實現(直接拷貝便可)

        private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
        private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
        private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
        private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
        private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";

        private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
        private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
        private const int S_OK = 0;
        private const int E_FAIL = unchecked((int)0x80004005);
        private const int E_NOINTERFACE = unchecked((int)0x80004002);

        private bool _fSafeForScripting = true;
        private bool _fSafeForInitializing = true;

        public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
        {
            int Rslt = E_FAIL;

            string strGUID = riid.ToString("B");
            pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
            switch (strGUID)
            {
                case _IID_IDispatch:
                case _IID_IDispatchEx:
                    Rslt = S_OK;
                    pdwEnabledOptions = 0;
                    if (_fSafeForScripting == true)
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
                    break;
                case _IID_IPersistStorage:
                case _IID_IPersistStream:
                case _IID_IPersistPropertyBag:
                    Rslt = S_OK;
                    pdwEnabledOptions = 0;
                    if (_fSafeForInitializing == true)
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
                    break;
                default:
                    Rslt = E_NOINTERFACE;
                    break;
            }

            return Rslt;
        }

        public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
        {
            int Rslt = E_FAIL;
            string strGUID = riid.ToString("B");
            switch (strGUID)
            {
                case _IID_IDispatch:
                case _IID_IDispatchEx:
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
                        Rslt = S_OK;
                    break;
                case _IID_IPersistStorage:
                case _IID_IPersistStream:
                case _IID_IPersistPropertyBag:
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
                        Rslt = S_OK;
                    break;
                default:
                    Rslt = E_NOINTERFACE;
                    break;
            }

            return Rslt;
        }

        #endregion

        /// <summary>
        /// 打開記事本
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenNote_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("notepad.exe");
        }
    }
}
View Code
小提示:EUserControl代碼的Guid能夠用VS附帶的Guid生成工具生成:

 

 
4)在EasyActivex項目AssemblyInfo.cs文件中添加代碼
 
 
 
//用戶添加
[assembly: AllowPartiallyTrustedCallers()]

5)設置EasyActivex項目項目屬性爲com互操做
 

 
6)新建windows程序安裝項目EasySetup
 

 
7)將EasyActivex項目生產的dll添加到EasySetup項目中。下圖的EasyActivex.dll爲已經添加進去了的文件。
 

 
8)在EasySetup項目中,設置EasyActivex.dll文件屬性爲vsdraCOM。
 

 
完成以上步驟,生成下便可獲得msi安裝文件
 
3、將msi安裝文件打包爲cab,達到在瀏覽器中自動安裝的效果
 
若是隻是生成了msi文件,用戶安裝的時候比較麻煩,像安裝通常軟件同樣,須要用戶慢慢點擊下一步,慢慢安裝,在本項目中採用打包成cab文件的方式,作到用戶點擊運行後,便可自動安裝。
在這裏須要準備文件有:
    cabarc.exe:微軟提供的cab打包工具
    EasySetup.msi:  本案例中EasySetup項目生成的windows部署安裝文件
    install.inf : 須要跟EasySetup.msi打包在一塊兒的文件,製做方法請見下文
    build.bat:  打包的批處理命令,製做方法請見下文
 
1)  install.inf製做。新建txt文件,加入如下內容,將文件名從新命名爲install.inf便可。其中EasyZSetup.msi便是要打包的安裝程序的名稱。

[version] 
signature="$CHICAGO$" 
AdvancedINF=2.0 

[Setup Hooks] 
hook1=hook1 

[hook1] 
run=msiexec.exe /i "%EXTRACT_DIR%\EasySetup.msi" /qn
 

2)   build.bat製做。新建txt文件,加入如下內容,將文件名從新命名build.bat便可。其中EasyActivex.cab是生成目標cab的名稱;install.inf是第一步生成的文件名,而EasySetup.msi是須要打包的安裝程序名;第二條ping命令僅僅是讓批處理不要那麼快退出,起到更利於觀察生成結果的做用。

"cabarc.exe" -s 6144 n EasyActivex.cab install.inf EasySetup.msi
ping -n 20 127.0.0.1 >nul 

 把以上四個文件複製到同一個文件夾中,雙擊build.bat批處理命令便可生成cab文件
 

 
雙擊bat後的運行結果以下,其中EasyActivex.cab便是生成的目標cab文件。
 

 
 
3、給cab數字簽名(可選)
 
     因爲處於安全問題考慮,IE瀏覽器設置默認是禁用未簽名的Activex控件的,不過想一想也知道,假如打開個未知網頁,「網頁」就能隨便調用計算機本地的東西是多麼恐怖的事情,所以,瀏覽器運行的Activex必須是簽名了的,也符合常理。
     若是不怕用戶麻煩,不採用cab簽名的方式的話,也能夠經過設置瀏覽器安全性來運行Activex。設置方法:打開瀏覽器--瀏覽器Internet選項--安全選項卡--自定義級別按鈕-下載未簽名的Activex控件設置爲提示,保存便可。等安裝完畢後,能夠將「下載未簽名的Activex控件」設置回禁用。
   如下爲給cab簽名的方法,具體方法,數字認證網上面已經介紹得很詳細:
 
   1)申請、安裝證書。上中國數字認證網(http://www.ca365.com/)申請一個免費數字證書(試用期爲1年,若是企業用的話須要購買)。
        操做方法:http://www.ca365.com/forward.do?pageurl=/ca/yhsc/4.jsp ,值得注意的是證書用途必須選擇代碼簽名證書。
        申請成功後的證書,因爲是不帶密鑰的,所以下載完畢後只可以在申請證書的機器上安裝、使用(簽名文件),若是須要在其餘機器上使用的話須要將密鑰導出,操做方法爲: http://www.ca365.com/forward.do?pageurl=/ca/yhsc/5.jsp
 
  2)用證書給cab包簽名:http://www.ca365.com/forward.do?pageurl=/ca/thsc/7.jsp
 
4、在解決方案中添加EasyWeb項目
 
    終於到了最後一步,發佈鳥。在解決方案中添加EasyWeb項目
 
 
 
在網頁目錄中新建Activex文件夾,並將EasyActivex.cab文件拷貝進去
 

 
在網頁中添加如下代碼,便可調用Activex控件了。值得注意的是codebase是cab包的相對路徑;clsid是EUserControl控件的Guid。
 
 <object id="csharpActiveX" codebase="Activex/EasyActivex.cab" classid="clsid:685F0A47-944D-4145-BF4E-76A02A422B02"></object>運行效果以下:

 

點擊便可在網頁中打開記事本了。

 

5、本案例源碼+cab打包工具+數字簽名工具下載

 

 

前言
ActiveX控件之前也叫作OLE控件,它是微軟IE支持的一種軟件組件或對象,能夠將其插入到Web頁面中,實如今瀏覽器端執行動態程序功能,以加強瀏覽器端的動態處理能力。一般ActiveX控件都是用C++或VB語言開發,本文介紹另外一種方式,在.NET Framework平臺上,使用C#語言開發ActiveX控件。

雖然本文通篇都在講如何使用C#語言開發ActiveX控件,但我並不極力推薦使用這種技術,由於該技術存在明顯的侷限,即須要瀏覽器端安裝.NET Framework(版本取決於開發ActiveX控件使用的.NET Framework版本),該侷限對於挑剔的互聯網用戶,幾乎是不可接受的。因此,我建議如下幾條均知足時,方可考慮使用該技術:

開發團隊中沒有人掌握使用C++/VB開發ActiveX控件技術;
該ActiveX控件不用於互聯網;
用戶對僅能使用IE瀏覽器訪問表示能夠接受;
用戶對在瀏覽器端安裝.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接口,能夠將該接口的實現抽象爲一個控件基類。

1、IObjectSafety接口

爲了讓ActiveX控件得到客戶端的信任,控件類還須要實現一個名爲「IObjectSafety」的接口。先建立該接口(注意,不能修改該接口的GUID值),接口內容以下:


 1 [ComImport, Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
 2 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
 3 public interface IObjectSafety
 4 {
 5     [PreserveSig]
 6     int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
 7
 8     [PreserveSig()]
 9     int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
10 }
2、ActiveXControl控件基類


 1 public abstract class ActiveXControl : IObjectSafety
 2 {
 3     #region IObjectSafety 成員
 4
 5     private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
 6     private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
 7     private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
 8     private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
 9     private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";
10
11     private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
12     private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
13     private const int S_OK = 0;
14     private const int E_FAIL = unchecked((int)0x80004005);
15     private const int E_NOINTERFACE = unchecked((int)0x80004002);
16
17     private bool _fSafeForScripting = true;
18     private bool _fSafeForInitializing = true;
19
20
21     public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
22     {
23         int Rslt = E_FAIL;
24
25         string strGUID = riid.ToString("B");
26         pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
27         switch (strGUID)
28         {
29             case _IID_IDispatch:
30             case _IID_IDispatchEx:
31                 Rslt = S_OK;
32                 pdwEnabledOptions = 0;
33                 if (_fSafeForScripting == true)
34                     pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
35                 break;
36             case _IID_IPersistStorage:
37             case _IID_IPersistStream:
38             case _IID_IPersistPropertyBag:
39                 Rslt = S_OK;
40                 pdwEnabledOptions = 0;
41                 if (_fSafeForInitializing == true)
42                     pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
43                 break;
44             default:
45                 Rslt = E_NOINTERFACE;
46                 break;
47         }
48
49         return Rslt;
50     }
51
52     public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
53     {
54         int Rslt = E_FAIL;
55
56         string strGUID = riid.ToString("B");
57         switch (strGUID)
58         {
59             case _IID_IDispatch:
60             case _IID_IDispatchEx:
61                 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) &&
62                         (_fSafeForScripting == true))
63                     Rslt = S_OK;
64                 break;
65             case _IID_IPersistStorage:
66             case _IID_IPersistStream:
67             case _IID_IPersistPropertyBag:
68                 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) &&
69                         (_fSafeForInitializing == true))
70                     Rslt = S_OK;
71                 break;
72             default:
73                 Rslt = E_NOINTERFACE;
74                 break;
75         }
76
77         return Rslt;
78     }
79
80     #endregion
81 }
3、MacActiveX控件類


 1 [Guid("65D8E97F-D3E2-462A-B389-241D7C38C518")]
 2 public class MacActiveX : ActiveXControl
 3 {
 4     public string GetMacAddress()
 5     {
 6         var mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
 7         var mos = mc.GetInstances();
 8         var sb = new StringBuilder();
 9
10         foreach (ManagementObject mo in mos)
11         {
12             var macAddress = mo["MacAddress"];
13
14             if (macAddress != null)
15                 sb.AppendLine(macAddress.ToString());
16         }
17
18         return sb.ToString();
19     }
20 }
注意,第一行指定的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控件了,能夠將它隨應用程序一併發佈,瀏覽器端訪問包含有該控件的頁面時,就會自動提示安裝了。接下來就後一種發佈方式進行詳細講解。

1、安裝項目

在解決方案中添加一個安裝項目,如圖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設置主輸出項屬性

2、製做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文件內容以下:


.OPTION   EXPLICIT
.Set Cabinet=on
.Set Compress=on
.Set MaxDiskSize=CDROM
.Set ReservePerCabinetSize=6144
.Set DiskDirectoryTemplate="."
.Set CompressionType=MSZIP
.Set CompressionLevel=7
.Set CompressionMemory=21
.Set CabinetNameTemplate="CSharpActiveX.CAB"
"installer.inf"
"CSharpActiveX.msi"
installer.inf文件定義了CAB文件的安裝行爲,做爲控件的一部分打入CAB包中,其內容以下:


[Setup Hooks]
hook1=hook1

[hook1]
run=msiexec /i %EXTRACT_DIR%\CSharpActiveX.msi /qn

[Version]
Signature= "$CHICAGO$"
AdvancedInf=2.0
makecab.bat文件是調用makecab.exe進行打包的批處理文件,內容以下:

makecab.exe   /f   "cab.ddf"當生成安裝項目後,將CSharpActiveX.msi文件拷貝到CAB目錄下,就能夠雙擊makecab.exe文件進行打包了,執行完成後會輸出CSharpActiveX.CAB文件,這就是所謂的ActiveX控件了。

3、簽名

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"
signtool sign -f Apollo.pfx -p 11111111 CSharpActiveX.CAB

應用
ActiveX控件用於HTML靜態頁面,執行於IE瀏覽器端。須要以<object>標籤的形式引入頁面文件,而後使用Javascript語言調用它。測試代碼以下:


 1 <html>
 2 <head>
 3     <title>CSharpActiveX測試</title>
 4 </head>
 5 <body>
 6 <object id="cSharpActiveX" classid="clsid:65D8E97F-D3E2-462A-B389-241D7C38C518" codebase="CSharpActiveX.CAB#version=1,0,0" style="display: none;"></object>
 7     <script type="text/javascript" language="javascript" defer="defer">
 8         var activeX = document.getElementById("cSharpActiveX");
 9         alert(activeX.GetMacAddress());
10     </script>
11 </body>
12 </html>
注意,<object>標籤的classid屬性值即爲MacActiveX類的Guid特性值。

部署
ActiveX控件在IE瀏覽器端的部署會因ActiveX控件是否簽名而有所區別。下面就以此分類進行說明。固然,首先須要將test.htm和CSharpActiveX.CAB文件部署到服務器上,假設部署後的訪問地址爲http://192.168.1.1/test.htm

1、部署未簽名的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控件接口

2、部署已簽名的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>版本。

1、升級ActiveX控件版本

打開ActiveX控件項目的「程序集信息」對話框,升級程序集版本和文件版本,如圖21所示:

 

圖21升級ActiveX控件版本

2、升級安裝項目版本

選中安裝項目,按F4快捷鍵打開安裝項目的屬性窗口,升級安裝項目的版本,如圖22所示:

 

圖22升級安裝項目版本

注意,此處還有一項關鍵工做要作,就是設置RemovePreviousVersions屬性值爲True,這樣就會在升級時先自動卸載以前版本的控件。

3、設置安裝項目註冊表項版本

瀏覽器端檢測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的默認鍵值的主次版本號間是用「,」分隔,而不是「.」,後續升級時,須要同步升級該鍵值版本號。

4、升級網頁<object>版本

最後,須要升級網頁中的ActiveX對象引用版本號,以下用下劃線標識部分:

<object id="csharpActiveX" classid="clsid:65D8E97F-D3E2-462A-B389-241D7C38C518" codebase="CSharpActiveX.CAB#version=1,0,1" style="display: none;"></object>從新生成安裝程序,打CAB包,將升級的頁面及ActiveX控件(CAB包)更新到服務器。此時,瀏覽器端從新訪問時,就會提示/自動升級ActiveX控件了。

 今後學習網 http://item.congci.com/item/c-activex-kaifa-dabao-qianming-fabu

相關文章
相關標籤/搜索