我想在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。
我见过How can I make an ActiveX control written with C# raise events in JavaScript when clicked?,但那里的答案看起来实际上很复杂,而且使用起来很复杂。
从this article开始,似乎XMLHttpRequest事件不是COM事件。 onreadystatechange
是IDispatch
类型的属性。当脚本客户端将该属性设置为函数时,JScript将其编组为IDispatch对象。
剩下的唯一问题是从C#调用IDispatch。
答案 0 :(得分:14)
因为它是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,但是当然你可以发送回作为字符串,整数等编组的简单值,这些值按照你的预期进行编组。 / p>
例如,修改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#对象发送的更少的args。根据我的经验,您需要在VBScript中设计事件处理程序以明确接受正确数量的参数。
答案 1 :(得分: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
享受!