最近在忙微软Imagine Cup,需要在WEB中实现用户说话的自动检测,语音数据的传输,语音播放等功能,而浏览器出于安全性考虑实现上述功能非常困难,因此想到了
ActiveX,而ActiveX基于COM技术使用C#、VB.NET等语言也可以编写,不过笔者发现国内对C#编写ActiveX的文章并不是很多,因此写下此文希望能对想使用.NET语言编写ActiveX的人有所帮助。
关键词
ActiveX .NET 签名 Javascript 事件
涉及内容
· 使用C#编写ActiveX
· 为该ActiveX添加事件并在Javascript中注册
· 为该ActiveX制作安装包
· 为ActiveX安装包签名
开始
第一步 创建ActiveX项目
使用.NET语言编写的ActiveX控件的主体就是一个类库,首先我们来创建这个类库项目。打开Visual Studio 2008,File->New->Project,选择Class Library,创建一个类库项目。
图1 创建ActiveX项目
第二步 编写ActiveX主体
ActiveX的主体包括方法定义接口、事件定义接口(可选)、实现这些接口的ActiveX主体类三个部分。下面是笔者原创的Demo。
首先,我们创建方法定义接口:
///
<summary>
///
该接口定义了ActiveX的方法
///
</summary>
[
Guid
(
"F3BD342F-14E1-4347-BFBD-F449DD070DF9"
),
InterfaceType
(
ComInterfaceType
.InterfaceIsDual),
ComVisible
(
true
)]
public
interface
IBosnMaActiveX
{
[
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)]
public
interface
BosnMaActiveXEvents
{
[
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
)
]
public
class
BosnAcX
:
IBosnMaActiveX
,
IObjectSafety
{
#region
Events, Handlers, Instances
public
delegate
void
VolumeChangedHandler
(
int
value);
public
delegate
void
SimpleHandler
();
public
event
VolumeChangedHandler
OnRecorderVolumeChanged;
public
event
SimpleHandler
OnRecorderStarted;
public
event
SimpleHandler
OnRecorderStopped;
#endregion
#region
Implementation of IBosnMaActiveX
///
<summary>
///
调用该方法将引发OnRecorderStarted事件,并在3秒后引发OnRecorderVolumeChanged
///
</summary>
public
void
Start()
{
OnRecorderStarted();
SimpleHandler
d = Work;
d.BeginInvoke(
null
,
null
);
}
public
void
Work()
{
Thread
.Sleep(3000);
OnRecorderVolumeChanged(53);
}
///
<summary>
///
调用该方法将引发OnRecorderStopped事件
///
</summary>
public
void
Stop()
{
OnRecorderStopped();
}
#endregion
}
这里要注意主体类的事件名称要与事件接口(在上例中为
BosnMaActiveXEvents
)中的方法名相同。
在
BosnAcX
中我们实现了
IBosnMaActiveX
中的方法,当调用
Start()时引发一个OnRecorderStarted事件,并在3秒后引发一个OnRecorderVolumeChanged事件,在调用Stop()时引发一个OnRecorderStopped事件。
编译并注册ActiveX
编译整个项目将输出dll。
图2 编译ActiveX项目生成dll文件
然后我们启动命令行CMD(如果是Vista/Win7使用管理员方式打开),使用以下命令注册控件.
C:/>D: //转到.dll所在目录,笔者为了方便将.dll copy到了D盘根目录
D:/>regasm activexofbosnma.dll /codebase /tlb
D:/>regasm activexofbosnma.dll /codebase /tlb
*regasm
命令在
%systemroot%/Microsoft.NET/Framework/v2.x.xxxx/
目录下,将该目录注册到用户环境变量中即可不使用完全限定名运行该命令。
*
使用
regasm activexofbosnma.dll /codebase /tlb /unregister
可以反注册
,
在
ActiveX
代码变更时重编译后,需要先反注册再注册。
图
3
注册和反注册
ActiveX
控件
测试ActiveX
最后我们创建一个html页面来测试该ActiveX.
<
html
>
<
head
runat
="server">
<
title
></
title
>
<
object
id
="myAcX"
name
="myAcX"
classid
="clsid:78E683CE-EC77-40b0-B0C3-4060FFC70A93">
</
object
>
<
script
language
="javascript"
for
="myAcX"
type
="text/javascript"
event
="OnRecorderVolumeChanged(v);">
MyDiv.innerHTML =
'In javascript: Get Volume:'
+v;
</
script
>
<
script
language
="javascript"
for
="myAcX"
type
="text/javascript"
event
="OnRecorderStarted">
MyDiv.innerHTML =
'In javascript: OnRecorderStarted'
;
</
script
>
<
script
language
="javascript"
for
="myAcX"
type
="text/javascript"
event
="OnRecorderStopped">
MyDiv.innerHTML =
'In javascript: OnRecorderStopped'
;
</
script
>
</
head
>
<
body
>
<
form
>
<
script
language
="javascript"
type
="text/jscript">
function
Button1_onclick() {
myAcX.Start();
}
function
Button2_onclick() {
myAcX.Stop();
}
function
RecorderVolumeChanged(v) {
alert(
'volume:'
+ v);
}
</
script
>
<
div
id
="MyDiv">
Nothing happened
</
div
>
<
p
>
<
input
id
="Button1"
type
="button"
value
="Start"
onclick
="Button1_onclick()"
/>
<
input
id
="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
)
]
public
enum
ObjectSafetyOptions
{
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)
]
public
interface
IObjectSafety
{
[
PreserveSig
]
long
GetInterfaceSafetyOptions(
ref
Guid
iid,
out
int
pdwSupportedOptions,
out
int
pdwEnabledOptions);
[
PreserveSig
]
long
SetInterfaceSafetyOptions(
ref
Guid
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
//
public
class
IObjectSafetyImpl
:
IObjectSafety
{
private
ObjectSafetyOptions
m_options =
ObjectSafetyOptions
.INTERFACESAFE_FOR_UNTRUSTED_CALLER |
ObjectSafetyOptions
.INTERFACESAFE_FOR_UNTRUSTED_DATA;
#region
[IObjectSafety implementation]
public
long
GetInterfaceSafetyOptions(
ref
Guid
iid,
out
int
pdwSupportedOptions,
out
int
pdwEnabledOptions)
{
pdwSupportedOptions = (
int
)m_options;
pdwEnabledOptions = (
int
)m_options;
return
0;
}
public
long
SetInterfaceSafetyOptions(
ref
Guid
iid,
int
dwOptionSetMask,
int
dwEnabledOptions)
{
return
0;
}
#endregion
};
}
并实现以下两个方法:
#region
Implementation of IObjectSafety
private
ObjectSafetyOptions
m_options =
ObjectSafetyOptions
.INTERFACESAFE_FOR_UNTRUSTED_CALLER |
ObjectSafetyOptions
.INTERFACESAFE_FOR_UNTRUSTED_DATA;
public
long
GetInterfaceSafetyOptions(
ref
Guid
iid,
out
int
pdwSupportedOptions,
out
int
pdwEnabledOptions)
{
pdwSupportedOptions = (
int
)m_options;
pdwEnabledOptions = (
int
)m_options;
return
0;
}
public
long
SetInterfaceSafetyOptions(
ref
Guid
iid,
int
dwOptionSetMask,
int
dwEnabledOptions)
{
return
0;
}
#endregion
源码下载
作者:Bosn Ma
E-mail: x@bosnma.com
说明: 本文章可以转载,但请保留原文。本文作者Bosn Ma,来源于
http://www.bosnma.com
如有问题欢迎到以上地址发表,获通过E-Mail与我联系。