通过COM将C#类实例从JavaScript传递回托管代码
下面的代码显示了我的问题的基本轮廓。我在表单中托管一个WebBrowser控件,并使用两种方法提供一个通过COM将C#类实例从JavaScript传递回托管代码,c#,javascript,.net,com,webbrowser-control,C#,Javascript,.net,Com,Webbrowser Control,下面的代码显示了我的问题的基本轮廓。我在表单中托管一个WebBrowser控件,并使用两种方法提供一个ObjectForScripting,GiveMeAGizmo和GiveMeAGizmoUser。两个方法都返回各自的类实例: [ComVisible] 公共类Gizmo { 公共字符串名称{get;set;} } [ComVisible] 公共类鼠标器 { 公共void doSomethingWith(对象oGizmo) { Gizmo g=(Gizmo)oGizmo; System.Diag
ObjectForScripting
,GiveMeAGizmo
和GiveMeAGizmoUser
。两个方法都返回各自的类实例:
[ComVisible]
公共类Gizmo
{
公共字符串名称{get;set;}
}
[ComVisible]
公共类鼠标器
{
公共void doSomethingWith(对象oGizmo)
{
Gizmo g=(Gizmo)oGizmo;
System.Diagnostics.Debug.WriteLine(g.name);
}
}
在JavaScript中,我创建了两个类的一个实例,但我需要将第一个实例传递给第二个实例上的一个方法。JS代码看起来有点像这样:
var
//返回Gizmo实例
gizmo=window.external.giveMeagzmo(),
//返回GizmoUser实例
gUser=window.external.GiveMeAGizmoUser();
gizmo.name='hello';
//将Gizmo实例传递回C#代码
gUser.doSomethingWith(gizmo);
这就是我碰壁的地方。我的C#methodGizmoUser.doSomethingWith()
无法将对象强制转换回Gizmo类型。它抛出以下错误:
无法将“System.\u ComObject”类型的COM对象强制转换为接口类型“Gizmo”
不确定如何继续,我尝试了一些其他方法:
- 安全铸造
Gizmo g=oGizmo作为Gizmo代码>(
为g
)null
- 让类实现
并调用IDispatch
,如图所示。成员“name”为InvokeMember
null
我需要它来处理低于4.0的.NET framework版本,因此我不能使用
动态
。有人知道我该怎么做吗?你需要做两件事
真有趣。当我们在
doSomethingWith
中接收到oGizmo
对象时,它属于Windows运行时对象的类型。这种行为在JavaScript和VBScript之间是一致的
现在,如果我们在GiveMeAGizmo()
方法的返回值上显式指定marshallas(UnmanagedType.IUnknown)
,一切正常,那么对象可以在doSomethingWith
内部被强制转换回Gizmo
:
[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
(将对象封送为COMVARIANT
)的默认值,问题又来了
因此,到目前为止,这种COM互操作行为有一个解决方法,但没有合理的解释
[更新]下面还有一些实验。请注意如何成功获取gizmo1
,而gizmo2
则不是:
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安全权限集有关,这些权限集是由.强制实施的。
oGizmo在调试器中是什么样子的?或者它总是空的?@Abhinav:它的类型是System.\uu ComObject
。如果我尝试oGizmo.GetType().GetMembers()
,它将返回null
(与GetProperties()
和GetMethods()
相同)。是否可以显示'giveMeagzmo()“代码?你真的试过了吗?在OP的情况下,它不起作用,因为他的原始对象类型Gizmo
已经是一个托管对象。不知何故,当从JavaScript传回时,它被包装为“Windows运行时对象”。出于同样的原因,Gizmo g=(Gizmo)marshall.CreateWrapperOfType(oGizmo,typeof(Gizmo))
也不起作用。你在这里付出了额外的努力,这给我留下了深刻的印象。据我所知,你的答案非常有效,所以绿色的记号是你的。@AndyE,没问题。WebBrowser
我特别感兴趣的是周围的一切:)啊,我会记住下一个问题;-)。我正在从事的这个项目使用了很多先进的技术来破解WebBrowser控件,但是我们在一些复杂的事情上已经被卡住了好几次(老实说,我不是.NET方面的专家!)。