我有这个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++"删除"?
我已经搜索过,但我找不到足够明确的答案.
正如Erik所说,元帅确实意味着复制,但我不认为他回答了你问题的要点.
你需要保持pData本机指针,直到MyDataStructure被GCed?没有.
封送后,MyDataStructure实例foo包含pData指向的结构的副本.你不需要再持有pData了.为了避免内存泄漏,您必须将该pData传递给另一个将删除它的非托管函数,并且可以在编组后立即完成,无论您保留MyDataStructure实例多长时间.
是的,在这种情况下,马歇尔意味着复制; 因此,您需要在非托管代码中释放内存.对PtrToStructure执行的所有调用都是从pData指向的内存位置读取目标结构"MyDataStructure"大小所指示的字节数.
当然,细节取决于'MyDataStructure'的确切含义(您在MyDataStructure中使用任何FieldOffset或StructLayout属性) - 但最终结果是PtrToStructure的返回是数据的副本.
正如GBegen在答案中指出的那样,我没有回答你问题的要点.是的,您需要在非托管代码中删除结构的非托管副本,但不需要保留pData - 您可以在调用PtrToStructure完成后立即删除非托管副本.
PS:我编辑了我的帖子以包含这些信息,以便将答案合并到一个帖子中 - 如果有人赞成这个答案,请upvote GBegen的回答以及他的贡献.