ReleaseUnmanagedMemoryandItsPointersfromManagedC#简而言之,问题是:如何释放从原生DLL返回的内存作为托管代码ItrPtr?详细信息:假设我们有一个简单的函数,将两个参数作为OUTPUT,第一个是指向字节数组的引用指针,第二个是引用Int。该函数会按照一定的规则分配字节数,返回内存指针和字节大小以及返回值(1表示成功,0表示失败)。下面的代码工作正常,我可以正确获取字节数组和字节数并返回值,但是当我尝试使用指针(IntPtr)释放内存时,出现异常:Windows在TestCppDllCall.exe中触发了断点。这可能是由于堆损坏,这表明TestCppDllCall.exe或它加载的任何DLL中存在错误。也可能是由于用户在TestCppDllCall.exe具有焦点时按了F12。输出窗口可能包含更多诊断信息。需要明确的是:下一个C#代码可以与具有相同签名的其他DLL函数一起正常工作,并且可以毫无问题地释放内存。如果您需要更改分配内存的方法或添加任何其他代码,则接受(C)代码中的任何修改。我需要的所有功能是一个NativeDLL函数,它接受两个参数引用(字节数组和int,在c#中[IntPtrofbytearrayandint])根据一些规则填充一些值并返回函数结果(成功或失败)).CppDll.h#ifdefCPPDLL_EXPORTS#defineCPPDLL_API__declspec(dllexport)#else#defineCPPDLL_API__declspec(dllimport)#endifextern"C"CPPDLL_APIintwriteToBuffer(unsignedchar*&myBuffer,int&mySize);CppDll.cpp#include"stdafx.h"#include"CppDll.h"extern"C"CPPDLL_APIintwriteToBuffer(unsignedchar*&myBuffer,int&mySize){mySize=26;unsignedchar*pTemp=newunsignedchar[26];for(inti=0;i<26;i++){pTemp[i]=65+i;}myBuffer=pTemp;返回1;}C#代码:usingSystem;使用系统文本;使用System.Runtime.InteropServices;namespaceTestCppDllCall{classProgram{conststringKERNEL32=@"kernel32.dll";conststring_dllLocation=@"D:CppDllBinCppDll.dll";conststringfunEntryPoint=@"writeToBuffer";[DllImport(KERNEL32,SetLastError=true)]publicstaticexternIntPtrGetProcessHeap();[DllImport(KERNEL32,SetLastError=true)]publicstaticexternboolHeapFree(IntPtrhHeap,uintdwFlags,IntPtrlpMem);[DllImport(_dllLocation,EntryPoint=funEntryPoint,CallingConvention=CallingConvention.Cdecl)]publicstaticexternintwriteToBuffer(outIntPtrmyBuffer,outintmySize);staticvoidMain(string[]args){IntPtrbyteArrayPointer=IntPtr.Zero;整数数组大小;try{intretValue=writeToBuffer(outbyteArrayPointer,outarraySize);if(retValue==1&&byteArrayPointer!=IntPtr.Zero){byte[]byteArrayBuffer=newbyte[arraySize];Marshal.Copy(byteArrayPointer,byteArrayBuffer,0,byteArrayBuffer.Length);字符串strMyBuffer=Encoding.Default.GetString(byteArrayBuffer);Console.WriteLine("返回值:{0}rnArray大小:{1}rnReturn字符串:{2}",retValue,arraySize,strMyBuffer);}}catch(Exceptionex){Console.WriteLine("ErrorcallingDLLrn{0}",ex.Message);}finally{if(byteArrayPointer!=IntPtr.Zero)HeapFree(GetProcessHeap(),0,byteArrayPointer);}控制台.ReadKey();}}}当我调试这段代码时,我在行中设置了断点(返回1),滚冲区域的值为:myBuffer=0x031b4fc0"ABCDEFGHIJKLMNOPQRSTUVWXYZ??????????"当函数调用返回值时,我在C#代码中得到相同的值:52121536并且作为结果我得到正确的内存指针,我能够获得字节数组值,如何在C#中使用这个指针释放这些内存块?如果有任何不清楚的地方或有任何拼写错误,请告诉我,我不是以英语为母语的人简短回答:您应该在DLL中添加一个单独的方法来为您释放内存。答案很简单:内存可以在DLL实现中以不同的方式分配。释放内存的方式必须与分配内存的方式相匹配。例如,用new[](带方括号)分配的内存需要用delete[]释放(不是删除或释放)。C#不为您提供机制;您需要将指针发送回C++。extern"C"CPPDLL_APIvoidfreeBuffer(unsignedchar*myBuffer){delete[]myBuffer;如果您想在本机代码中分配自己的内存,请使用CoTaskMemAlloc并且您可以使用Marshal.FreeCoTaskMem来释放托管代码中的指针。CoTaskMemAlloc被描述为“在基于COM的应用程序中共享内存的唯一方法”(参见http://msdn.microsoft.com/en-us/library/windows/desktop/aa366533(v=vs.85).aspx)如果您需要将CoTaskMemAlloc分配的内存与本机C++对象一起使用,您可以使用placementnew来初始化内存,就像使用new运算符一样。例如:void*p=CoTaskMemAlloc(sizeof(MyType));MyType*pMyType=new(p)MyType;这不分配内存,它只是调用预分配内存上的构造函数。调用Marshal.FreeCoTaskMem不会调用类型的析构函数(如果您只需要释放内存则不需要);如果您需要通过调用析构函数来释放更多内存,则必须提供一个本地方法来执行P/Invoke操作。在任何情况下,都不支持将本机类实例传递给托管代码。如果需要使用其他API分配内存,则需要通过P/Invoke将内存暴露在托管代码中,以便在托管代码中释放。HeapFree(GetProcessHeap(),0,byteArrayPointer);不,那行不通。堆句柄错误,CRT使用HeapCreate()创建自己的堆。它隐藏在CRT数据中,您无法访问它。从技术上讲,您可以从GetProcessHeaps()获取句柄,除非您不知道它是哪一个。也有可能是指针错误,CRT可能从HeapAlloc()返回的指针中添加了一些额外的信息来存储调试数据。您需要导出一个调用delete[]的函数来释放缓冲区。或者编写一个C++/CLI包装器以在包装器中使用delete[]。另一个要求是C++代码和包装器使用完全相同版本的CRTDLL(需要/MD)。这几乎总是要求您可以重新编译C++代码。以上就是C#学习教程:从托管C#中释放非托管内存,共享其指针的所有内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文来自网络收集,不代表作品如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处:
