• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C#COMObjectforUseInJavaScript/HTML,IncludingEventHandling

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

By Jerome Terry, 22 Apr 2009

Download source - 5.12 KB

Introduction

I wanted to be able to use a pre-built .NET object inside a web browser. After searching the web (including CodeProject), I found that a possible solution would be to create a .NET COM component and use the ActiveXObject in JavaScript to interact with the COM object. A Google search turned up many helpful articles, but nothing that showed how to create a COM component in C#, surface .NET events through COM, and use the COM object in JavaScript to my satisfaction. In this article, I will put together all the pieces to show how to implement a complete solution, to use C# COM objects inside JavaScript.

Overview

This article describes how to create a C# COM Object (using Visual Studio .NET 2005) that can be used in JavaScript inside a web browser (only tested on IE 8 RC on Windows Vista). Complete source code for the COM object, as well as a simple web page that demonstrates how to use the COM object is provided, including how to make calls into the COM Object, and how to handle .NET events raised from the COM object.

Creating the C# COM Library

Create a new C# Class Library project called MyComComponent, and enable the setting “Register for COM interop” in the build settings for the project. If you are using Vista, you will need to run Visual Studio as an administrator to build your project after changing this setting. Exclude Class1.cs from the project.
Add a class named MyComObject.cs to the project, change the access modifier to public, and import the System.Runtime.InteropServices namespace:

Copy Code
using System;
using System.Runtime.InteropServices;

namespace MyComComponent
{
    public class MyComObject
    {
    }
} 

Add the interfaces that define the operations and events that will be exposed to COM. Add empty interface definitions named IComObject and IComEvents to the MyComObject.cs file:

Copy Code
using System;
using System.Runtime.InteropServices;

namespace MyComComponent
{
    public class MyComObject
    {
    }

    public interface IComObject
    {
    }

    public interface IComEvents
    {
    }
}

Expose the MyComObject class and the IComObject and IComEvents interfaces to COM. First, add the attribute [ComVisible(true)] to the class and interfaces.

Copy Code
using System;
using System.Runtime.InteropServices;

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

    [ComVisible(true)]
    public interface IComObject
    {
    }

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

Since we are defining our own custom COM interface, we need to tell the Type Library Exporter to not generate an interface for us. To do this, add the ClassInterface attribute to the MyComObject class with value of ClassInterfaceType.None.

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

We need to tell the Type Library Exporter that the interface for IComEvents is IDispatch in order to get events to be raised out of our COM object. To do this, add the InterfaceType attribute to the IComEvents interface, with value of ComInterfaceType.InterfaceIsIDispatch.

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

Now we can start decorating the MyComObject with the interface definitions. IComObject is simple enough to implement, just by explicitly implementing it. The Type Library Exporter will automatically expose all events in the IComObject interface for us.

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

Adding the IComEvents interface is a little different. Use the ComSourceInterfaces attribute on the MyComObject class, with typeof(IComEvents) as the value. The ComSourceInterfaces attribute is used to define the list of interfaces that are exposed as COM event sources.

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

Each type exposed from COM has a globally unique ID. Since we haven't defined the GUID’s, the Type Library Exported will do this for us. However, we want to be able to use this GUID to load the type, so we will now add the GUIDs to all three types. Use the guidgen utility to do this.

We now have the code structure in place for a COM object that explicitly implements an interface, and has an events source interface defined. The code at this point should be something like:

Copy Code
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
    {
    }
}

Now we will add some methods to the interfaces. To IComObject, add a method called MyFirstComCommand that accepts a string as an argument and returns an integer, as well as a method called Dispose that has no parameters and no return value.

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

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

To IComEvents, add a single method called MyFirstEvent that accepts a string as an argument and has no return value. Note the absence of the event keyword.

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

All that’s left to do is to implement the methods and events in the MyComObject class. The implementation of MyFirstCommand just raises the MyFirstEvent event and returns a random number. The Dispose method displays a message box. Add the following code to the MyComComponent class, and add a reference to System.Windows.Forms.dll to the project:

Copy Code
[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");
}

Now we have a fully functional COM object, written in C#. The code for the COM object should look like this:

Copy Code
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);
    }
}

Creating an Instance of the COM Component

To use the COM component in a web page, embed an <object /> tag in the head of the page

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

Hooking Up Events to the COM Component

Hooking up the events from the COM component is a little tricky. What you need to do is embed a <script/> tag in the body of the web page as follows:

Copy Code
<script for="myComComponent" event="MyFirstEvent(args)" language="javascript">
function myComComponent::MyFirstEvent(args) {
}

The "for" attribute should be set to the name of instance of your COM component. The "event" attribute should be set to the JavaScript function signature for the event. The name of the JavaScript function is the instance name of your COM component, followed by double colons, followed by the JavaScript signature of the event.

Executing Commands on the COM Component

Here's the JavaScript code to execute MyFirstComCommand:

Copy Code
var returnCode = myComComponent.MyFirstComCommand("Hello World!");

Disposing of the COM Component

In Internet Explorer 8, the COM component is not destroyed until the web browser is fully closed - closing of the tab that contained the COM component does not dispose of the object! If the user continuously hits the refresh button, new instances of the COM component will be created, but the old instances won't be released until the web browser is closed. You can use the onunload event to detect when the page is unloaded, then dispose of your COM component.

In our example, the Dispose method we added could be used for this purpose. Just change the implementation of the Dispose method to clean up any resources used by the COM component. The implementation in this example just shows a Message Box, so we know when the Dispose method is getting called.

Putting it all Together

Below is the source code to a web page that creates an instance of the MyComComponent COM object, executes methods on the COM component, and listens for events from the COM component.

Copy Code
<html>
    <head>
        <title>My Com Component</title>
        <object id="myComComponent" name="myComComponent" 
		classid="clsid:4794D615-BE51-4a1e-B1BA-453F6E9337C4"></object>
        <script language="javascript" type="text/javascript">
            function myButton_click() {
                var returnCode = myComComponent.MyFirstComCommand(myArgs.value);
                var msg = "myComComponent.MyFirstComCommand returned " + returnCode;
                appendText(msg);
                appendText("\r\n");
            }
            
            function setText(txt) {
                myTextBox.value = txt;
            }
            
            function appendText(txt) {
                myTextBox.value = myTextBox.value + txt;
            }
            
            function MyComComponent_onload() {
                setText("");
                myComComponent.MyFirstComCommand("Hi");
            }
            
            function MyComComponent_onunload() {
                myComComponent.Dispose();
            }
        </script>
    </head>
    <body onload="MyComComponent_onload();" onunload="MyComComponent_onunload();">
        <h1>My Com Component</h1>
        <table>
            <tr>
                <td>
                    <button id="myButton" onclick="myButton_click();">Com Method</button>
                    <label>Args</label>
                    <textarea id="myArgs" rows="1" cols="16">Hello World!</textarea>
                </td>
            </tr>
            <tr>
                <td>
                    <textarea id="myTextBox" rows="10" cols="80"></textarea>
                </td>
            </tr>
        </table>
        
        <script for="myComComponent" event="MyFirstEvent(args)" language="javascript">
        function myComComponent::MyFirstEvent(args) {
            appendText("myComComponent raised MyFirstEvent. args: ");
            appendText(args);
            appendText("\r\n");
        }
        </script>
    </body>
</html>

Using the Code

To use the sample web page, you first need to compile the MyComComponent solution file. The generated assembly will automatically be registered for COM Interop when you build the solution, so you don't need to put the assembly in the same folder as the web page.

After building the solution, open the web page MyComComponent.htm in your browser (make sure ActiveX and JavaScript are enabled).

Links

History

  • 22 April 2009 - Original Post

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
使用3DES加密算法对数据进行加密C#类发布时间:2022-07-10
下一篇:
如何在C#中获得input文本框中的值发布时间:2022-07-10
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap