如何使用非托管导出(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
。 您还需要使用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 发现的那样 (参见下面的评论),只有.net 4支持通过引用传递size param索引。在早期版本中,你需要按值传递size param索引。
我选择通过引用传递它的原因是允许以下协议:
- 调用者传入一个值,表示该数组的大小。
- 被调用者传出一个值,表示已填充了多少元素。
这在.net 4上运行良好,但在早期版本中,您需要在步骤2中使用额外的参数。