从c#调用dll中的Delphi方法

我试图使用以下签名调用Delphi DLL中的方法:

function SMap4Ovr(const OverFileName : ShortString ; const Aclay : Integer ; const Acarbon : Double ; out errstr : ShortString): WordBool; 

我在C#中使用以下导入:

  [DllImport("SMap.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] public static extern bool SMap4Ovr( string OverFileName, int Aclay, double Acarbon, out string errstr ); 

但我得到一个AccessViolationException。

我似乎能够在DLL中调用几个更简单的方法,这些方法有字符串参数但不是整数或双精度数。

我也试过CallingConvention = CallingConvention.Cdecl,但这给了我同样的错误。

在编写互操作代码时,接口的两端必须以各种方式匹配。 以下是您必须在双方达成一致的主要问题:

  1. 召集会议。
  2. 参数列表。
  3. 参数类型和语义。

第一个观察是您的调用约定不匹配。 您已在Delphi端register并在C#端register stdcall 。 Delphi register约定对Delphi是私有的,所以你应该使用stdcall

其次,您的字符串参数类型不匹配。 Delphi shortstring是一种数据类型,在Delphi 2发布时成为遗产,应该被认为是上个世纪的遗留物。 它永远不是一个有效的互操作类型,并且p / invoke框架中没有任何东西可用于匹配它。 虽然你可以尝试手工编组,但是当有简单的解决方案时,这是一项根本不需要的工作。 你应该试着忘记所有关于shortstring

您需要使用接口两端都可以使用的字符串类型。 您可以使用以null结尾的C字符串,但更好更简单的选择是COM BSTR ,它是Delphi中的WideString

因此,最终结果如下。

delphi

 function SMap4Ovr( OverFileName: WideString; Aclay: Integer; Acarbon: Double; out errstr: WideString ): WordBool; stdcall; 

C#

 [DllImport("SMap.dll")] public static extern bool SMap4Ovr( [MarshalAs(UnmanagedType.BStr)] string OverFileName, int Aclay, double Acarbon, [MarshalAs(UnmanagedType.BStr)] out string errstr ); 

我没有在DllImport上指定调用约定,因为默认是stdcall 。 如果您愿意,可以明确说明这一点。

使用WideString时要小心, 不要尝试将其用作返回值 。 因为Delphi对返回值使用非标准语义,所以只能使用适合寄存器的简单类型作为返回值。

Delphi中的默认调用约定是寄存器,而不是stdcall。 似乎调用约定细节告诉我们,Microsoft fastcall与Borland fastcall(注册)不一样

而C#字符串类型与Delphi ShortString不同(它内部包含一个字节长度+字符串体)