将结构数组从c#传递给delphi

我在VS2010中使用Robert Giesecke Unmanaged Exports 1.2.6 ,我的目标是将一系列结构从c#(.NET 3.5)传递给delphi(D7) 。 我不得不承认,我对delphi并不熟悉。

我已经阅读过这篇文章 ,但建议的答案对我不起作用:在delphi中调用func时,CPU调试窗口打开,如果我继续应用程序退出,无exception且没有所需的结果。

这是我试过的代码:

C#平台x86

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using RGiesecke.DllExport; namespace ArrayTest { public class Class1 { 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; } } } 

Delphi7中

 program DelphiApp; {$APPTYPE CONSOLE} uses SysUtils, ActiveX; type TSample = record Name: WideString; end; PSample = ^TSample; function func(samples: PSample; var len: Integer): Integer; stdcall; external 'ArrayTest.dll'; procedure Test2; var samples: array of TSample; i, len: Integer; begin len := 10; SetLength(samples, len); if func(PSample(samples), len)=0 then for i := 0 to len-1 do Writeln(samples[i].Name); end; begin Test2(); end. 

如前所述,调试器打开CPU窗口,如果我继续应用程序退出,无exception或错误消息。 如果我在没有dbugger的情况下运行它,Windows告诉我应用程序不再工作,应用程序关闭。

我错过了什么?

更新

修改后的代码

 [DllExport] public static int func( [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] Sample[] samples, ref int len ) { Console.WriteLine("return 0"); return 0; } procedure Test2; var samples: array of TSample; i, len: Integer; begin len := 10; SetLength(samples, len); if func(PSample(samples), len)=0 then for i := 0 to len-1 do Writeln('D7: ', i); end; 

即使我不访问任何一侧的arrays,行为仍然是相同的。

控制台输出: return 0

好像我发现了这个问题:

如果使用.NET 4.0或更高版本,代码运行正常。 如果使用.NET 3.5或更低版本,则len-parameter必须按值传递。

请参阅MSDN文档SizeParamIndex v3.5 :

包含大小的参数必须是按值传递的整数。

请参阅MSDN文档SizeParamIndex v4.0 :

当数组作为C样式数组传递时,封送器无法确定数组的大小。 因此,要将托管数组传递给非托管函数或方法,必须提供两个参数:

  • 数组,由引用或值定义。

  • 数组大小,由引用或值定义。

代码使用.NET 3.5:

C#

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

Delphi7中

 function func(samples: PSample; len: Integer; var outLen: Integer): Integer; stdcall; external 'ArrayTest.dll'; procedure Test2; var samples: array of TSample; i, len: Integer; begin len := 0; // query the required array size i := func(PSample(samples), len, len); if i>0 then begin len := i; SetLength(samples, len); if func(PSample(samples), len, len)>=0 then for i := 0 to len-1 do Writeln(samples[i].Name); end; end; 

结论:

在我的问题中发布并由David Heffernan发布的代码仅适用于.NET> = 4.0! 如果必须使用.NET <= 3.5,则必须按值传递数组,而不是按引用传递!