0

我有一个用于 3ds Max 的自定义插件,它与后端的一些托管代码交互。在某些情况下,我想将托管对象转发到 MAXScript 以进行直接交互,即从我的一个函数返回一个包装的对象。

MAXScript 能够通过 Max 附带的另一个插件 (msxdotNet) 直接相对较好地操作托管对象(我使用的是 3ds Max 2008)。它基本上包装了一个对象并使用反射来进行后期绑定调用,但它完全是自包含的,没有任何 sdk 暴露。除了 Max 添加一些顶级脚本类所需的最小接口外,插件 dll 本身也没有暴露任何东西。

脚本类允许通过构造函数实例化一个新对象

local inst = (dotNetObject "MyPlugin.MyClass" 0 0 "arg3")

就我而言,我已经有一个我想使用的对象的实例。

有没有办法从我的插件中构造一个 dotNetObject 包装器的实例以返回 Max?


理想情况下,我想要一个带有(C++/CLI)签名的辅助函数,类似于:

Value* WrapObject(System::Object ^obj);

我可以做出的一些基本保证:

  • msxdotNet 插件已加载。
  • msxdotNet 插件和我的托管程序集位于同一个 AppDomain 中。

msxdotNet 插件的源代码作为sdk 示例包含在内,但出于管理/理智的考虑,修改它并重新编译它不是一种选择。

4

1 回答 1

2

我通过利用 dotNetObject 包装的任何 CLR 对象将自动用另一个包装器包装返回值(方法结果和属性值)这一事实解决了这个问题。这甚至适用于用 dotNetClass 包装的 CLR 类型的静态方法和属性。

假设我的插件中已经有了一个方法,可以让我执行任意 MAXScript:

Value* EvalScript(System::String ^script);

现在我只需要将一个对象序列化为一个字符串,然后再返回一个活动对象(对同一对象的引用,而不仅仅是一个副本!)。

我通过抓取GCHandle对象的 来做到这一点,GCHandle::ToIntPtr用于将其转换为可 blitable 的对象,并用于GCHandle::FromIntPtr在不同的上下文中实现相同的对象。当然,我正在处理中(并且在同一个应用程序域中)这样做,否则这是行不通的。

Value* WrapObject(System::Object ^obj)
{
    GCHandle handle = GCHandle::Alloc(obj)
    try
    {
        return EvalScript(System::String::Format(
            L"((dotNetClass \"System.Runtime.InteropServices.GCHandle\").FromIntPtr (dotNetObject \"System.IntPtr\" {0})).get_Target()",
            GCHandle::ToIntPtr(handle));
    }
    finally
    {
        handle.Free();
    }
}

我在实际代码中解释这一点的注释是实际代码的 10 倍以上。

于 2009-04-13T21:49:53.857 回答