[英]How to free a Delphi PByte passed to C#?
我設法將一個Delphi DLL中的PByte傳遞給C#並讀取了PByte:
public void DoSomething(string company, string claimNumber, string language)
{
var buffersize = 0;
IntPtr pnt = new IntPtr();
try
{
//Get some data from Delphi dll
if (DelphiController.DoSomething(ref buffersize, ref pnt))
{
byte[] managedArray = new byte[buffersize];
Marshal.Copy(pnt, managedArray, 0, buffersize);
//Do something with managedArray...
}
}
finally
{
//how to free pnt?
DelphiController.FreeMemory(pnt, buffersize);
}
}
Delphi功能:
function DoSomething(var buffersizeArr: integer; var pnt: PByte): Wordbool; stdcall; export;
var
arrB: Tarray<Byte>;
begin
//some code
arrB := TFile.ReadAllBytes(fileName);
buffersizeArr := length(arrB);
pnt := @arrB[0];
//some more code
end;
到目前為止,一切工作正常,所以現在我想釋放pnt
分配的內存。 我試圖將pnt
傳遞回Delphi DLL,但無法釋放內存,並始終收到Invalid Pointer Operation
異常。
function FreeMemory(pnt: Pointer; size: integer): Wordbool; stdcall; export;
var
p: Pointer;
begin
try
FreeMem(pnt, size); //throws invalid pointer exception
result := true;
except
on e:Exception do
begin
result := false;
end;
end;
end;
那么,此時釋放內存的正確方法是什么?
Delphi代碼已損壞。 您正在返回一個動態數組的地址,該函數在函數返回之前已被銷毀。 換句話說,您的Delphi代碼返回一個指向釋放內存的指針。 您的問題不應該是“如何釋放內存”,而應該問“如何阻止釋放內存”!
相反,您應該執行以下操作:
function DoSomething(var buffersizeArr: integer; var pnt: PByte): Wordbool; stdcall;
var
arrB: Tarray<Byte>;
begin
arrB := ...;
buffersizeArr := Length(arrB);
pnt := CoTaskMemAlloc(buffersizeArr);
Move(Pointer(arrB)^, pnt^, buffersizeArr);
Result := ...;
end;
然后,您可以使用Marshal.FreeCoTaskMem
在C#代碼中取消分配數組。
我選擇在這里使用CoTaskMemAlloc
,因為這是從共享堆中分配的,因此您可以輕松地從C#取消分配。 您可以同樣使用LocalAlloc
,然后在C#中使用Marshal.FreeHGlobal
解除分配。 如果使用GetMem
在Delphi中進行分配,則還需要導出一個Delphi函數來執行釋放,因為GetMem
使用內部的Delphi堆。
一些小注意事項:
export
Delphi關鍵字將被忽略,您可以將其刪除。 IntPtr
中使用new
毫無意義。 您可以編寫IntPtr pnt = IntPtr.Zero
。 out
參數而不是ref
則不需要初始化作為參數傳遞的變量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.