通过COM将C#类实例从JavaScript传递回托管代码 [英] Passing a C# class instance back to managed code from JavaScript via COM
问题描述
我的问题的基本轮廓显示在下面的代码中。我正在以某种形式托管WebBrowser控件,并提供具有两种方法的 ObjectForScripting
: GiveMeAGizmo
和 GiveMeAGizmoUser
。两种方法都返回各自的类实例:
The basic outline of my problem is shown in the code below. I'm hosting a WebBrowser control in a form and providing an ObjectForScripting
with two methods: GiveMeAGizmo
and GiveMeAGizmoUser
. Both methods return the respective class instances:
[ComVisible]
public class Gizmo
{
public string name { get; set; }
}
[ComVisible]
public class GizmoUser
{
public void doSomethingWith(object oGizmo)
{
Gizmo g = (Gizmo) oGizmo;
System.Diagnostics.Debug.WriteLine(g.name);
}
}
在JavaScript中,我创建了两个类的实例,但是我需要将第一个实例传递给第二个实例的方法。 JS代码看起来像这样:
In JavaScript, I create an instance of both classes, but I need to pass the first instance to a method on the second instance. The JS code looks a little like this:
var
// Returns a Gizmo instance
gizmo = window.external.GiveMeAGizmo(),
// Returns a GizmoUser instance
gUser = window.external.GiveMeAGizmoUser();
gizmo.name = 'hello';
// Passes Gizmo instance back to C# code
gUser.doSomethingWith(gizmo);
这是我碰壁的地方。我的C#方法 GizmoUser.doSomethingWith()
无法将对象转换回Gizmo类型。它引发以下错误:
This is where I've hit a wall. My C# method GizmoUser.doSomethingWith()
cannot cast the object back to a Gizmo type. It throws the following error:
无法将类型为'System .__ ComObject'的COM对象转换为接口类型'Gizmo'
Unable to cast COM object of type 'System.__ComObject' to interface type 'Gizmo'
不确定如何进行操作,我尝试了其他几件事:
Unsure how to proceed, I tried a couple of other things:
- 安全转换
Gizmo g = oGizmo作为Gizmo;
(g
为null
) - 让类实现
IDispatch
并调用InvokeMember
,如在此处解释。成员名称为null
。
- Safe casting
Gizmo g = oGizmo as Gizmo;
(g
isnull
) - Having the classes implement
IDispatch
and callingInvokeMember
, as explained here. The member "name" isnull
.
我需要使用此名称.NET Framework版本低于4.0,所以我不能使用 dynamic
。有人知道我该如何工作吗?
I need this to work with .NET framework version lower than 4.0, so I cannot use dynamic
. Does anybody know how I can get this working?
推荐答案
多么有趣。当我们在 doSomethingWith
中收到 oGizmo
对象时,它的类型为 Windows运行时对象
。这种行为在JavaScript和VBScript之间是一致的。
How interesting. When we receive the oGizmo
object back in doSomethingWith
, it is of the type Windows Runtime Object
. This behavior is consistent between JavaScript and VBScript.
现在,如果我们明确指定 MarshalAs(UnmanagedType.IUnknown)
关于 GiveMeAGizmo()
方法的返回值,一切正常,该对象可以转换回 Gizmo
在 doSomethingWith
内:
Now, if we explicitly specify MarshalAs(UnmanagedType.IUnknown)
on the return value of the GiveMeAGizmo()
method, everything works fine, the object can be cast back to Gizmo
inside doSomethingWith
:
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)]
public class ObjectForScripting
{
[return: MarshalAs(UnmanagedType.IUnknown)]
public object GiveMeAGizmo()
{
return new Gizmo();
}
public object GiveMeAGizmoUser()
{
return new GizmoUser();
}
}
如果我们指定,仍然UnmanagedType.IDispatch
或 UnmanagedType.Struct
(将对象编组为COM VARIANT
),问题又回来了。
Still, if we specify UnmanagedType.IDispatch
or UnmanagedType.Struct
(the default one which marshals the object as COM VARIANT
), the problem is back.
因此,目前有一种解决方法,但是对于这种COM互操作行为尚无合理的解释。
Thus, there's a workaround, but no reasonable explanation for such COM interop behavior, so far.
[更新] ,下面还有其他一些实验。请注意如何成功获取 gizmo1
,而 gizmo2
却不成功:
[UPDATE] A few more experiments, below. Note how obtaining gizmo1
is successful, while gizmo2
is not:
C#:
// pass a Gizmo object to JavaScript
this.webBrowser.Document.InvokeScript("SetGizmo", new Object[] { new Gizmo()});
// get it back, this works
var gizmo1 = (Gizmo)this.webBrowser.Document.InvokeScript("GetGizmo");
// get a new Gizmo, via window.external.GiveMeAGizmo()
// this fails
var gizmo2 = (Gizmo)this.webBrowser.Document.InvokeScript("GetGizmo2");
JavaScript:
var _gizmo;
function SetGizmo(gizmo) { _gizmo = gizmo; }
function GetGizmo() { return _gizmo; }
function GetGizmo2() { return window.external.GiveMeAGizmo(); }
这只是一个猜测,但我认为这种行为可能与.NET安全权限有关设置,由 WebBrowser.ObjectForScripting
。
It's only a guess, but I think such behavior might have something to do with .NET security permission sets, imposed by WebBrowser.ObjectForScripting
.
这篇关于通过COM将C#类实例从JavaScript传递回托管代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!