3D Studio Max SDK .NET / C++ 通过 NativePointer 和 Marshal 的互操作性
3D Studio Max SDK .NET / C++ interoperability via NativePointer and Marshal
我正在为 3D Studio Max 开发一个插件。它的核心是用C++编写的,用户界面是用WPF编写的。 Autodesk 提供了其 C++ 类型的 .NET 包装器,每个包装器都实现了一个 INativePointer 接口,提供了一个 System::IntPtr NativePointer 属性。
我曾希望使用 C# 和 C++/CLI 将对这些对象的引用从 C++ 传递到 .NET。但是,NativePointer 返回的地址很接近,但不太正确。例如:
// create instance of a CustAttribute, which max exposed to .NET as ICustAttribute
object instance = CoreInterface.CreateInstance(SClassID.CustAttribute, myCustomAttributeClassID );
// The C++ constructor of my custom attribute runs and the address of the
// created object is 0x45001000 for example.
// cast to ICustAttrib (successfully) - all methods on attrib work.
Autodesk.Max.ICustAttrib attrib = (Autodesk.Max.ICustAttrib)instance;
// get the native pointer
System.IntPtr ptr = attrib.NativePointer;
// Strangely, ptr is equal to 0x45001009
// call my C++/CLI function which casts ICustAttrib to CustAttrib and modifies object
Support.ModifyAttribute( ptr );
Crash! ptr is off by 9 bytes.
奇怪的是,我的 Support.ModifyAttribute( ) 方法(将地址转换为 CustAttrib)崩溃了。地址的值比创建的对象的实际值大 9 个字节。这对于我测试过的所有 3D Studio Max 包装器类型都是一致的。结果我的代码崩溃了。
我的问题是:如何成功地将 3D Studio Max .NET 包装器对象传递回 C++ 以实现互操作性? 3D Studio Max SDK 没有通过示例或文档说明如何将对象的 .NET 实例转换为 C++ 实例,尽管这必须有效,因为它已在整个 SDK 中完成。还有其他人对此有好运吗?
我注意到 this 问题相关但未得到解答。
我正在使用 3D Studio Max 2016 和 VS2013。
在查看 3D Studio Max 提供的可用托管程序集后,我发现 Autodesk.Max.Wrappers.DLL 程序集包含一个名为 CustomMarshaler__typename 的 类 集合,每个类型对应一个通过包装器公开的类型.我能够使用它们来满足我获取本机地址的要求:
// create instance of a CustAttribute, which max exposed to .NET as ICustAttribute
object instance = CoreInterface.CreateInstance(SClassID.CustAttribute, myCustomAttributeClassID );
// The C++ constructor of my custom attribute runs and the address of the
// created object is 0x45001000 for example.
// cast to ICustAttrib (successfully) - all methods on attrib work.
Autodesk.Max.ICustAttrib attrib = (Autodesk.Max.ICustAttrib)instance;
// Get the marshaler for the type - not sure what the string is for
ICustomMarshaler marshaler = Autodesk.Max.Wrappers.CustomMarshalerCustAttrib.GetInstance("what goes there?");
// get the native pointer via the custom marshaler - it isn't clear if there is any type checking internally since MarshalManagedToNative takes on object
System.IntPtr ptr = marshaler.MarshalManagedToNative(attrib);
// Hurrah - ptr is equal to 0x45001000
// call my C++/CLI function which casts intptr to native ::CustAttrib type and modifies it via native methods.
Support.ModifyAttribute( ptr );
// Huzzah - attribute is correctly modified in native C++
效果不错,太棒了。它适用于所有提供的包装器类型:
Autodesk.Max.Wrappers.CustomMarshalerINode.GetInstance("what goes there?");
Autodesk.Max.Wrappers.CustomMarshalerModifier.GetInstance("what goes there?");
Autodesk.Max.Wrappers.CustomMarshalerGUP.GetInstance("what goes there?");
唯一令人烦恼的问题是 CustomMarshalerCustAttrib.GetInstance( String ) 中的字符串的用途。
希望有人会觉得这有用!
我正在为 3D Studio Max 开发一个插件。它的核心是用C++编写的,用户界面是用WPF编写的。 Autodesk 提供了其 C++ 类型的 .NET 包装器,每个包装器都实现了一个 INativePointer 接口,提供了一个 System::IntPtr NativePointer 属性。
我曾希望使用 C# 和 C++/CLI 将对这些对象的引用从 C++ 传递到 .NET。但是,NativePointer 返回的地址很接近,但不太正确。例如:
// create instance of a CustAttribute, which max exposed to .NET as ICustAttribute
object instance = CoreInterface.CreateInstance(SClassID.CustAttribute, myCustomAttributeClassID );
// The C++ constructor of my custom attribute runs and the address of the
// created object is 0x45001000 for example.
// cast to ICustAttrib (successfully) - all methods on attrib work.
Autodesk.Max.ICustAttrib attrib = (Autodesk.Max.ICustAttrib)instance;
// get the native pointer
System.IntPtr ptr = attrib.NativePointer;
// Strangely, ptr is equal to 0x45001009
// call my C++/CLI function which casts ICustAttrib to CustAttrib and modifies object
Support.ModifyAttribute( ptr );
Crash! ptr is off by 9 bytes.
奇怪的是,我的 Support.ModifyAttribute( ) 方法(将地址转换为 CustAttrib)崩溃了。地址的值比创建的对象的实际值大 9 个字节。这对于我测试过的所有 3D Studio Max 包装器类型都是一致的。结果我的代码崩溃了。
我的问题是:如何成功地将 3D Studio Max .NET 包装器对象传递回 C++ 以实现互操作性? 3D Studio Max SDK 没有通过示例或文档说明如何将对象的 .NET 实例转换为 C++ 实例,尽管这必须有效,因为它已在整个 SDK 中完成。还有其他人对此有好运吗?
我注意到 this 问题相关但未得到解答。
我正在使用 3D Studio Max 2016 和 VS2013。
在查看 3D Studio Max 提供的可用托管程序集后,我发现 Autodesk.Max.Wrappers.DLL 程序集包含一个名为 CustomMarshaler__typename 的 类 集合,每个类型对应一个通过包装器公开的类型.我能够使用它们来满足我获取本机地址的要求:
// create instance of a CustAttribute, which max exposed to .NET as ICustAttribute
object instance = CoreInterface.CreateInstance(SClassID.CustAttribute, myCustomAttributeClassID );
// The C++ constructor of my custom attribute runs and the address of the
// created object is 0x45001000 for example.
// cast to ICustAttrib (successfully) - all methods on attrib work.
Autodesk.Max.ICustAttrib attrib = (Autodesk.Max.ICustAttrib)instance;
// Get the marshaler for the type - not sure what the string is for
ICustomMarshaler marshaler = Autodesk.Max.Wrappers.CustomMarshalerCustAttrib.GetInstance("what goes there?");
// get the native pointer via the custom marshaler - it isn't clear if there is any type checking internally since MarshalManagedToNative takes on object
System.IntPtr ptr = marshaler.MarshalManagedToNative(attrib);
// Hurrah - ptr is equal to 0x45001000
// call my C++/CLI function which casts intptr to native ::CustAttrib type and modifies it via native methods.
Support.ModifyAttribute( ptr );
// Huzzah - attribute is correctly modified in native C++
效果不错,太棒了。它适用于所有提供的包装器类型:
Autodesk.Max.Wrappers.CustomMarshalerINode.GetInstance("what goes there?");
Autodesk.Max.Wrappers.CustomMarshalerModifier.GetInstance("what goes there?");
Autodesk.Max.Wrappers.CustomMarshalerGUP.GetInstance("what goes there?");
唯一令人烦恼的问题是 CustomMarshalerCustAttrib.GetInstance( String ) 中的字符串的用途。
希望有人会觉得这有用!