使用带有C DLL的delphi dta类型的问题

Tim*_*ram 3 delphi dll matlab

我试图使用一个用C语言编写的.dll(尽管它包含了一个matlab .ddl)

我尝试使用的函数在C中定义为:

 __declspec(dllexport) int ss_scaling_subtraction(double* time, double** signals, double* amplitudes, int nSamples, int nChannels, double* intensities);
Run Code Online (Sandbox Code Playgroud)

除其他外,.dll需要一个二维数组 - 当我尝试使用时:

Array of array of double
Run Code Online (Sandbox Code Playgroud)

在声明中,编译器发出错误,因此我定义了自己的数据类型:

T2DArray = Array of array of double;
Run Code Online (Sandbox Code Playgroud)

我在一个单元中初始化.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';
Run Code Online (Sandbox Code Playgroud)

但是,当调用此函数时,我从.dll获取访问冲突

创建新数据类型

T1DArray = array of double
Run Code Online (Sandbox Code Playgroud)

和改变

Array of double
Run Code Online (Sandbox Code Playgroud)

T1DArray
Run Code Online (Sandbox Code Playgroud)

在声明似乎使事情运行但结果仍然不正确.

我在这里读到,将delphi数据类型传递给.dll以不同语言编码可能很危险,所以我认为这可能会导致问题.

但是当我必须首先使用它来正确地声明函数时,我怎么不使用delphi数据类型?!

额外的信息,我已经打开了matlab运行时编译器的lib并打开了StirScanDLL.dll的入口点

Dav*_*nan 10

这里的基本问题是二进制互操作不匹配之一.简单地说,指向数组的指针在二进制级别与Delphi开放数组参数不同.虽然它们在语义上都表示数组,但二进制表示不同.

C函数声明如下:

__declspec(dllexport) int ss_scaling_subtraction(
    double* time, 
    double** signals, 
    double* amplitudes, 
    int nSamples, 
    int nChannels, 
    double* intensities
);
Run Code Online (Sandbox Code Playgroud)

在Delphi中声明你的函数:

function ss_scaling_subtraction(
    time: PDouble; 
    signals: PPDouble; 
    amplitudes: PDouble; 
    nSamples: Integer;
    nChannels: Integer; 
    intensities: PDouble
): Integer; cdecl; external 'StirScanDLL.dll';
Run Code Online (Sandbox Code Playgroud)

如果您发现PPDouble未声明,请按以下方式对其进行定义:

type
  PPDouble = ^PDouble;
Run Code Online (Sandbox Code Playgroud)

也就是指针指向double的指针.

现在剩下的就是调用这些函数.在Delphi中将您的数组声明为动态数组.像这样:

var
  time, amplitudes, intensities: TArray<Double>; 
  signals: TArray<TArray<Double>>; 
Run Code Online (Sandbox Code Playgroud)

如果你有一个较旧的pre-generics Delphi,那么声明一些类型:

type
  TDoubleArray = array of Double;
  T2DDoubleArray = array of TDoubleArray;
Run Code Online (Sandbox Code Playgroud)

然后使用适当的类型声明变量.

接下来,您需要分配数组,并填充从调用者传递给被调用者的任何数据.

SetLength(time, nSamples); // I'm guessing here as to the length
SetLength(signals, nSamples, nChannels); // again, guessing
Run Code Online (Sandbox Code Playgroud)

最后是时候调用这个函数了.现在事实证明,Delphi的优秀设计师安排将动态数组存储为第一个元素的指针.这意味着它们不会被用作参数.

retval := ss_scaling_subtraction(
   PDouble(time),
   PPDouble(signals),
   PDouble(amplitudes),
   nSamples,
   nChannels,
   PDouble(intensities)
);
Run Code Online (Sandbox Code Playgroud)

请注意,此处显示的动态数组的强制转换依赖于实现细节.因此,有些人可能会争辩说,对于@time[0]一维数组,例如等等会更好.并创建一个PDouble振幅数组并复制内部数组的第一个元素的地址.就个人而言,我很依赖这个实现细节.它确实使编码更加简单.


最后一条建议.Interop可能很棘手.这很容易出错.当你弄错了,代码编译,但在运行时死亡可怕.带有神秘的错误消息.导致头部刮伤.

所以,从最简单的接口开始.接收标量参数的函数.比如说,接收一个整数,并返回一个整数.证明你可以做到这一点.然后转到浮点标量.然后是一维数组.最后是二维数组.沿途的每一步,都会增加复杂性.当您遇到问题时,您会知道它已归结为最近添加的参数.

你没有采取这种方法.你已经直接杀死并在你的第一次尝试中实现了一切.当它失败时,你不知道在哪里看.将问题分解成小块,并从那些较小的块中构建更复杂的问题.