2

I want to use delphi array function in C#.

My delphi code:

TIntegerArray = array of integer;
function Testarray(): TIntegerArray stdcall; export;
 var
   res: TIntegerArray2;
 begin
   SetLength(res, 10);
   res[5] := 55;
   Result := res;
 end;
 exports Testarray;

C# code:

[DllImport("GitaTele.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int[] Testarray();

Shows me error:

Cannot marshal 'return value': Invalid managed/unmanaged type combination.

5
  • 1
    In Delphi you return a specific type TIntegerArray2 while in C# you try to map this to int[]. Howe is this supposed to work? Commented May 12, 2015 at 5:40
  • You can't marshal directly an array as the retun value. And even if you could, who would free the memory Delphy allocated for that array? Commented May 12, 2015 at 5:41
  • thank you. edited.my code is more than: TIntegerArray = array of integer; TIntegerArray2 = array of integer; Commented May 12, 2015 at 5:42
  • You cannot use arrays as a function result across DLL boundaries. Simple as that. Same reason why you cannot return strings as function results. Commented May 12, 2015 at 5:43
  • Pass it as a var parameter instead. But it's not as simple as that. You also have to decide which side is responsible for memory allocation / freeing. The answer varies depending on that. Commented May 12, 2015 at 5:49

1 Answer 1

3

Delphi dynamic arrays are not valid interop types. You need to have the caller allocate the array, and then let the callee populate it.

procedure PopulateArray(arr: PInteger; var len: Integer); stdcall;
var
  i: Integer;
  returnArray: TArray<Integer>;
begin
  returnArray := GetArray;
  len := Min(len, Length(returnArray));
  for i := 0 to len - 1 do
  begin
    arr^ := returnArray[i];
    inc(arr);
  end;
end;

Do note the export has no meaning, is ignored, and should be removed for sake of simplicity.

From C# the calling code is:

[DllImport("...", CallingConvention = CallingConvention.StdCall)]
public static extern void PopulateArray(
    [In, Out]
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
    int[] arr,
    ref int len
);

....

int[] arr = new int[50];
int len = arr.Length;
PopulateArray(arr, ref len);
// len now contains actual length
Sign up to request clarification or add additional context in comments.

4 Comments

Why does it needs the whole MarshalAs? Can't he marshal the array directly to a PInteger, that is a int*?
You can do without the MarshalAs, but it allows the marshaller to optimise marshalling. On the other hand, since this example is blittable then the marshaller will just pin the array. So in that sense, MarshalAs serves no purpose.
@DavidHeffernan MarshalAs(MarshalAs( you doubled the MarshalAs in your code.
@xanatos Belt and braces ;-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.