第壹步 創建ActiveX項目
使用.NET語言編寫的ActiveX控件的主體就是壹個類庫,首先我們來創建這個類庫項目。打開Visual Studio 2008,File-New-Project,選擇Class Library,創建壹個類庫項目。
創建ActiveX項目
第二步 編寫ActiveX主體
ActiveX的主體包括方法定義接口、事件定義接口(可選)、實現這些接口的ActiveX主體類三個部分。下面是筆者原創的Demo。
首先,我們創建方法定義接口:
///summary
/// 該接口定義了ActiveX的方法
////summary
[
Guid("F3BD342F-14E1-4347-BFBD-F449DD070DF9"),
InterfaceType(ComInterfaceType.InterfaceIsDual),
ComVisible(true)]
publicinterfaceIBosnMaActiveX
{
[DispId(1)]
void Start();
[DispId(2)]
void Stop();
}
該接口內的成員會暴露給外部調用。這裏我們提供兩個簡單方法Start和Stop。使用工具(Visual Studio - Tools - Create GUID)生成自己的GUID。
接下來定義事件接口:
///summary
/// 該接口定義了ActiveX的事件
////summary
[ComVisible(true)]
[Guid("C4F9F24F-B860-4e79-945D-B9A281950C82")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
publicinterfaceBosnMaActiveXEvents
{
[DispId(21)]
void OnRecorderStarted();
[DispId(22)]
void OnRecorderStopped();
[DispId(23)]
void OnRecorderVolumeChanged(int value);
}
這裏我們為ActiveX定義三個事件,分別為OnRecorderStarted、OnRecorderStopped 、OnRecorderVolumeChanged(帶壹個int參數)。
最後我們編寫集成方法接口和事件接口的ActiveX主體類:
[
Guid("78E683CE-EC77-40b0-B0C3-4060FFC70A93"),
ProgId("ActiveXOfBosnMa.BosnMaActiveX"),
ClassInterface(ClassInterfaceType.None),
ComDefaultInterface(typeof(IBosnMaActiveX)),
ComSourceInterfaces(typeof(BosnMaActiveXEvents)),
ComVisible(true)
]
publicclassBosnAcX : IBosnMaActiveX, IObjectSafety
{
#region Events, Handlers, Instances
publicdelegatevoidVolumeChangedHandler(int value);
publicdelegatevoidSimpleHandler();
publiceventVolumeChangedHandler OnRecorderVolumeChanged;
publiceventSimpleHandler OnRecorderStarted;
publiceventSimpleHandler OnRecorderStopped;
#endregion
#region Implementation of IBosnMaActiveX
///summary
/// 調用該方法將引發OnRecorderStarted事件,並在3秒後引發OnRecorderVolumeChanged
////summary
publicvoid Start()
{
OnRecorderStarted();
SimpleHandler d = Work;
d.BeginInvoke(null, null);
}
publicvoid Work()
{
Thread.Sleep(3000);
OnRecorderVolumeChanged(53);
}
///summary
/// 調用該方法將引發OnRecorderStopped事件
////summary
publicvoid Stop()
{
OnRecorderStopped();
}
#endregion
}
這裏要註意主體類的事件名稱要與事件接口(在上例中為BosnMaActiveXEvents)中的方法名相同。在BosnAcX中我們實現了IBosnMaActiveX中的方法,當調用Start()時引發壹個OnRecorderStarted事件,並在3秒後引發壹個OnRecorderVolumeChanged事件,在調用Stop()時引發壹個OnRecorderStopped事件。
編譯並註冊ActiveX
編譯整個項目將輸出dll。
然後我們啟動命令行CMD(如果是Vista/Win7使用管理員方式打開),使用以下命令註冊控件.
C:D: //轉到.dll所在目錄,筆者為了方便將.dll copy到了D盤根目錄
D:regasm activexofbosnma.dll /codebase /tlb
*regasm命令在%systemroot%Microsoft.NETFrameworkv2.x.xxxx目錄下,將該目錄註冊到用戶環境變量中即可不使用完全限定名運行該命令。
*使用regasm activexofbosnma.dll /codebase /tlb /unregister可以反註冊,在ActiveX代碼變更時重編譯後,需要先反註冊再註冊。
測試ActiveX
最後我們創建壹個html頁面來測試該ActiveX.
html
headrunat="server"
title/title
objectid="myAcX"name="myAcX"classid="clsid:78E683CE-EC77-40b0-B0C3-4060FFC70A93"
/object
scriptlanguage="javascript"for="myAcX"type="text/javascript"event="OnRecorderVolumeChanged(v);"
MyDiv.innerHTML = 'In javascript: Get Volume:'+v;
/script
scriptlanguage="javascript"for="myAcX"type="text/javascript"event="OnRecorderStarted"
MyDiv.innerHTML = 'In javascript: OnRecorderStarted';
/script
scriptlanguage="javascript"for="myAcX"type="text/javascript"event="OnRecorderStopped"
MyDiv.innerHTML = 'In javascript: OnRecorderStopped';
/script
/head
body
form
scriptlanguage="javascript"type="text/jscript"
function Button1_onclick() {
myAcX.Start();
}
function Button2_onclick() {
myAcX.Stop();
}
function RecorderVolumeChanged(v) {
alert('volume:' + v);
}
/script
divid="MyDiv"Nothing happened/div
p
inputid="Button1"type="button"value="Start"onclick="Button1_onclick()"/nbsp;nbsp;nbsp;nbsp;nbsp;nbsp;nbsp;nbsp;nbsp;nbsp;nbsp;nbsp;
inputid="Button2"type="button"value="Stop"onclick="Button2_onclick()"//p
/form
/body
/html
測試效果
首先使用IE打開測試頁面
允許ActiveX交互後進入主界面,點擊Start按鈕會收到ActiveX返回的OnRecorderStarted事件。
三秒過後收到Volume事件
最後點擊Stop按鈕會收到OnRecorderStopped事件。
安全性
為了標記ActiveX控件為安全的(避免彈出“該控件是不安全的”警告),需要實現IObjectSafety接口。
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Text;
namespace ActiveXOfBosnMa
{
[
Serializable,
ComVisible(true)
]
publicenumObjectSafetyOptions
{
INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001,
INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002,
INTERFACE_USES_DISPEX = 0x00000004,
INTERFACE_USES_SECURITY_MANAGER = 0x00000008
};
//
// MS IObjectSafety Interface definition
//
[
ComImport(),
Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
]
publicinterfaceIObjectSafety
{
[PreserveSig]
long GetInterfaceSafetyOptions(refGuid iid, outint pdwSupportedOptions, outint pdwEnabledOptions);
[PreserveSig]
long SetInterfaceSafetyOptions(refGuid iid, int dwOptionSetMask, int dwEnabledOptions);
};
//
// Provides a default Implementation for
// safe scripting.
// This basically means IE won't complain about the
// ActiveX object not being safe
//
publicclassIObjectSafetyImpl : IObjectSafety
{
privateObjectSafetyOptions m_options =
ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER |
ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;
#region [IObjectSafety implementation]
publiclong GetInterfaceSafetyOptions(refGuid iid, outint pdwSupportedOptions, outint pdwEnabledOptions)
{
pdwSupportedOptions = (int)m_options;
pdwEnabledOptions = (int)m_options;
return 0;
}
publiclong SetInterfaceSafetyOptions(refGuid iid, int dwOptionSetMask, int dwEnabledOptions)
{
return 0;
}
#endregion
};
}
並實現以下兩個方法:
#region Implementation of IObjectSafety
privateObjectSafetyOptions m_options =
ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER |
ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;
publiclong GetInterfaceSafetyOptions(refGuid iid, outint pdwSupportedOptions, outint pdwEnabledOptions)
{
pdwSupportedOptions = (int)m_options;
pdwEnabledOptions = (int)m_options;
return 0;
}
publiclong SetInterfaceSafetyOptions(refGuid iid, int dwOptionSetMask, int dwEnabledOptions)
{
return 0;
}
#endregion