Вопрос вкратце: Как освободить память, возвращенную из Native DLL как ItrPtr в управляемом коде?
Подробности: Предположим, что у нас простая функция принимает два параметра как OUTPUT, первый из них - Reference Reference указатель на байтовый массив, а второй - Reference Int. Функция будет выделять количество байтов на основе некоторых правил и возвращать указатель на память и размер байтов и возвращаемое значение (1 для успеха и 0 для отказа).
Нижеприведенный код работает отлично, и я могу получить массив байтов правильно и количество байтов и возвращаемое значение, но когда я пытаюсь освободить память с помощью указателя (IntPtr), я получаю исключение:
Windows вызвала точку останова в TestCppDllCall.exe.
Это может быть связано с повреждением кучи, что указывает на ошибку в TestCppDllCall.exe или на любую из загруженных DLL файлов.
Это также может быть вызвано нажатием кнопки F12, когда у TestCppDllCall.exe есть фокус.
В окне вывода может быть больше диагностической информации.
Чтобы все было ясно:
-
Следующий код С# корректно работает с другой функцией DLL, имеет одну и ту же подпись и освобождает память без каких-либо проблем.
-
Любая модификация в коде (C) принята, если вам нужно изменить метод памяти памяти или добавить какой-либо другой код.
-
Вся необходимая функциональность - это функция Native DLL, которая принимает два параметра по ссылке (байтовый массив и int, In С# [IntPtr из байтового массива и int]) заполняют их некоторыми значениями на основе некоторых правил и возвращают функцию результат (Success или Fail).
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;
}
Код С#:
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();
}
}
}
Когда я отлаживаю этот код, я устанавливаю точку останова в строке (return 1), а значение буфера:
myBuffer = 0x031b4fc0 "ABCDEFGHIJKLMNOPQRSTUVWXYZ««««««««î"
И я получил то же значение в коде С#, когда возвращается вызов функции и значение:
52121536
Результат я Получил правильный указатель памяти, и я могу получить значение байтового массива, как освободить эти блоки памяти с помощью этого указателя на С#?
Пожалуйста, дайте мне знать, если что-то неясно или если есть опечатка, я не являюсь носителем английского языка.