通过COM将C#类实例从JavaScript传递回托管代码 [英] Passing a C# class instance back to managed code from JavaScript via COM

查看:113
本文介绍了通过COM将C#类实例从JavaScript传递回托管代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题的基本轮廓显示在下面的代码中。我正在以某种形式托管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 is null)
  • Having the classes implement IDispatch and calling InvokeMember, as explained here. The member "name" is null.

我需要使用此名称.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆