I managed to pass a PByte from a Delphi DLL to C# and read the 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:
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;
Everything works fine so far and so now I wanted to free up the memory allocated by pnt. I tried to pass pnt back to the Delphi DLL but I am not able to free the memory and always get a Invalid Pointer Operation Exception.
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;
So what is the correct way to free up memory at this point?
The Delphi code is broken. You are returning the address of a dynamic array that is destroyed before the function returns. In other words, your Delphi code returns a pointer to deallocated memory. Your question should not be "how do I deallocate the memory" but rather you should ask "how do I stop the memory from being deallocated"!
Instead you should do something like this:
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;
Then you can deallocate the array in your C# code using Marshal.FreeCoTaskMem.
I have chosen to use CoTaskMemAlloc here because this allocates from a shared heap and so you can deallocate from C# easily. You could equally use LocalAlloc and then in C# deallocate with Marshal.FreeHGlobal. If you allocated in Delphi using GetMem then you would also need to export a Delphi function to perform the deallocation, because GetMem uses the internal Delphi heap.
Some minor notes:
export Delphi keyword is ignored and you can remove it.new with your IntPtr. You can write IntPtr pnt = IntPtr.Zero.out parameters instead of ref then you don't need to initialise the variables that you pass as parameters.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With