如何使用非托管导出(Robert Giesecke)将结构数组从.NET传递到Delphi?

时间:2014-03-19 13:38:07

标签: c# delphi pinvoke

我刚刚问过并获得了我的问题的答案:“无法返回非托管导出的自定义类型实例(Robert Giesecke)” - > can't return custom type instance with unmanaged export (Robert Giesecke) 我想知道是否(以及如何)使用非托管导出(Robert Giesecke)将结构数组从.NET传递到Delphi:

  • 直接返回数组

[DllExport] public static void CreateSampleInstance(out Sample[] sample)

  • 在返回的结构中使用数组成员

[DllExport] public static void CreateSampleInstance(out Sample sample)

`public struct Sample
{
   Other[] Others;
}`

我的问题是如何编写Delphi端以及在.NET中设置什么属性。

非常感谢。

1 个答案:

答案 0 :(得分:3)

数组更加棘手,因为您需要更加注意分配和销毁数组的位置。最干净的方法总是在调用者处分配,将数组传递给被调用者以让它填充数组。在您的上下文中,这种方法看起来像这样:

public struct Sample
{
    [MarshalAs(UnmanagedType.BStr)]
    public string Name;
}

[DllExport]
public static int func(
    [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
    Sample[] samples, 
    ref int len
)
{
    // len holds the length of the array on input
    // len is assigned the number of items that have been assigned values 
    // use the return value to indicate success or failure
    for (int i = 0; i < len; i++)
        samples[i].Name = "foo: " + i.ToString();
    return 0;
}

您需要指定数组需要在向外方向编组。如果您希望以两种方式编组值,则可以使用In, Out代替Out。您还需要使用MarshalAsUnmanagedType.LPArray来指示如何封送数组。并且您确实需要指定大小参数,以便编组人员知道要编组回非托管代码的项目数。

然后在Delphi方面你声明这样的函数:

type
  TSample = record
    Name: WideString;
  end;
  PSample = ^TSample;

function func(samples: PSample; var len: Integer): Integer; stdcall; 
  external dllname;

这样称呼:

var
  samples: array of TSample;
  i, len: Integer;
....
len := 10;
SetLength(samples, len);
if func(PSample(samples), len)=0 then
  for i := 0 to len-1 do
    Writeln(samples[i].Name);

<强>更新

作为AlexS discovered(参见下面的评论),只有.net 4支持通过引用传递size param索引。在早期版本中,你需要按值传递size param索引。

我选择通过引用传递它的原因是允许以下协议:

  1. 调用者在中传递一个值,表示数组的大小。
  2. 被叫方传递 out 一个值,表示已填充了多少元素。
  3. 这在.net 4上运行良好,但在早期版本中,您需要在步骤2中使用额外的参数。