.net 如何将托管对象发送到本机函数以使用它?

.net 如何将托管对象发送到本机函数以使用它?,.net,c++-cli,unmanaged,managed,mixed-mode,.net,C++ Cli,Unmanaged,Managed,Mixed Mode,如何将托管对象发送到本机函数以使用它 void managed_function() { Object^ obj = gcnew Object(); void* ptr = obj ??? // How to convert Managed object to void*? unmanaged_function(ptr); } // The parameter type should be void* and I can not change the type. // This

如何将托管对象发送到本机函数以使用它

void managed_function()
{
  Object^ obj = gcnew Object();

  void* ptr = obj ??? // How to convert Managed object to void*?

  unmanaged_function(ptr);
}

// The parameter type should be void* and I can not change the type.
// This function is native but it uses managed object. Because type of ptr could not be 
// Object^ I called it "Unmanaged Function".
void unmanaged_function(void* ptr)
{
  Object^ obj = ptr ??? // How to convert void* to Managed object?

  obj->SomeManagedMethods();
}

在谷歌搜索、阅读MSDN并尝试一些代码之后,我发现这个方法可以将托管对象传递给非托管函数

这些方法显示了如何将Object^转换为void*并将void*转换为Object^

using namespace System;
using namespace System::Runtime::InteropServices;

void managed_function() 
{ 
  Object^ obj = gcnew Object();

  // Convert Object^ to void*
  GCHandle handle = GCHandle::Alloc(obj);
  IntPtr pointer = GCHandle::ToIntPtr(handle);
  void* ptr = pointer.ToPointer();

  unmanaged_function(ptr);

  handle.Free();
} 

void unmanaged_function(void* ptr) 
{
  // Convert void* to Object^
  IntPtr pointer(ptr);
  GCHandle handle = GCHandle::FromIntPtr(pointer);
  Object^ obj = (Object^)handle.Target;

  obj->SomeManagedMethods();
} 

注意:如果“unmanaged_function”具有可变参数,则此方法将不起作用。

更干净、更好的方法是使用模板

MSDN的一句话:

gcroot模板是使用值类System::Runtime::InteropServices::GCHandle的功能实现的,它向垃圾收集堆提供“句柄”。请注意,句柄本身不会被垃圾收集,并且在gcroot类中的析构函数不再使用时会被释放(不能手动调用此析构函数)。如果在本机堆上实例化gcroot对象,则必须对该资源调用delete

您的示例代码适用于使用
gcroot
(该代码使用VS 2010编译和运行):

使用名称空间系统;
使用名称空间System::Runtime::InteropServices;
公共引用类SomeManagedObject
{
公众:
字符串^数据;
SomeManagedObject()
{
data=“初始数据”;
}
void SomeManagedMethods()
{
data=“已更改的数据”;
}
};
void非托管函数(void*ptr)
{
gcroot&obj=*((gcroot*)ptr);
obj->SomeManagedMethods();
} 
void托管函数()
{ 
//gcroot处理所有分配/解除分配和转换
gcroot*pObj=新的gcroot();
*pObj=gcnew SomeManagedObject();
非托管_函数(pObj);
删除pObj;
} 

“参数应为void*,我无法更改类型。”这意味着什么?如果函数是本机函数,它如何知道托管指针?(
Object^
)您可以使用Marshal::GetFunctionPointerForDelegate()创建一个可以传递给本机代码的函数指针。请确保将委托对象存储在某个位置,这样它就不会被垃圾收集。
#包括MWE的
(至少在VS14 afaik中)
using namespace System;
using namespace System::Runtime::InteropServices;

public ref class SomeManagedObject
{
public:
    String^ data;
    SomeManagedObject()
    {
        data = "Initial Data";
    }
    void SomeManagedMethods()
    {
        data = "Changed Data";
    }
};

void unmanaged_function(void* ptr) 
{
    gcroot<SomeManagedObject^>& obj = *((gcroot<SomeManagedObject^>*)ptr);
    obj->SomeManagedMethods();
} 

void managed_function() 
{ 
    // gcroot handles all allocations/deallocation and convertions
    gcroot<SomeManagedObject^>* pObj = new gcroot<SomeManagedObject^>();

    *pObj = gcnew SomeManagedObject();
    unmanaged_function(pObj);

    delete pObj;
}