【问题标题】:Delphi-to-C dll: Passing ArraysDelphi-to-C dll:传递数组
【发布时间】:2013-06-21 17:06:42
【问题描述】:

我正在使用 Delphi 加载一个 dll(我在 Delphi XE-3 中创建),以便与一些 C 代码进行交互。我的问题是弄清楚为什么我的数组没有被传递给 c 函数——它们是唯一没有传递的。 delphi 文件(简化)如下所示:

program CallcCode
uses
  SysUtils, Windows, 
  DLLUnit in 'DLLUnit.pas'; // Header conversion

var
  DLLHandle: cardinal;
  n: Integer;
  A: TArray<Integer>;
  result1: Integer; 

begin
  // Initialize each Array
  SetLength(A,n);
  A[0] = ...;

  // Load the DLL (and confirm its loaded)
  DLLhandle := LoadLibrary('dllname.dll');
    if DLLhandle <> 0 then
      begin
       result1 := dll_func1(n,A); // A and B are not passed correctly
    end
  FreeLibrary(DLLHandle);
end.

我第一次成功“Trace into” dll_func1,进入DLLUnit,里面有:

const
  nameofDLL = 'dllname';
function dll_func1(n: Integer; A: TArray<Integer>): Integer; cdecl; external nameofDLL;

再次“Tracing-into”,我到达 c 文件,它仍然具有正确的 n 和 DLLdefs 值,但 A(在“局部变量”标题下)变成了:

[-]  A       :(Aplha-Numeric)
    ..[0]    0 (0x00000000)

我知道我至少可以正确访问 DLL(希望如此),因为其他函数调用可以正常工作,并且我能够毫无问题地跟踪到 dll_func1.c 文件。我尝试将功能更改为

function dll_func1(n: Integer; A: PInteger): Integer; cdecl; external nameofDLL;
...
result1 := dll_func1(n,PInteger(A))

function dll_func1(n: Integer; A: PInteger): Integer; cdecl; external nameofDLL;
...
result1 := dll_func1(n,@A[0])

(同时使用 TArray 和整数或 A 数组)但没有变化,这让我相信这与我没有看到的问题有关。整个事情编译并运行,但由于 TArray 失败,结果 1 不正确。关于出了什么问题的任何想法?

EDIT C 中的函数为:

int dll_func1(int n, int A [])

【问题讨论】:

  • 您只需要按照我在回答您上一个问题时告诉您的操作即可。密切关注我写的内容。你在这里所拥有的和它完全不同。好吧,问题的后半部分是。我怀疑该结构传递错误。为什么不编写一个接受单个数组并尝试传递它的 C 函数。然后变得更加雄心勃勃。
  • 我在函数调用(单元文件)中写了PInteger,在程序文件(我初始化它们的地方)中将它们定义为TArray&lt;Integer&gt;,并使用solve(n, PInteger(Ap), PInteger(Ax));只有数组没有传递给函数。结构传递不正确是什么意思?
  • 没有。 PInteger 是预定义的类型。不要将其重新定义为其他内容。删除所有声明。它被声明为 PInteger = ^Integer
  • 哦,我说的“添加 Pinteger”不是这个意思,我的意思是函数声明将 Ap 和 Ai 设置为 PInteger 类型。
  • 无论如何,您需要学习如何解决问题。目前,您正在尝试解决如何将数组从 Delphi 传递到 C。需要一个具有单个参数的函数。在您完全理解之前,不要考虑任何更复杂的事情。将问题分解成小块。

标签: c delphi dll delphi-xe3


【解决方案1】:

您的问题包含外部函数的两个 Delphi 声明。其中一个使用TArray&lt;T&gt; 作为参数。那是完全错误的。不要那样做。您不能将 Delphi 动态数组用作互操作类型。原因是TArray&lt;T&gt; 是一种复杂的托管类型,只能由 Delphi 代码创建和使用。

您需要按照我在下面的操作以及我在对您之前的问题的回答中解释的方式进行操作,并将数组参数声明为指向元素类型的指针。比如PIntegerPDouble等。

这里有很多混乱和不必要的复杂性。您需要的是最简单的示例,该示例展示了如何将数组从 Delphi 代码传递到 C 代码。

这是。

C 代码

//testarray.c

void printDouble(double d); // linker will resolve this from the Delphi code

void test(double *arr, int count)
{
    int i;
    for (i=0; i<count; i++)
    {
        printDouble(arr[i]);
    }
}

德尔福代码

program DelphiToC;

{$APPTYPE CONSOLE}

uses
  Crtl;

procedure _printDouble(d: Double); cdecl;
begin
  Writeln(d);
end;

procedure test(arr: PDouble; count: Integer); cdecl; external name '_test';

{$L testarray.obj}

var
  arr: TArray<Double>;

begin
  arr := TArray<Double>.Create(1.0, 2.0, 3.0, 42.0, 666.0);
  test(PDouble(arr), Length(arr));
  Readln;
end.

使用例如 Borland C 编译器编译 C 代码,如下所示:

bcc32 -c testarray.c

输出是:

1.00000000000000E+0000 2.00000000000000E+0000 3.00000000000000E+0000 4.20000000000000E+0001 6.66000000000000E+0002

请注意,我静态链接到 C 代码,因为这对我来说更容易。如果将 C 代码放在 DLL 中,则不会有太大变化。

结论是,我在你之前的回答中给你的代码是正确的,我在这里重复一遍。这种方法成功地将数组从 Delphi 代码传递给 C。看起来您的诊断和调试有误。

您只是在检查A[0],因此您只看到一个值也就不足为奇了。如果您查看A[1]A[2]、...、A[n-1],您会看到所有值都被正确传递。或者您的调试可能是对使用TArray&lt;T&gt; 作为参数的外部函数的错误声明进行的。

【讨论】:

  • 我知道这是我这边的问题,并且尝试在 delphi 代码中传递数组的“不同”方式告诉我问题不是数组本身(因为没有他们工作)。问题是我是 dll 和接口的新手,不知道接下来要测试什么,这就是为什么我要问一些我可以解决的其他问题。最小的例子(这一个和我做的那个)都有效(这并不奇怪,真的)。至于结构,这是问题中的错字(我已修复);它一直在我的代码中工作,它仍然只是数组。
  • 那么,您在这里寻找什么?我已经向您展示了如何传递一个数组,现在两次。我在这里猜测,但我的猜测是你的数组通过了很好,但你不知道如何在栅栏的 C 侧显示它。您忽略了显示界面的 C 端。你的数组参数是什么类型的?他们是int*。自然,如果您查看*A,例如,您只会看到一个值。但是A[0]A[1] 等呢?再次,请消除复杂性。您问题中的代码应与单个数组一起使用。摆脱结构,它只是分散注意力。简化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多