Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过COM将C#类实例从JavaScript传递回托管代码_C#_Javascript_.net_Com_Webbrowser Control - Fatal编程技术网

通过COM将C#类实例从JavaScript传递回托管代码

通过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

下面的代码显示了我的问题的基本轮廓。我在表单中托管一个WebBrowser控件,并使用两种方法提供一个
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#method
GizmoUser.doSomethingWith()
无法将对象强制转换回Gizmo类型。它抛出以下错误:

无法将“System.\u ComObject”类型的COM对象强制转换为接口类型“Gizmo”

不确定如何继续,我尝试了一些其他方法:

  • 安全铸造
    Gizmo g=oGizmo作为Gizmo
    g
    null
  • 让类实现
    IDispatch
    并调用
    InvokeMember
    ,如图所示。成员“name”为
    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
    (将对象封送为COM
    VARIANT
    )的默认值,问题又来了

    因此,到目前为止,这种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方面的专家!)。