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

 踏实小青年 发布于 2023-01-09 13:05

我试图使用一个用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的入口点

1 个回答
  • 这里的基本问题是二进制互操作不匹配之一.简单地说,指向数组的指针在二进制级别与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可能很棘手.这很容易出错.当你弄错了,代码编译,但在运行时死亡可怕.带有神秘的错误消息.导致头部刮伤.

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

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

    2023-01-09 13:07 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有