9

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

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

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

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

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

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


我已经看到如何在单击时使用 JavaScript 中的 C# 引发事件编写 ActiveX 控件?,但是那里的答案看起来确实很难实现,而且使用起来也很复杂。


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

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

4

2 回答 2

15

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

[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方法。这对我有用。

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

        return "ok";
    }

一起编译,用 regasm 注册它:

%NET64%\regasm.exe Cheeso.Greet.dll /register /codebase

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

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

有用。

您也可以从 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 等进行封送处理,如您所期望的那样进行封送处理。

例如,修改 C# 代码以发回对自身的引用和数字 42。

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

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

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

或者像这样在 VBScript 中:

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

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

于 2012-06-24T05:22:56.347 回答
2

哇,哇!可能容易吗?

using System;
using System.EnterpriseServices;

[assembly: ApplicationName("Calculator")]
[assembly: ApplicationActivation(ActivationOption.Library)]
public class Calculator : ServicedComponent
{
    public int Add(int x, int y){ return (x + y); }
}

然后使用这些构建命令

 sn -k Calculator.snk           
 csc /t:library Calculator.cs
 regsvcs Calculator.dll

在 jscript (wsh) 上:

c = new ActiveXObject("Calculator");
WScript.Echo(typeof(c));  // output: object
WScript.Echo(c.Add(4,1)); // output: 5

来源:msdn

享受!

于 2015-02-15T12:59:21.707 回答