使用C#构建带事件的签名ActiveX组件(一)

2009年4月23日星期四

使用C#构建带事件的签名ActiveX组件(一)

 



 


 

                最近在忙微软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)]

    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定义三个事件,分别为OnRecorderStartedOnRecorderStoppedOnRecorderVolumeChanged(带一个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。

 


图2 编译ActiveX项目生成dll文件

然后我们启动命令行CMD(如果是Vista/Win7使用管理员方式打开),使用以下命令注册控件.

C:\>D:                       //转到.dll所在目录,笔者为了方便将.dll copy到了D盘根目录
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>

<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

源码下载



请到原文地址下载


http://www.bosnma.com/welcome/showArticle.aspx?ID=117


关于




作者:Bosn Ma

E-mail: x@bosnma.com

说明: 本文章可以转载,但请保留原文。本文作者Bosn Ma,来源于http://www.bosnma.com

原文地址: http://www.bosnma.com/welcome/showArticle.aspx?ID=117

如有问题欢迎到以上地址发表,获通过E-Mail与我联系。

0 评论:

发表评论