在 C# 中创建 COM/ActiveXObject,从 JScript 中使用,带有简单的事件 [英] Create COM/ActiveXObject in C#, use from JScript, with simple event

查看:10
本文介绍了在 C# 中创建 COM/ActiveXObject,从 JScript 中使用,带有简单的事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 C# 中创建一个 COM 对象,并通过 JScript 中的 IDispatch 使用它.这部分很简单.

I'd like to create a COM object in C#, and use it via IDispatch from JScript. That part is pretty simple.

我还想在 COM 对象上实现简单的回调,类似于可在浏览器中使用的 XmlHttpRequest 对象公开的事件.该模型允许 Javascript 像这样附加事件处理程序:

I also want to implement simple callbacks on the COM object, similar to the event exposed by the XmlHttpRequest object that is usable in a browser. That model allows Javascript to attach event handlers like this:

var xmlhttp = new ActiveXObject("MSXML.XMLHTTP"); 
xmlhttp.onReadyStateChange = function() {
  ...
};

我希望我的客户端 JScript 代码如下所示:

I want my client-side JScript code to look like this:

var myObject = new ActiveXObject("MyObject.ProgId");
myObject.onMyCustomEvent = function(..args here..) { 
   ...
};

C# 代码是什么样的?我想要一般情况 - 我希望能够将参数传递回 Javascript fn.

What does the C# code look like? I'd like the general case - I'd like to be able to pass arguments back to the Javascript fn.

我见过 如何使用 C# 编写的 ActiveX 控件在点击时在 JavaScript 中引发事件? ,但那里的答案看起来真的很难实现,而且使用起来也很复杂.

I've seen How can I make an ActiveX control written with C# raise events in JavaScript when clicked? , but the answers there look really complicated to implement, and complicated to use.

这篇文章看来,XMLHttpRequest事件不是COM 事件.onreadystatechangeIDispatch 类型的属性.当脚本客户端将该属性设置为函数时,JScript 将其编组为 IDispatch 对象.

From this article, it seems that XMLHttpRequest events are not COM events. The onreadystatechange is a property of type IDispatch. When script clients set that property to a function, JScript marshals it as an IDispatch object.

剩下的唯一问题是从 C# 调用 IDispatch.

The only problem that remains is then to invoke the IDispatch from C#.

推荐答案

既然是COM,就先定义一个接口.让我们保持简单.

Since it's COM, start by defining an interface. Let's keep it simple.

[Guid("a5ee0756-0cbb-4cf1-9a9c-509407d5eed6")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IGreet
{
    [DispId(1)]
    string Hello(string name);

    [DispId(2)]
    Object onHello { get; set; }
}

然后,实现:

[ProgId("Cheeso.Greet")]
[ComVisible(true)]
[Guid("bebcfaff-d2f4-4447-ac9f-91bf63b770d8")]
[ClassInterface(ClassInterfaceType.None)]
public partial class Greet : IGreet
{
    public Object onHello { get; set; }

    public String Hello(string name)
    {
        var r = FireEvent();
        return "Why, Hello, " + name + "!!!" + r;
    }
}

主要技巧是 FireEvent 方法.这对我有用.

The main trick is the FireEvent method. This worked for me.

    private string FireEvent()
    {
        if (onHello == null) return " (N/A)";
        onHello
            .GetType()
            .InvokeMember
            ("",
             BindingFlags.InvokeMethod,
             null,
             onHello,
             new object [] {});

        return "ok";
    }

一起编译,用 regasm 注册:

Compile that all together, register it with regasm:

%NET64%
egasm.exe Cheeso.Greet.dll /register /codebase

...然后像这样从 JScript 中使用它:

...And then use it from JScript like this:

var greet = new ActiveXObject("Cheeso.Greet"), response;
greet.onHello = function() {
    WScript.Echo("onHello (Javascript) invoked.");
};
response = greet.Hello("Fred");
WScript.Echo("response: " + response);

它有效.

您也可以从 VBScript 中调用它:

You can also call it from VBScript:

Sub onHello ()
    WScript.Echo("onHello (VBScript) invoked.")
End Sub

Dim greet
Set greet = WScript.CreateObject("Cheeso.Greet")
greet.onHello = GetRef("onHello")
Dim response
response = greet.Hello("Louise")
WScript.Echo("response: " &  response)

<小时>

要使用这种方法将参数从 C# 传递回 JScript,我认为对象需要是 IDispatch,但当然您可以将简单的值作为字符串、int 等封送返回,这些值按照您的预期进行封送.


To pass parameters back from C# to JScript with this approach, I think objects need to be IDispatch, but of course you can send back simple values marshaled as string, int, and so on which are marshaled as you would expect.

例如,修改 C# 代码以返回对自身的引用,以及数字 42.

For example, modify the C# code to send back a reference to itself, and the number 42.

        onHello
            .GetType()
            .InvokeMember
            ("",
             BindingFlags.InvokeMethod,
             null,
             onHello,
             new object [] { this, 42 });

然后,你可以像这样在 jscript 中得到它:

Then, you can get that in jscript like so:

greet.onHello = function(arg, num) {
    WScript.Echo("onHello (Javascript) invoked.");
    WScript.Echo("  num = " + num + "  stat=" + arg.status);
};

或者在 VBScript 中像这样:

Or in VBScript like so:

Sub onHello (obj, num)
    WScript.Echo("onHello (VBScript) invoked. status=" & obj.status )
    WScript.Echo("  num= " & num)
End Sub

注意:您可以定义您的 jscript 事件处理函数,以在调用事件"时接受比 C# 对象发送的更少的参数.根据我的经验,您需要在 VBScript 中设计事件处理程序以显式接受正确数量的参数.

NB: You can define your jscript event handler function to accept fewer args than are sent by the C# object when invoking the "event". In my experience you need to design the event handler in VBScript to explicitly accept the correct number of arguments.

这篇关于在 C# 中创建 COM/ActiveXObject,从 JScript 中使用,带有简单的事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆