从c#调用dll中的Delphi方法

时间:2013-05-17 04:29:14

标签: c# delphi pinvoke

我正在尝试使用以下签名调用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,但这给了我同样的错误。

2 个答案:

答案 0 :(得分:9)

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

  1. 召集会议。
  2. 参数列表。
  3. 参数类型和语义。
  4. 第一个观察是您的呼叫约定不匹配。您在Delphi端有register,在C#端有stdcall。 Delphi register约定对Delphi是私有的,因此您应该使用stdcall

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

    您需要使用接口两端都可以使用的字符串类型。您可以使用以null结尾的C字符串,但更好更简单的选择是在Delphi中BSTR的COM 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 don't attempt to use it as a return value时要小心。因为Delphi对返回值使用非标准语义,所以只能使用适合寄存器的简单类型作为返回值。

答案 1 :(得分:0)

Delphi中的默认调用约定是寄存器,而不是stdcall。似乎calling conventions details向我们显示微软fastcall与Borland fastcall(注册)不一样

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