從瀏覽器啟動客戶端程序
- 綜述
現在有很多B/S與C/S相結合的產品,會出現一種需求:從瀏覽器啟動客戶端的程序,並且如果客戶端未安裝相應程序,先提示安裝。主流的幾款產品:騰訊QQ、阿里旺旺、迅雷、PPLive等,都有實現了類似的功能。瀏覽器啟動客戶端程序可以通過注冊自定義的Url協議來實現,而檢測客戶端是否安裝程序需要利用ActiveX控件。要額外注意的是,現在只有IE瀏覽器才支持。
- 客戶端程序
先准備一個簡單的客戶端程序,只用來顯示傳入的命令行參數。
Client
1 namespace wuhong.Client
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 if (args != null && args.Length > 0)
8 {
9 Array.ForEach(args, arg => Console.WriteLine(arg));
10 }
11
12 Console.ReadLine();
13 }
14 }
15 } - 從瀏覽器啟動
注冊自定義的Url協議,這樣當用戶點擊這個URL協議的鏈接后,IE就會啟動相關URL協議的處理器,使用注冊的程序來處理這個協議。具體來說,比如現在需要注冊“wuhong.client”的Url協議,使得形如“wuhong.client:XXXXYYYY”的鏈接都由上節的控制台程序來處理。這一切只需要在客戶端安裝控制台程序的同時向注冊表添加下面的項就可以實現:
注冊表
1 [HKEY_CLASSES_ROOT\wuhong.client]
2
3 @="wuhong.Client"
4
5 "URL Protocol"=""
6
7 [HKEY_CLASSES_ROOT\wuhong.client\DefaultIcon]
8
9 @=" wuhong.Client.exe "
10
11 [HKEY_CLASSES_ROOT\wuhong.client\Shell]
12
13 [HKEY_CLASSES_ROOT\wuhong.client\Shell\open]
14
15 [HKEY_CLASSES_ROOT\wuhong.client\Shell\open\command]
16
17 @="\"[TARGETDIR]wuhong.Client.exe\" \"%1\""解釋一下其中幾項:[HKEY_CLASSES_ROOT\wuhong.client]默認項和URL Protocol項的值都是設置一個名稱。[HKEY_CLASSES_ROOT\wuhong.client\DefaultIcon]默認項的值是Url協議的圖標文件名的路徑。簡單處理可以省略這一項。[HKEY_CLASSES_ROOT\wuhong.client\Shell\open\command]默認項的值是用來調用(或者啟動)處理這個Url協議的程序。整個Url會作為一個參數傳遞給處理程序。 - 檢測客戶端程序安裝
檢測客戶端是否安裝了上節的控制台程序,需要另外實現一個ActiveX控件,在客戶端安裝程序的同時一並安裝。這樣可以利用ActiveX控件的加載情況,來判斷控制台程序是否安裝。作為示例,這里實現一個沒有任何其他功能的ActiveX控件。首先定義IobjectSafety接口。IobjectSafety接口用來向IE聲明自身是腳本安全的。在IE的中級安全級別上,是允許腳本安全的ActiveX控件的創建而不提示警告。
IobjectSafety接口
1 namespace wuhong.ActiveX
2 {
3 [ComImport, Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
4 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
5 public interface IObjectSafety
6 {
7 [PreserveSig]
8 int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
9
10 [PreserveSig()]
11 int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
12 }
13 }接下來是控件的代碼,實現一個“wuhong.client”的控件,本身不添加任何額外的功能。
UserControl類
1 namespace wuhong.ActiveX
2 {
3 [Guid("9C9701D1-D188-495d-8721-9D246211A27C"), ProgId("wuhong.client"), ComVisible(true)]
4 public partial class ActiveXObject : UserControl, IObjectSafety
5 {
6 public ActiveXObject()
7 {
8 InitializeComponent();
9 }
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
15 public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
16 {
17 pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
18 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
19
20 return S_OK;
21 }
22
23 public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
24 {
25 return S_OK;
26 }
27 }
28 }另外AssemblyInfo.cs中需要修改並添加以下內容:
AssemblyInfo.cs
1 using System.Security;
2 [assembly: AllowPartiallyTrustedCallers()]
3 [assembly: ComVisible(true)]項目生成中也需要選擇“為COM互操作注冊”。 - 測試
將客戶端程序、ActiveX控件以及注冊Url協議的注冊表項制作成安裝包。使用下面的頁面代碼測試:
Test頁面
1 <html xmlns="http://www.w3.org/1999/xhtml" >
2 <head>
3 <script type='text/javascript'>
4 function Start() {
5 try {//支持
6 var obj = new ActiveXObject("wuhong.client");
7 }
8 catch (e) {//不支持
9 }
10 if(null != obj){
11 delete obj;
12 window.navigate('wuhong.client:start?HelloWorld');
13 }
14 else{
15 alert("您未安裝程序,請安裝!");
16 }
17 }
18 </script>
19 <title></title>
20 </head>
21 <body>
22 <input type="button" onclick="Start()" value="啟動"/>
23 </body>
24 </html>可以看到安裝前后點擊“啟動”按鈕的區別。安裝前:
安裝后:

