Home > front end >  Setting up Delphi to call a 2 dimensional array in C DLL
Setting up Delphi to call a 2 dimensional array in C DLL

Time:08-11

I have a DLL with the following header definitions:

typedef struct {
    int32_t dimSizes[2];
    double NumericControl[1];
} DoubleArrayBase;
typedef DoubleArrayBase **DoubleArray;
    
void __stdcall ReadTERFCorrectedData(char FilepathString[], 
    int32_t ArrayLengths[], DoubleArray *AmplitudeData, 
    DoubleArray *FrequencyData, int32_t len);

My question is, how do I go about setting up a Delphi call to this function?

My Delphi definition of the call is as follows:

type
  PTheStruct = ^TheStruct;
  TheStruct= record
    dimSizes: array of integer;
    NumericControl: array of Double;
  end;

procedure ReadTERFCorrectedData(asFilePathString: AnsiString; ArrayLength: pint; arAmplitude, arFrequency: PThestruct; TheLength : Integer );stdcall; external DLLDirectory;

But I don't even know if I'm on the right track.

CodePudding user response:

The DLL is using fixed-length arrays, but your Delphi code is using dynamic arrays instead. They are not the same thing.

Also, the DLL is expecting a pointer-to-pointer-to-struct, but you are using a pointer-to-record instead. You are missing a level of indirection.

Also, the DLL expects a pointer to a null-terminated AnsiChar C string, not an AnsiString.

Try this instead:

type
  PDoubleArray = ^DoubleArray;
  DoubleArray = ^PDoubleArrayBase;
  PDoubleArrayBase = ^DoubleArrayBase;
  DoubleArrayBase = packed record
    dimSizes: array[0..1] of Int32;
    NumericControl: array[0..0] of Double;
  end;
    
procedure ReadTERFCorrectedData(FilepathString: PAnsiChar;
  ArrayLengths: PInt32; AmplitudeData, FrequencyData: PDoubleArray;
  len: Int32); stdcall; external '...';

// Alternatively:
//
// procedure ReadTERFCorrectedData(FilepathString: PAnsiChar;
//   var ArrayLengths: Int32; var AmplitudeData, FrequencyData: DoubleArray;
//   len: Int32); stdcall; external '...';

UPDATE: the function takes DoubleArray* parameters, ie a pointer to a DoubleArray. So you likely need to call it something like this:

procedure TForm7.btn1Click(Sender: TObject);
var
  AmplitudeData, FrequencyData : DoubleArray;
  ArrayLengths: array[0..1] of Int32;
  I: Integer;
begin
  ReadTERFCorrectedData(fileloc, @ArrayLengths[0], @AmplitudeData, @FrequencyData, 500);
  ...
end;

But, there is simply not enough information presented to know whether you need to pre-allocate the arrays before calling the function, or if the function will allocate the arrays for you. The use of pointer-to-pointer indirections strongly implies that the DLL will perform the allocations for you. But what the DoubleArray contents will look like upon exit is anyone's guess without seeing documentation or example C code.

CodePudding user response:

Using Remy's answer, how whould one go about calling the DLL? This seems to work, but i am only getting 0's in my array's, Which i am certain is not correct.

type
  PDoubleArray = ^DoubleArray;
  DoubleArray = ^PDoubleArrayBase;
  PDoubleArrayBase = ^DoubleArrayBase;
  DoubleArrayBase = record
    dimSizes: array[0..1] of Int32;
    NumericControl: array[0..0] of Double;
  end;
    
procedure ReadTERFCorrectedData(FilepathString: PAnsiChar;
  ArrayLengths: PInt32; AmplitudeData, FrequencyData: PDoubleArray;
  len: Int32); stdcall; external '...';
implementation

{$R *.dfm}
procedure TForm7.btn1Click(Sender: TObject);
var
  AmplitudeData, FrequencyData : array of DoubleArrayBase;
  arraylengths: array of Integer;
  I: Integer;
begin
  SetLength(AmplitudeData,500);
  SetLength(FrequencyData,500);
  SetLength(arraylengths,2);
  ReadTERFCorrectedData(fileloc,@arraylengths[0], @AmplitudeData[0], @FrequencyData[0],500);
  for I := 0 to 499 do
  begin
    mmo1.Lines.Add(FrequencyData[i].NumericControl[0].ToString);
    mmo1.Lines.Add(frequencydata[i].dimsizes[0].tostring);
    mmo1.Lines.Add(frequencydata[i].dimsizes[1].tostring);
  end;
end;
  • Related