c# ActiveX 控件的開發
關於ActiveX控件的開發,網上很多例子,昨天也整整研究一天才捋順了.
網上大部分例子都是js調用控件的方法,由於要實現在html頁面"相應"控件的事件,整整折騰一天.
關鍵點在於 "創建ActiveX控件" 的 第2,和第7
該技術局限性較大,如浏覽器端需安裝 .net 框架,僅限於IE浏覽器.
關於ActiveX的證書及浏覽器安裝時設置,可參考 www.Bkjia.com這也是我看到比較詳細的介紹了.
創建ActiveX控件
1.創建一個類庫;
2.項目屬性-應用程序-程序集信息-"使程序集COM可見"勾上;
3.項目屬性-生成-"為COM互操作注冊"勾上.(這個折騰一天,否則注冊事件不可用);
4.創建接口: IObjectSafety (注意GUID不能變);
5.創建ActiveX控件的基類並實現IObjectSafety,ActiveX控件可以繼承它來減少代碼;
6.創建一個ActiveX自定義控件如:ActiveXDemo1;
7.定義ActiveXDemo1的"方法接口"及"事件接口".(如使用自定義事件需用此方式), "事件接口"成員應加上[DispId(x)]標識;
8.創建ActiveX控件完成.
IObjectSafety 接口定義
[ComImport, Guid("4A359FBB-C9A4-494E-B048-AC068DB4FCB2")] //該GUID不能變
[InterfaceType(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);
}
}
ActiveX控件基類(ActiveXControlBase)
public class ActiveXControlBase : 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
}
自定義ActiveX控件
[ComVisible(true)]
[Guid("684AAD87-C086-4F27-AE55-941A1AAC7212")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IThreadDemoEvent
{
[DispId(1)] //使用事件,必須加上該標識
void ShowMessage1(string str_Msg);
[DispId(2)]
void ShowMessage2(string str_Msg);
}
[ComVisible(true)]
[Guid("4D12136B-9545-423B-A110-B9405ADF8B30")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IThreadDemo
{
string StartTimer();
string StopTimer();
}
[Guid("2B4FCB85-A3B7-43BD-B104-7380E7F3483F"),
ClassInterface(ClassInterfaceType.AutoDual),
ComDefaultInterface(typeof(IThreadDemo)),
ComSourceInterfaces(typeof(IThreadDemoEvent)),
ComVisible(true)
]
public class ActivexThreadDemo : ActiveXControlBase, IThreadDemo
{
~ActivexThreadDemo()
{
ShowMessage1("釋放了啊");
}
Thread _th;
bool _isStop;
public event ShowMessageHandle ShowMessage1;
public event ShowMessageHandle ShowMessage2;
void ThreadMethd()
{
while (true)
{
Thread.Sleep(3000);
if (ShowMessage1 != null)
{
ShowMessage1.Invoke(DateTime.Now.ToString());
}
if (_isStop) break;
}
_th.Abort();
_th = null;
}
public string StartTimer()
{
if (_th == null)
{
_isStop = false;
_th = new Thread(ThreadMethd);
_th.IsBackground = false;
_th.Start();
return "開起計時";
}
if (ShowMessage2 != null)
{
ShowMessage2("執行了 StartTimer");
}
return "已經開起過計時;";
}
public string StopTimer()
{
if (_isStop)
{
return "已經停止計時了!";
}
else
{
_isStop = true;
return "停止計時";
}
}
}
注意:
不能使用泛型委托來聲明事件,如:public event Action<T> ShowMessageHandle;
當類裡面包含 static成員,刷新頁面不會清空
跨線程觸發事件: [事件].Invoke(參數1,參數2 ...);
ActiveX控件Setup
1.創建Installer項目;
2.右擊項目 添加->項目輸出 打開添加項目輸出組對話框,並選擇ActiveX控件類庫;
3.主輸出文件的屬性 Register 值為 vsdrpCOM (關鍵),RemovePreviousVersions 設置為true
web頁面測試;
1.創建一個object 標簽,calassid為控件GUID
<object id="ActiveXObj1" classid="clsid:3BCF612C-91CF-4543-83BB-FD2331FDDCB6" ></object>
2.調用控件方法
var r = document.ActiveXObj1.Test1();
3."注冊控件的事件"
<script language="javascript" type="text/javascript" for="ActiveXObj1" event="ShowMessage1(msg)">
alert("ActiveXObj1 :"+ msg )
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ActiveX測試頁面</title>
<script type="text/javascript">
function test1() {
var r = document.ActiveXObj1.Test1();
window.status = r;
}
function StartTimer() {
alert(document.ActiveThreadEvent);
var r = document.ActiveThreadEvent.StartTimer();
window.status = r;
}
function StopTimer() {
var r = document.ActiveThreadEvent.StopTimer();
window.status = r;
}
</script>
<!--事件的注冊-->
<script language="javascript" type="text/javascript" for="ActiveXObj1" event="ShowMessage1(msg)">
alert("ActiveXObj1 :"+ msg )
</script>
<script language="javascript" type="text/javascript" for="ActiveXObj1" event="ShowMessage2(msg)">
alert("ActiveXObj1:" + msg)
</script>
<!--線程事件注冊-->
<script language="javascript" type="text/javascript" for="ActiveThreadEvent" event="ShowMessage1(msg)">
alert("ActiveThreadEvent :"+ msg )
</script>
<script language="javascript" type="text/javascript" for="ActiveThreadEvent" event="ShowMessage2(msg)">
alert("ActiveThreadEvent:" + msg)
</script>
</head>
<body>
<object id="ActiveXObj1" classid="clsid:3BCF612C-91CF-4543-83BB-FD2331FDDCB6" ></object>
<br />
<object id="ActiveThreadEvent" classid="clsid:2B4FCB85-A3B7-43BD-B104-7380E7F3483F" ></object>
<br />
<br />
<input type="button" value="測試4-相應事件!" onclick="test1();" /><br />
<input type="button" value="開始計時!" onclick="StartTimer();" /><br />
<input type="button" value="停止計時!" onclick="StopTimer();" /><br />
</body>
</html>