Search code examples
c#delphidlldllexport

Calling function in C# DLL from Delphi has parameter stuck on single value


I have a C# DLL with several exported functions. On one of these functions, when calling it from our Delphi XE2 application the length parameter for the array is always read as 31 in the DLL, regardless of what I actually pass.

The C# function declaration

[DllExport(CallingConvention = CallingConvention.StdCall)]
public static bool FraDataRead(int dbHash, uint pointid, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] Double[] FraData, int length)

Delphi function declaration

TGetFraData = function(dbHash         : Integer;
                       pointid        : Uint32;
                       unmanagedArray : Array of Double;
                       arraySize      : Integer) : Bool; stdcall;

Getting the procedure

GetFraData : TGetFraData; //this is a class variable, here for simplicity 
@GetFraData := GetProcAddress(FDllHandle, 'FraDataRead');

Calling function

function TIviumSQLAccess.IviFraData(const PointId : Uint32;
                     const FraData : Array of Double;
                     const arraySize : Integer): Boolean;
begin
  Result := GetFraData(dbHash,
                    PointId,
                    FraData,
                    arraySize);
end;

I have tested calling the function from another C# application, and there the length parameter functions as expected. When calling from Delphi it always calls with 32 as the length (currently) but the DLL always process 31. I have tried both larger and smaller numbers when calling, but it always uses 31.


Solution

  • TGetFraData = function(dbHash         : Integer;
                           pointid        : Uint32;
                           unmanagedArray : Array of Double;
                           arraySize      : Integer) : Bool; stdcall;
    

    This code is wrong because it uses a Delphi open array. These are actually implemented as two arguments, the pointer to the array, and the index of the last element, which is why you see a 31 for your array of length 32.

    You need instead to declare the type like this

    TGetFraData = function(dbHash         : Integer;
                           pointid        : Uint32;
                           unmanagedArray : PDouble;
                           arraySize      : Integer) : Bool; stdcall;
    

    and then pass a pointer to the first element of the array.