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

我刚刚询问并获得了我的问题的答案:“无法返回具有非托管导出的自定义类型实例(Robert Giesecke)” – > 无法返回具有非托管导出的自定义类型实例(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中设置什么属性。

非常感谢。

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

 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 发现的那样 (参见下面的评论),只有.net 4支持通过引用传递size param索引。在早期版本中,你需要按值传递size param索引。

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

  1. 调用者传入一个值,表示该数组的大小。
  2. 被调用者传出一个值,表示已填充了多少元素。

这在.net 4上运行良好,但在早期版本中,您需要在步骤2中使用额外的参数。