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

来源:互联网 发布:js给input数组赋值 编辑:程序博客网 时间:2024/05/30 20:08

 

 
 
                最近在忙微软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与我联系。
原创粉丝点击