簡體   English   中英

如何釋放傳遞給C#的Delphi PByte?

[英]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
  • 如果聲明p / invoke使用out參數而不是ref則不需要初始化作為參數傳遞的變量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM