原文:https://www.cnblogs.com/mooncher/p/6848626.html
開發環境: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

VS2010+win10: 命令:C:\Program Files (x86)\Microsoft SDKs\Windows\v7.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):
|
1
2
3
4
5
6
7
8
9
10
11
|
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文件,在需要使用瀏覽器插件的頁面上加入以下代碼:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<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類中的方法,是不是很方便?
為了更方便直觀的看出插件有沒有正常加載,可以再加入一些檢測代碼,如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<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瀏覽器插件的技能~

