カスタム3ds MaxプラグインからdotNetObject値を返す方法はありますか?
質問
3ds Maxのカスタムプラグインを使用して、バックエンドのマネージコードとインターフェイスします。状況によっては、管理されたオブジェクトに沿ってMAXScriptに直接やり取りしたい、つまり、関数の1つからラップされたオブジェクトを返したいと思います。
MAXScriptは、Maxに含まれる別のプラグイン(msxdotNet)を介して、比較的簡単に管理オブジェクトを直接操作できます(3ds Max 2008を使用しています)。基本的にオブジェクトをラップし、レイトバインドコールにリフレクションを使用しますが、完全に自己完結型であり、sdkにさらされていません。プラグインdll自体も、いくつかのトップレベルのスクリプトクラスを追加するためにMaxが必要とする最小限のインターフェース以外は公開しません。
スクリプトクラスを使用すると、コンストラクタを介して新しいオブジェクトをインスタンス化できます
local inst = (dotNetObject "MyPlugin.MyClass" 0 0 "arg3")
私の場合、使用したいオブジェクトのインスタンスが既にあります。
Maxに戻るために、プラグイン内からdotNetObjectラッパーのインスタンスを構築する方法はありますか
理想的には、次のような(C ++ / CLI)シグネチャを持つヘルパー関数が必要です:
Value* WrapObject(System::Object ^obj);
私ができる基本的な保証:
- msxdotNetプラグインはすでにロードされています。
- msxdotNetプラグインとマネージアセンブリは同じAppDomainにあります。
msxdotNetプラグインのソースは SDKサンプルとして含まれていますが、管理/健全性のために、それを変更して再コンパイルすることはオプションではありません。
解決
dotNetObjectでラップされたCLRオブジェクトは、戻り値(メソッドの結果とプロパティ値)を別のラッパーで自動的にラップするという事実を活用して、これを解決しました。これは、dotNetClassでラップされたCLR型の静的メソッドとプロパティにも適用されます。
プラグインに任意のMAXScriptを実行できるメソッドが既にあるとしましょう:
Value* EvalScript(System::String ^script);
今、オブジェクトを文字列にシリアル化して、アクティブなオブジェクト(コピーではなく、同じオブジェクトへの参照!)に戻す必要があります。
これを行うには、オブジェクトの GCHandle
を取得し、 GCHandle :: ToIntPtr
を使用してblittableに変換し、 GCHandle :: FromIntPtr を使用します。 code>は、同じオブジェクトを異なるコンテキストで具体化します。もちろん、私はこれをプロセス内(および同じアプリドメイン内)で行っていますが、そうしないと機能しません。
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倍以上です。