通过引用将双精度数组从C传递到Delphi DLL

0sc*_*car 1 c arrays delphi dll

对于我们的Delphi(XE5)应用程序,我们正在开发一个API。为了与主程序(基于C;(控制台)C或C ++代码应用程序或Matlab和Simulink)传递来自Delphi DLL函数的数据,需要由调用方分配的双精度数填充数组。

我知道开放式数组(特定于Delphi)在此用途上不是很方便,因为它们包含您随后必须在C中模仿的其他数据。相反,我计划inc(APDouble)通过直接指向正确的指针来使用指针算术(请参见dll函数:)。地址。我的问题是,这是否是您的软件开发人员将如何执行此操作。

下面包括一个演示(完整源代码)。

DLL(在DXE5中制作):

library PDA;

uses
  System.StrUtils,
  System.SysUtils,
  Vcl.Dialogs;

{$R *.res}

function ShowArrayContents( APDouble: PDouble;
                            size: Integer): integer; cdecl; export;
var
  i: Integer;
begin
  Result := 0;
  for i := 0 to size-1 do
  begin
    // Show value!
    MessageDlg(Format('%p -> %p -> %f', [@APDouble, APDouble, APDouble^]), mtWarning, [mbOK], 0);
    Inc(APDouble);
  end;
end;

exports
  ShowArrayContents;

begin

end.
Run Code Online (Sandbox Code Playgroud)

C代码调用程序(在C ++构建器XE4中制成):

#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>
#include <windows.h>

typedef int (*_ShowArrayContents) (double *, int);

char *dllname = "PDA.dll";
static HINSTANCE hInstanceControl;

_ShowArrayContents ShowArrayContents = NULL;

int _tmain(int argc, _TCHAR* argv[])
{
    double DVals[3] = {1.23, 4.56, 7.89};
    int i;

    hInstanceControl = LoadLibrary(dllname);

    if( hInstanceControl != NULL){
        ShowArrayContents =(_ShowArrayContents)GetProcAddress(hInstanceControl, "ShowArrayContents");
    } else {
        return 0;
    }

    // test program:
    (*ShowArrayContents)(&DVals[0], 3);

    FreeLibrary(hInstanceControl);

    system("pause");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*nan 5

您的代码可以正常工作,但您会发现它很尴尬。对于这样的互操作,我会咬牙切齿并使用$POINTERMATH指令。就像在C或C ++中一样,这使您可以将指针当作数组一样对待。例如:

{$POINTERMATH ON}
function GetSum(arr: PDouble; len: Integer): Double; cdecl; 
var
  i: Integer;
begin
  Result := 0.0;
  for i := 0 to len-1 do
    Result := Result + arr[i];
end;
Run Code Online (Sandbox Code Playgroud)

另一种选择是将其复制到本地Delphi数组,然后将其用于后续处理。显然,这涉及到副本,但有时实际上是您想要的。在这种情况下,您可以这样操作:

var
  x: TArray<Double>;
....
SetLength(x, len);
Move(arr^, Pointer(x)^, len*SizeOf(arr^));
Run Code Online (Sandbox Code Playgroud)

或者,如果您不喜欢使用,则可以使用Move一个不错的旧循环:

{$POINTERMATH ON}
var
  i: Integer;
  x: TArray<Double>;
....
SetLength(x, len);
for i := 0 to len-1 do
  x[i] := arr[i];
Run Code Online (Sandbox Code Playgroud)