问题描述
我想在 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 事件.onreadystatechange
是 IDispatch
类型的属性.当脚本客户端将该属性设置为函数时,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 中使用,带有简单的事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!