使用 Delphi 编写的 DLL 中的数组

普尤尔根斯

我有一些用 Delphi 编写的函数,我需要通过 DLL 从其他编程语言(例如 Python)访问这些函数。Delphi 函数采用某种数字(整数或双精度数)、数组或矩阵(数组数组)作为输入和返回类型。

在 Delphi 中,通过一个简单的测试函数可以很好地传递整数:

library Delphi_Library;

uses
  System.SysUtils;

function AddIntegers(const _a, _b: integer): integer; stdcall;
begin
    Result := _a + _b;
end;
exports
    AddIntegers;
begin
end.

并从 Python 调用它:

import ctypes
Dll = ctypes.WinDLL('Delphi_Library')
a = ctypes.c_int(5)
b = ctypes.c_int(7)

c = Dll.AddIntegers(a, b)

print(c)

但是,我不能直接将数组传递给 DLL,但据我所知,我需要使用指向该数组的指针。另外我不能使用数组作为返回类型,所以我想改变一个输入数组。作为测试函数,我想编写一个小函数,它将一个指向数组的指针array_in和它的长度size_array_in作为输入,并将另一个数组array_out和它的大小size_array_out设置为相同的值。它还以双精度形式返回数组的最后一个元素。

我在 Delphi 中的代码如下所示:

library Delphi_Library;

uses
  System.SysUtils;

type
    TArray = Array of Double;
    PArray = ^TArray;

function ReturnArray(array_in: pointer; size_array_in: integer; array_out: pointer; size_array_out: integer): Double; stdcall;
var
 i: Integer;
 P_value: PDouble;
 arr: TArray;
begin
  Result := 0;
  P_value := PDouble(array_in);
  setlength(arr, size_array_out);
  //arr := P_in^;
  for i := 0 to size_array_in-1 do
  begin
    arr[i] := P_value^;
    inc(P_value);
  end;
  array_out := @arr;
  size_array_out := Length(arr);
end;
exports
    ReturnArray;
begin
end.

在 Python 中

ReturnArray = Dll.ReturnArray
ReturnArray.restype = ctypes.c_double
ReturnArray.argtypes = ctypes.POINTER(ctypes.c_double*8), ctypes.c_int, ctypes.POINTER(ctypes.c_double*8), ctypes.c_int

data_in = (ctypes.c_double*8)(*range(32, 40))
data_out = (ctypes.c_double*8)(*range(8))
num_1 = 8
num_2 = 8

print('input', list(data_in), list(data_out))
retval = ReturnArray(data_in, num_1, data_out, num_2)
print('output', retval, list(data_in), list(data_out))

但是,data_out在调用 Delphi-DLL 函数后,我仍然得到相同的数组/列表

那么如何将数组或指向数组的指针从另一种编程语言解析为 Delphi 数组呢?我的最终目标是编写一个接口,以便能够使用带有定义的 Delphi 函数,就像function AnyFunction(a: Array of Double; b: Array of Array of Double): Array of Double来自支持调用 C-DLL 的任何编程语言一样

雷米勒博

Delphi 的动态数组与其他编程语言/编译器(C++Builder 除外)根本不兼容。所以你只需要对原始指针进行操作。在这种情况下,调用者需要分配两个数组并传入指向它们的指针,然后 Delphi 代码可以简单地将值从一个数组复制到另一个数组,例如:

library Delphi_Library;

uses
  System.SysUtils, System.Math;

{$POINTERMATH ON}
function ReturnArray(array_in: PDouble; size_array_in: Integer;
  array_out: PDouble; size_array_out: Integer): Integer; stdcall;
var
  i, len: Integer;
begin
  len := Min(size_array_in, size_array_out);
  for i := 0 to len-1 do
  begin
    array_out[i] := array_in[i];
    // or, if {$POINTERMATH} is not available in your Delphi version:
    // array_out^ := array_in^;
    // Inc(array_in);
    // Inc(array_out);
  end;
  // Or simpler:
  // Move(array_in^, array_out^, len * sizeof(Double));
  Result := len;
end;

exports
  ReturnArray;

begin
end.
ReturnArray = Dll.ReturnArray
ReturnArray.restype = ctypes.c_int
ReturnArray.argtypes = ctypes.POINTER(ctypes.c_double*8), ctypes.c_int, ctypes.POINTER(ctypes.c_double*8), ctypes.c_int

data_in = (ctypes.c_double*8)(*range(32, 40))
data_out = (ctypes.c_double*8)(*range(8))
num_1 = 8
num_2 = 8

print('input', list(data_in), list(data_out))
retval = ReturnArray(data_in, num_1, data_out, num_2)
print('output', retval, list(data_in), list(data_out))

我的最终目标是编写一个接口,以便能够使用带有定义的 Delphi 函数,就像function AnyFunction(a: Array of Double; b: Array of Array of Double): Array of Double来自支持调用 C-DLL 的任何编程语言一样

Delphi开放数组参数只不过是编译器魔术来隐藏由以下组成的一对参数:

  • 指向数组第一个元素的原始指针。
  • 数组的最后一个索引(不是长度!)。

因此,例如,可以使用如下所示的开放数组参数重写上面的示例:

library Delphi_Library;

uses
  System.SysUtils, System.Math;

function ReturnArray(array_in: array of Double;
  array_out: array of Double): Integer; stdcall;
var
  i, len: Integer;
begin
  len := Min(Length(array_in), Length(array_out));
  for i := 0 to len-1 do
  begin
    array_out[i] := array_in[i];
  end;
  // Or simpler:
  // Move(array_in[0], array_out[0], len * sizeof(Double));
  Result := len;
end;

exports
  ReturnArray;

begin
end.
ReturnArray = Dll.ReturnArray
ReturnArray.restype = ctypes.c_int
ReturnArray.argtypes = ctypes.POINTER(ctypes.c_double*8), ctypes.c_int, ctypes.POINTER(ctypes.c_double*8), ctypes.c_int

data_in = (ctypes.c_double*8)(*range(32, 40))
data_out = (ctypes.c_double*8)(*range(8))
num_1 = 7 # NOT 8!
num_2 = 7 # NOT 8!

print('input', list(data_in), list(data_out))
retval = ReturnArray(data_in, num_1, data_out, num_2)
print('output', retval, list(data_in), list(data_out))

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章