在 Delphi 中编写的 DLL 中使用数组
Using Arrays in DLL written in Delphi
我有一些用 Delphi 编写的函数,我需要通过 DLL 从其他编程语言(例如 Python)访问这些函数。 Delphi-函数采用某种数字(整数或双精度数)、数组或矩阵(数组的数组)作为输入和 return 类型。
在 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,但据我所知,我需要使用指向数组的指针。此外,我不能将数组用作 return 类型,因此我想更改输入数组。作为测试函数,我想写一个小函数,它接受一个指向数组 array_in
的指针,它的长度 size_array_in
作为输入,并设置另一个数组 array_out
和它的大小 size_array_out
到相同的值。它还 return 将数组的最后一个元素作为双精度。
我在 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))
然而,在调用 Delphi-DLL 函数后,data_out
仍然得到相同的 array/list。
那么如何将数组或指向数组的指针从另一种编程语言解析为 Delphi-数组?我的最终目标是编写一个接口,以便能够使用支持调用 C-DLL 的任何编程语言中定义为 function AnyFunction(a: Array of Double; b: Array of Array of Double): Array of Double
的 Delphi 函数。
Delphi 的动态数组根本不兼容其他编程 languages/compilers(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))
My ultimate goal is to write an interface to be able to use a Delphi function with a definition like function AnyFunction(a: Array of Double; b: Array of Array of Double): Array of Double
from any programming language that supports calling C-DLLs.
Delphi open array parameters 只不过是隐藏一对参数的编译器魔术,这些参数包括:
- 指向数组第一个元素的原始指针。
- 数组的最后一个索引(不是长度!)。
因此,例如,可以使用开放数组参数重写上面的示例,如下所示:
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))
我有一些用 Delphi 编写的函数,我需要通过 DLL 从其他编程语言(例如 Python)访问这些函数。 Delphi-函数采用某种数字(整数或双精度数)、数组或矩阵(数组的数组)作为输入和 return 类型。
在 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,但据我所知,我需要使用指向数组的指针。此外,我不能将数组用作 return 类型,因此我想更改输入数组。作为测试函数,我想写一个小函数,它接受一个指向数组 array_in
的指针,它的长度 size_array_in
作为输入,并设置另一个数组 array_out
和它的大小 size_array_out
到相同的值。它还 return 将数组的最后一个元素作为双精度。
我在 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))
然而,在调用 Delphi-DLL 函数后,data_out
仍然得到相同的 array/list。
那么如何将数组或指向数组的指针从另一种编程语言解析为 Delphi-数组?我的最终目标是编写一个接口,以便能够使用支持调用 C-DLL 的任何编程语言中定义为 function AnyFunction(a: Array of Double; b: Array of Array of Double): Array of Double
的 Delphi 函数。
Delphi 的动态数组根本不兼容其他编程 languages/compilers(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))
My ultimate goal is to write an interface to be able to use a Delphi function with a definition like
function AnyFunction(a: Array of Double; b: Array of Array of Double): Array of Double
from any programming language that supports calling C-DLLs.
Delphi open array parameters 只不过是隐藏一对参数的编译器魔术,这些参数包括:
- 指向数组第一个元素的原始指针。
- 数组的最后一个索引(不是长度!)。
因此,例如,可以使用开放数组参数重写上面的示例,如下所示:
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))