数组更加棘手,因为您需要更加注意分配和销毁数组的位置。最干净的方法总是在调用者处分配,将数组传递给被调用者,让它填充数组。这种方法在您的上下文中看起来像这样:
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。您还需要使用MarshalAs 和UnmanagedType.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(参见下面的 cmets),仅 .net 4 支持通过引用传递大小参数索引。在早期版本中,您需要按值传递大小参数索引。
我选择在这里通过引用传递它的原因是允许以下协议:
- 调用者传递in一个指示数组有多大的值。
- 被调用者传递输出一个值,指示已填充多少元素。
这在 .net 4 上运行良好,但在早期版本中,您需要为步骤 2 使用额外的参数。