问题简言之: 如何将托管代码中从Native DLL返回的内存释放为ItrPtr?从托管C#发布非托管内存,并指向它的位置
详细信息: 假设我们有简单的函数将两个参数作为OUTPUT,第一个参考指针指向字节数组,第二个参考指针指向参考指针。 函数将根据一些规则分配字节数量并返回内存指针和字节大小以及返回值(1表示成功,0表示失败)。
下面的代码工作正常,我可以得到正确的字节数组,字节数和返回值,但是当我尝试使用指针来释放内存(IntPtr的)我得到异常:
Windows已经在TestCppDllCall.exe中触发了一个断点。
这可能是由于堆的损坏,这表明TestCppDllCall.exe或它已加载的任何DLL中存在一个错误。
这也可能是由于用户按下F12而TestCppDllCall.exe具有焦点。
输出窗口可能有更多诊断信息。
为了把事情说清楚:
与其他DLL函数接下来的C#代码正常工作具有相同的签名和释放内存没有任何问题的作品。
如果您需要更改分配内存方法或添加任何其他代码,则接受(C)代码中的任何修改。
我需要的所有功能是Native DLL函数通过引用接受两个参数(byte数组和int,在c#中[intPtr of byte array和int])根据一些规则填充一些值并返回函数结果(成功或失败)。
CppDll.h
#ifdef CPPDLL_EXPORTS
#define CPPDLL_API __declspec(dllexport)
#else
#define CPPDLL_API __declspec(dllimport)
#endif
extern "C" CPPDLL_API int writeToBuffer(unsigned char *&myBuffer, int& mySize);
CppDll。CPP
#include "stdafx.h"
#include "CppDll.h"
extern "C" CPPDLL_API int writeToBuffer(unsigned char*& myBuffer, int& mySize)
{
mySize = 26;
unsigned char* pTemp = new unsigned char[26];
for(int i = 0; i < 26; i++)
{
pTemp[i] = 65 + i;
}
myBuffer = pTemp;
return 1;
}
C#代码:
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace TestCppDllCall
{
class Program
{
const string KERNEL32 = @"kernel32.dll";
const string _dllLocation = @"D:\CppDll\Bin\CppDll.dll";
const string funEntryPoint = @"writeToBuffer";
[DllImport(KERNEL32, SetLastError = true)]
public static extern IntPtr GetProcessHeap();
[DllImport(KERNEL32, SetLastError = true)]
public static extern bool HeapFree(IntPtr hHeap, uint dwFlags, IntPtr lpMem);
[DllImport(_dllLocation, EntryPoint = funEntryPoint, CallingConvention = CallingConvention.Cdecl)]
public static extern int writeToBuffer(out IntPtr myBuffer, out int mySize);
static void Main(string[] args)
{
IntPtr byteArrayPointer = IntPtr.Zero;
int arraySize;
try
{
int retValue = writeToBuffer(out byteArrayPointer, out arraySize);
if (retValue == 1 && byteArrayPointer != IntPtr.Zero)
{
byte[] byteArrayBuffer = new byte[arraySize];
Marshal.Copy(byteArrayPointer, byteArrayBuffer, 0, byteArrayBuffer.Length);
string strMyBuffer = Encoding.Default.GetString(byteArrayBuffer);
Console.WriteLine("Return Value : {0}\r\nArray Size : {1}\r\nReturn String : {2}",
retValue, arraySize, strMyBuffer);
}
}
catch (Exception ex)
{
Console.WriteLine("Error calling DLL \r\n {0}", ex.Message);
}
finally
{
if (byteArrayPointer != IntPtr.Zero)
HeapFree(GetProcessHeap(), 0, byteArrayPointer);
}
Console.ReadKey();
}
}
}
当调试这个代码我设置在线路断裂点(返回1)和缓冲区的值为:
myBuffer = 0x031b4fc0 "ABCDEFGHIJKLMNOPQRSTUVWXYZ««««««««î"
当函数调用返回并且值为:
我在C#代码中获得了相同的值52121536
结果我得到了正确的内存指针,我能够得到字节数组值,如何释放这些内存块与此指针在C#中?
请让我知道是否有什么不清楚或者是否有任何错字,我不是英语母语的人。
感谢您的快速回复。 我希望有一种方法可以直接在C#中释放非托管内存。 – khaled
我同意dasblinkenlight:* cleananest *方式可以说是为您的.dll添加一个“免费”方法。但Peter Ritchie也是正确的:C#肯定有可能通过interop调用相应的“free”(例如'FreeCoTaskMem()')来分配.dll(例如'CoTaskMemAlloc()')。你不能从C#做的一件事是“删除”,如果.dll做了一个C++“新”的话。 “malloc/free”:OK。 CoTaskMemAlloc/FreeCoTaskMem:也行。 “新/免费”:绝对*不*。 – paulsm4
@ paulsm4请解释如何在C#malloc/free中调用? – awattar