我正在尝试使用一个用C语言编写的.dll(虽然它包含了一个matlab .ddl)
我尝试使用的功能在C中定义为:
__declspec(dllexport) int ss_scaling_subtraction(double* time, double** signals, double* amplitudes, int nSamples, int nChannels, double* intensities);
.dll需要一个二维数组 - 当我尝试使用时:
Array of array of double
在声明中,编译器发出错误,因此我定义了自己的数据类型:
T2DArray = Array of array of double;
我在一个单位中初始化.dll函数:
function ss_scaling_subtraction(const time: array of double; const signals: T2DArray; const amplituides : array of double; const nSamples: integer;const nChannels: integer; var intensities: array of double) : integer ; cdecl; external 'StirScanDLL.dll';
然而,当调用此函数时,我从.dll
获得访问冲突创建新数据类型
T1DArray = array of double
并改变
Array of double
要
T1DArray
在声明中似乎使事情运行但结果仍然不正确。
我在这里读到,将delphi数据类型传递给.dll以不同语言编码会很危险,所以我认为这可能会导致问题。
但是当我必须首先使用它来正确地声明函数时,我怎么不使用delphi数据类型?!
额外的信息,我已经打开了matlab运行时编译器lib并打开了StirScanDLL.dll的入口点
答案 0 :(得分:10)
这里的基本问题是二进制互操作不匹配之一。简单地说,指向数组的指针在二进制级别与Delphi开放数组参数不同。虽然它们在语义上都代表一个数组,但二进制表示不同。
C函数声明如下:
__declspec(dllexport) int ss_scaling_subtraction(
double* time,
double** signals,
double* amplitudes,
int nSamples,
int nChannels,
double* intensities
);
在Delphi中声明你的函数:
function ss_scaling_subtraction(
time: PDouble;
signals: PPDouble;
amplitudes: PDouble;
nSamples: Integer;
nChannels: Integer;
intensities: PDouble
): Integer; cdecl; external 'StirScanDLL.dll';
如果您发现未声明PPDouble
,请按此定义:
type
PPDouble = ^PDouble;
即指针指向double的指针。
现在剩下的就是调用这些函数。在Delphi中将您的数组声明为动态数组。像这样:
var
time, amplitudes, intensities: TArray<Double>;
signals: TArray<TArray<Double>>;
如果你有一个较旧的pre-generics Delphi,那么声明一些类型:
type
TDoubleArray = array of Double;
T2DDoubleArray = array of TDoubleArray;
然后用适当的类型声明变量。
接下来,您需要分配数组,并填充从调用者传递给被调用者的任何数据。
SetLength(time, nSamples); // I'm guessing here as to the length
SetLength(signals, nSamples, nChannels); // again, guessing
最后是时候调用这个函数了。现在事实证明,Delphi的优秀设计师安排将动态数组存储为第一个元素的指针。这意味着它们不会被用作参数。
retval := ss_scaling_subtraction(
PDouble(time),
PPDouble(signals),
PDouble(amplitudes),
nSamples,
nChannels,
PDouble(intensities)
);
请注意,此处显示的动态数组的强制转换依赖于实现细节。因此,有些人可能认为最好使用,例如@time[0]
等等,用于一维数组。并为幅度创建PDouble
数组并复制内部数组的第一个元素的地址。就个人而言,我很依赖这个实现细节。它确实使编码变得更加简单。
最后一条建议。 Interop可能很棘手。这很容易出错。当你弄错了,代码编译,但在运行时死亡可怕。带有神秘的错误消息。导致头部刮伤。
所以,从最简单的界面开始。接收标量参数的函数。比如说,接收一个整数,并返回一个整数。证明你可以做到这一点。然后转到浮点标量。然后是一维数组。最后是二维数组。沿途的每一步,都会增加复杂性。当您遇到问题时,您会发现它已归结为最近添加的参数。
你没有采取这种做法。你已经直接进行了杀戮,并在你的第一次尝试中实现了一切。当它失败时,你不知道在哪里看。将问题分解成小块,并从那些较小的块中构建更复杂的问题。