Есть ли способ вернуть значение dotNetObject из пользовательского плагина 3ds Max?

StackOverflow https://stackoverflow.com/questions/421566

  •  05-07-2019
  •  | 
  •  

Вопрос

У меня есть пользовательский плагин для 3ds Max, который взаимодействует с некоторым управляемым кодом на серверной части.В некоторых случаях я хотел бы переслать управляемый объект в MAXScript для прямого взаимодействия, т. е.возвращает обернутый объект из одной из моих функций.

MAXScript способен относительно хорошо манипулировать управляемыми объектами напрямую с помощью другого плагина (msxdotNet), входящего в комплект Max (я использую 3ds Max 2008).Он в основном обертывает объект и использует отражение для поздних связанных вызовов, но он полностью самодостаточен и не имеет никакого доступа к sdk.Сама библиотека dll плагина также не предоставляет ничего, кроме минимального интерфейса, требуемого Max для добавления нескольких скриптовых классов верхнего уровня.

Скриптовые классы позволяют создавать экземпляр нового объекта с помощью конструктора

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

В моем случае у меня уже есть экземпляр объекта, который я хотел бы использовать.

Есть ли способ создать экземпляр оболочки dotNetObject из моего плагина, чтобы вернуться к максимальному значению?


В идеале, я хотел бы иметь вспомогательную функцию с сигнатурой (C ++ / CLI), подобной:

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

Некоторые основные гарантии, которые я могу дать:

  • Плагин msxdotNet уже загружен.
  • Плагин msxdotNet и мои управляемые сборки находятся в одном домене приложения.

Исходный код для плагина msxdotNet является включен в качестве образца sdk, но для удобства управления изменять его и перекомпилировать не представляется возможным.

Это было полезно?

Решение

Я решил эту проблему, используя тот факт, что любой объект CLR, обернутый dotNetObject, автоматически обернет возвращаемые значения (результаты метода и значения свойств) другой оболочкой.Это даже относится к статическим методам и свойствам типов CLR, обернутых dotNetClass.

Допустим, у меня уже есть метод в моем плагине, который позволяет мне выполнять произвольный MAXScript:

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

Теперь мне просто нужно сериализовать объект в строку и снова вернуться к активному объекту (ссылка на тот же объект, а не просто копия!).

Я делаю это, хватая GCHandle объекта, используя GCHandle::ToIntPtr чтобы преобразовать его во что-то блиттабельное и используя 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 раз длиннее самого кода.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top