開發環境:VS2008
第一步 創建項目
新建一個項目,選擇“Windows窗體控件庫”,創建一個用戶控件項目“ActiveXDemo”(注意,這里起名不能用中文,否則后面會出問題),里面有個用戶控件類UserControl1.cs
在類中寫上你自己需要的業務邏輯代碼,保存
第二步 設置項目屬性
在AssemblyInfo.cs里添加[assembly: AllowPartiallyTrustedCallers()],需要引用using System.Security;命名空間
設置項目屬性,右鍵項目——屬性

選擇“應用程序”,點開“程序集信息”

勾選“使程序集COM可見”,點“確定”
然后選擇“生成”,滾動拉倒底部,勾選“為COM互操作注冊”

然后保存,重新編譯項目,至此,此時的“ActiveXDemo.dll”就成了一個ActiveX控件
第三步 安裝外部工具
安裝外部工具“OLE/COM對象查看器”和“創建GUID”(已有這兩款工具的可以忽略此步驟)

1.OLE/COM對象查看器
這款工具是用來查看ActiveX控件的,也就是驗證你的項目有沒有成為一個ActiveX控件
安裝方法:點開VS頂部菜單欄“工具”——“外部工具”

然后,添加一個“OLE/COM對象查看器”,對應的命令程序一般放在C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\OleView.Exe

點擊“應用”,“確定”,這就算是安裝完成,再重新點開頂部的“工具”菜單看看,里面就有一項“OLE/COM對象查看器”
點擊“OLE/COM對象查看器”,展開左側的“.NET Category”

你會發現,這里面就有你剛剛創建的ActiveX控件

這就是OLE/COM對象查看器的作用
2.創建GUID
高版本的VS貌似都自帶了這個工具,但是在有的低版本或者安裝不完整比如Vs2008中不一定有這個工具,所以在沒有的時候需要安裝一下
安裝方法同上,只不過命令程序的地址一般是C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\guidgen.exe

此工具的用途在下面的步驟中會講到
第四步 提高ActiveX插件的安全等級
IE怎么知道一個插件是腳本安全的?它是通過以下兩個辦法。
一是查詢ActiveX組件是否實現了IObjectSafety接口,並且返回腳本安全;
二是查詢ActiveX組件是否在注冊表的Component Category Manager里表明自己實現了CATID_SafeForInitializing和CATID_SafeForScripting。
這里我們只說第一種實現IObjectSafety接口
首先,為控件類UserControl1添加一個GUID,這個編號將用於B/S系統的客戶端調用時使用(可以使用 工具-創建GUID 菜單創建一個GUID):
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ActiveXDemo
{
[Guid("BB725724-65D6-4e71-AA11-DEDFAFE9248F"), ProgId("ActiveXDemo.UserControl1"), ComVisible(true)]
public partial class UserControl1 : UserControl,IObjectSafety
{
注意,要引入System.Runtime.InteropServices;命名空間
其次,為了讓ActiveX控件獲得客戶端的信任,控件類還需要實現一個名為“IObjectSafety”的接口,因此在項目中添加一個接口類IObjectSafety
直接將下列代碼復制粘貼,不要作任何改動,尤其是GUID,都是固定的,不能改
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace ActiveXDemo { [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); } }
同樣,需要引入System.Runtime.InteropServices;命名空間
接着,在控件類UserControl1中實現IObjectSafety的接口
#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
這些代碼也是固定的,不能改動,直接復制粘貼就行了
第五步 制作成安裝文件
在原項目解決方案中新建一個安裝項目,在VS2008中,是這樣操作的
新建項目——其他項目類型——安裝和部署——安裝項目

注意,這里下方“解決方案”這里要選擇“添入解決方案”
然后,右鍵安裝項目——添加——項目輸出

將我們的項目ActiveXDemo設為主輸出

點確定,然后在主輸出文件上右鍵——屬性
將Register屬性設為vsdrpCOM

重新編譯安裝項目,打開安裝項目所在目錄

至此,ActiveX瀏覽器插件的安裝包就制作好了,雙擊setup.exe文件或ActiveXDemoSetup.msi文件可以將瀏覽器插件安裝到你的電腦
第六步 使用ActiveX插件
新建一個Web項目或者一個Html文件,在需要使用瀏覽器插件的頁面上加入以下代碼:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>無標題頁</title>
</head>
<body>
<object id="csharpActiveX" classid="clsid:BB725724-65D6-4e71-AA11-DEDFAFE9248F" width="100%" height="150"></object>
<form id="form1" runat="server">
<div>
<input type='button' onclick='csharpActiveX.Test()' value='我是按鈕'/>
</div>
</form>
</body>
其中,重點是object標簽里的classid屬性,屬性里面的GUID對應的就是第四步中指定的GUID
直接使用object定義的id屬性就可以調用UserControl1類中的方法,是不是很方便?
為了更方便直觀的看出插件有沒有正常加載,可以再加入一些檢測代碼,如下:
<body>
<object id="csharpActiveX" classid="clsid:BB725724-65D6-4e71-AA11-DEDFAFE9248F" width="100%" height="150"></object>
<form id="form1" runat="server">
<div>
<input type='button' onclick='csharpActiveX.Test()' value='我是按鈕'/>
</div>
</form>
</body>
<script type="text/javascript">
var objCard = document.getElementById("csharpActiveX");
if (objCard.object==null) {
alert("csharpActiveX插件未安裝!");
}
else{
alert("已檢測到csharpActiveX插件!");
}
</script>
</html>
然后,由於只有IE支持ActiveX瀏覽器插件,所以在IE瀏覽器中打開這個頁面,看一下效果

這時,不放心的話,可以再檢查咱們的ActiveX插件究竟有沒有安裝上
點開工具欄“工具”——“管理加載項”

可以看到其中有一項ActiveXDemo.UserControl1,這就是我們安裝上去的瀏覽器插件

第七步 ActiveX插件調用頁面Js
這里,主要需要引入一個程序集叫Microsoft.mshtml.dll,它在系統文件夾里C:\Program Files (x86)\Microsoft.NET\Primary Interop Assemblies
引入后,開始在插件項目里寫上注冊Js函數相關的代碼,如下
private IHTMLWindow2 temphtml = null; private string functionstr = ""; public void RegJs(object objWinJs, string funcJs) { temphtml = (IHTMLWindow2)objWinJs; if (temphtml != null && !string.IsNullOrEmpty(funcJs)) { functionstr = funcJs; } else { temphtml = null; functionstr = ""; MessageBox.Show("注冊ActiveX插件回調腳本失敗"); } }
以及,執行頁面Js函數的代碼
private void ShowResult(object s, EventArgs e) { try { //必須要阻塞線程一段時間,以免在交易超時的情況下,由於read太快導致讀取不完整 System.Threading.Thread.Sleep(500); string txt = serialPort.ReadExisting(); temphtml.execScript("var msgActiveX='" + txt+"';", "JScript"); temphtml.execScript(functionstr + "()", "JScript"); } catch (Exception ex) { MessageBox.Show(ex.Message.ToString()); } }
在這里,我向頁面輸出了一個msgActiveX變量,並調用了前面注冊過的Js函數
然后,我們還需要在頁面加載的時候,調用插件的注冊JS函數方法,以及此Js函數定義
<script type="text/javascript"> Ext.onReady( function() { objCard.regJs(window, 'test'); } );
function test() {
var str = msgActiveX.substring(5);
var objJson = eval('(' + str + ')');
alert(objJson.responseCode);
//alert("回調函數執行成功");
} </script>
至此,恭喜你已成功掌握了制作ActiveX瀏覽器插件的技能~
