我有这个C ++代码:
extern "C" __declspec(dllexport) VOID AllocateFoo(MY_DATA_STRUCTURE** foo)
{
*foo = new MY_DATA_STRUCTURE;
//do stuff to foo
}
然后在C#中我调用函数:
[DllImport("MyDll.dll")]
static extern void AllocateFoo(out IntPtr pMyDataStruct);
...
MyDataStructure GetMyDataStructure()
{
IntPtr pData;
ManagedAllocateFooDelegate(out pData);
MyDataStructure foo = (MyDataStructure)Marshal.PtrToStructure(pData, typeof(MyDataStructure));
return foo;
}
MyDataStructure是一个结构(非类),对应于MY_DATA_STRUCTURE,成员被正确编组。
所以问题:当MyDataStructure是GC时,我是否需要存储pData然后在非托管代码中再次发布它? MSDN对Marshal.PtrToStructure(IntPtr,Type)说: “将数据从非托管内存块编组到指定类型的新分配托管对象。” 在那句话中,“马歇尔”是指“复制”吗?在这种情况下,我需要保留(IntPtr pData),然后将其传递给非托管代码(在MyDataStructure析构函数中),这样我就可以进行C ++“删除”了吗?
我已经搜索过,但我找不到足够明确的答案。
答案 0 :(得分:11)
正如Erik所说,元帅确实意味着复制,但我认为他没有回答你问题的主要观点。
您是否需要保留pData本机指针,直到MyDataStructure被GC为止?否。
一旦封送,您的MyDataStructure实例foo包含pData指向的结构的副本。你不需要再持有pData了。为了避免内存泄漏,您必须将该pData传递给另一个将删除它的非托管函数,这可以在编组之后立即完成,无论您持有MyDataStructure实例多长时间。
答案 1 :(得分:7)
是的,在这种情况下,马歇尔意味着复制;因此,您需要在非托管代码中释放内存。对PtrToStructure执行的所有调用都是从pData指向的内存位置读取目标结构“MyDataStructure”大小所指示的字节数。
当然,细节取决于'MyDataStructure'究竟是什么样的(你在MyDataStructure中使用任何FieldOffset或StructLayout属性) - 但最终结果是PtrToStructure的返回是数据的副本。
正如GBegen his answer指出的那样,我没有回答你问题的要点。是的,您需要在非托管代码中删除结构的非托管副本,但不需要保留pData - 您可以在调用PtrToStructure完成后立即删除非托管副本。
PS:我已经编辑了我的帖子以包含这些信息,以便将答案合并到一个帖子中 - 如果有人赞成这个答案,请提升GBegen的回答以及他的贡献。