65.9K
CodeProject 正在变化。 阅读更多。
Home

C# COM 对象供 JavaScript / HTML 使用,包括事件处理

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (29投票s)

2009年4月22日

CPOL

6分钟阅读

viewsIcon

190084

downloadIcon

2482

如何创建 C# COM 对象供 JavaScript / HTML 使用的完整示例,包括事件处理

引言

我希望能在 Web 浏览器中使用预先构建的 .NET 对象。在搜索了网络(包括 CodeProject)后,我发现一个可能的解决方案是创建一个 .NET COM 组件,并在 JavaScript 中使用 ActiveXObject 来与 COM 对象交互。通过 Google 搜索,我找到了许多有用的文章,但没有一篇能让我满意地展示如何用 C# 创建 COM 组件,如何通过 COM 暴露 .NET 事件,以及如何在 JavaScript 中使用 COM 对象。在本文中,我将把所有这些零散的知识点整合起来,展示如何实现一个完整的解决方案,在 JavaScript 中使用 C# COM 对象。

概述

本文介绍了如何创建一个 C# COM 对象(使用 Visual Studio .NET 2005),该对象可以在 Web 浏览器中的 JavaScript 中使用(仅在 Windows Vista 上的 IE 8 RC 上进行了测试)。文章提供了 COM 对象和演示如何使用该 COM 对象的简单网页的完整源代码,包括如何调用 COM 对象的方法,以及如何处理 COM 对象引发的 .NET 事件。

创建 C# COM 库

创建一个新的 C# 类库项目,名为 `MyComComponent`,并在项目的生成设置中启用“Register for COM interop”选项。如果您使用的是 Vista,在更改此设置后,您需要以管理员身份运行 Visual Studio 来生成您的项目。从项目中排除 `Class1.cs`。
向项目中添加一个名为 `MyComObject.cs` 的类,将访问修饰符更改为 `public`,并导入 `System.Runtime.InteropServices` 命名空间。

using System;
using System.Runtime.InteropServices;

namespace MyComComponent
{
    public class MyComObject
    {
    }
} 

添加用于定义将暴露给 COM 的操作和事件的接口。在 `MyComObject.cs` 文件中添加名为 `IComObject` 和 `IComEvents` 的空接口定义。

using System;
using System.Runtime.InteropServices;

namespace MyComComponent
{
    public class MyComObject
    {
    }

    public interface IComObject
    {
    }

    public interface IComEvents
    {
    }
}

将 `MyComObject` 类以及 `IComObject` 和 `IComEvents` 接口暴露给 COM。首先,为类和接口添加 `[ComVisible(true)]` 属性。

using System;
using System.Runtime.InteropServices;

namespace MyComComponent
{
    [ComVisible(true)]
    public class MyComObject
    {
    }

    [ComVisible(true)]
    public interface IComObject
    {
    }

    [ComVisible(true)]
    public interface IComEvents
    {
    }
}

由于我们定义了自己的自定义 COM 接口,我们需要告诉类型库导出器不要为我们生成接口。要做到这一点,请为 `MyComObject` 类添加 `ClassInterface` 属性,其值为 `ClassInterfaceType.None`。

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class MyComObject
{
}

我们需要告诉类型库导出器 `IComEvents` 接口是 `IDispatch`,以便从我们的 COM 对象引发事件。要做到这一点,请为 `IComEvents` 接口添加 `InterfaceType` 属性,其值为 `ComInterfaceType.InterfaceIsIDispatch`。

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IComEvents
{
}

现在我们可以开始用接口定义来装饰 `MyComObject` 了。`IComObject` 接口的实现相对简单,只需显式实现即可。类型库导出器将自动为我们公开 `IComObject` 接口中的所有事件。

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class MyComObject : IComObject
{
}

添加 `IComEvents` 接口略有不同。在 `MyComObject` 类上使用 `ComSourceInterfaces` 属性,其值为 `typeof(IComEvents)`。`ComSourceInterfaces` 属性用于定义作为 COM 事件源公开的接口列表。

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IComEvents))]
public class MyComObject : IComObject
{
}

从 COM 暴露的每个类型都有一个全局唯一标识符 (GUID)。由于我们尚未定义 GUID,类型库导出器将为我们完成此操作。但是,我们需要能够使用此 GUID 来加载类型,因此我们将现在为所有三个类型添加 GUID。请使用 guidgen 工具来完成此操作。

此时,我们已经具备了用于 COM 对象的代码结构,该对象显式实现了一个接口,并定义了一个事件源接口。此时的代码应该类似于:

using System;
using System.Runtime.InteropServices;

namespace MyComComponent
{
    [Guid("4794D615-BE51-4a1e-B1BA-453F6E9337C4")]
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(IComEvents))]
    public class MyComObject : IComObject
    {
    }

    [Guid("4B3AE7D8-FB6A-4558-8A96-BF82B54F329C")]
    [ComVisible(true)]
    public interface IComObject
    {
    }

    [Guid("ECA5DD1D-096E-440c-BA6A-0118D351650B")]
    [ComVisible(true)]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IComEvents
    {
    }
}

现在我们将向接口添加一些方法。向 `IComObject` 添加一个名为 `MyFirstComCommand` 的方法,该方法接受一个 `string` 参数并返回一个整数,以及一个名为 `Dispose` 的方法,该方法没有参数且没有返回值。

[Guid("4B3AE7D8-FB6A-4558-8A96-BF82B54F329C")]
[ComVisible(true)]
public interface IComObject
{ 
    [DispId(0x10000001)]
    int MyFirstComCommand(string arg);

    [DispId(0x10000002)]
    void Dispose();
}

向 `IComEvents` 添加一个名为 `MyFirstEvent` 的方法,该方法接受一个 `string` 参数且没有返回值。请注意 `event` 关键字的缺失。

[Guid("ECA5DD1D-096E-440c-BA6A-0118D351650B")]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IComEvents
{
    [DispId(0x00000001)]
    void MyFirstEvent(string args);
}

剩下要做的就是在 `MyComObject` 类中实现方法和事件。`MyFirstCommand` 的实现只是引发 `MyFirstEvent` 事件并返回一个随机数。`Dispose` 方法显示一个消息框。将以下代码添加到 `MyComComponent` 类中,并向项目中添加对 `System.Windows.Forms.dll` 的引用。

[ComVisible(false)]
public delegate void MyFirstEventHandler(string args);

public event MyFirstEventHandler MyFirstEvent;

public int MyFirstComCommand(string arg)
{
    if (MyFirstEvent != null)
        MyFirstEvent(arg);
    return (int)DateTime.Now.Ticks;
}

public void Dispose()
{
    System.Windows.Forms.MessageBox.Show("MyComComponent is now disposed");
}

现在我们有了一个功能齐全的 COM 对象,用 C# 编写。COM 对象的代码应如下所示:

using System;
using System.Runtime.InteropServices;

namespace MyComComponent
{
    [Guid("4794D615-BE51-4a1e-B1BA-453F6E9337C4")]
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(IComEvents))]
    public class MyComObject : IComObject
    {
        [ComVisible(false)]
        public delegate void MyFirstEventHandler(string args);

        public event MyFirstEventHandler MyFirstEvent;

        public int MyFirstComCommand(string arg)
        {
            if (MyFirstEvent != null)
                MyFirstEvent(arg);
            return (int)DateTime.Now.Ticks;
        }

        public void Dispose()
        {
            System.Windows.Forms.MessageBox.Show("MyComComponent is now disposed");
        }
    }

    [Guid("4B3AE7D8-FB6A-4558-8A96-BF82B54F329C")]
    [ComVisible(true)]
    public interface IComObject
    {
        [DispId(0x10000001)]
        int MyFirstComCommand(string arg);

        [DispId(0x10000002)]
        void Dispose();
    }

    [Guid("ECA5DD1D-096E-440c-BA6A-0118D351650B")]
    [ComVisible(true)]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IComEvents
    {
        [DispId(0x00000001)]
        void MyFirstEvent(string args);
    }
}

创建 COM 组件的实例

要在网页中使用 COM 组件,请在页面的 `` 中嵌入一个 `` 标签。

<object name="myComComponent" id="myComComponent" 
	classid="clsid:4794D615-BE51-4a1e-B1BA-453F6E9337C4" />

连接 COM 组件的事件

连接 COM 组件的事件有点棘手。您需要做的是在网页的 `` 中嵌入一个 `

© . All rights reserved.