【问题标题】:Is there a way to return a dotNetObject value from a custom 3ds Max plugin?有没有办法从自定义 3ds Max 插件返回 dotNetObject 值?
【发布时间】:2010-09-30 02:39:54
【问题描述】:

我有一个用于 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 示例包含在内,但出于管理/理智的考虑,不能对其进行修改和重新编译。

【问题讨论】:

    标签: .net 3dsmax maxscript


    【解决方案1】:

    我通过利用 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 倍以上。

    【讨论】:

      猜你喜欢
      • 2021-10-19
      • 2019-03-07
      • 1970-01-01
      • 2023-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-20
      相关资源
      最近更新 更多