簡単に言えば、問題は次のとおりです。マネージ コードで ItrPtr としてネイティブ DLL から返されたメモリを解放する方法は?
詳細 : 単純な関数が OUTPUT として 2 つのパラメーターを受け取るとします。最初のパラメーターはバイト配列への参照ポインターであり、2 番目のパラメーターは Reference Int です。この関数は、いくつかの規則に基づいてバイト数を割り当て、メモリのポインターとバイトのサイズ、および戻り値 (成功の場合は 1、失敗の場合は 0) を返します。
以下のコードは正常に動作し、バイト配列とバイト数と戻り値を正しく取得できますが、ポインター (IntPtr) を使用してメモリを解放しようとすると、例外が発生します。
Windows は、TestCppDllCall.exe でブレークポイントをトリガーしました。
これは、ヒープの破損が原因である可能性があります。これは、TestCppDllCall.exe または読み込まれた DLL のバグを示しています。
これは、TestCppDllCall.exe にフォーカスがあるときにユーザーが F12 キーを押したことが原因である可能性もあります。
出力ウィンドウには、より多くの診断情報が表示される場合があります。
物事を明確にするために:
次の C# コードは、同じ署名を持つ他の DLL 関数で正しく動作し、メモリの解放は問題なく動作します。
(C) コードの変更は、メモリの割り当て方法を変更したり、他のコードを追加したりする必要がある場合に受け入れられます。
私が必要とするすべての機能は、参照によって2つのパラメータを受け入れるネイティブDLL関数です(バイト配列とint、c#では[バイト配列とintのIntPtr])いくつかのルールに基づいていくつかの値を入力し、関数の結果を返します(成功または失敗) .
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# でこのポインタを使用してこれらのメモリ ブロックを解放する方法を教えてください。
不明な点やタイプミスがある場合はお知らせください。私は英語のネイティブ スピーカーではありません。