从C#调用DLL中的Delphi方法

5

我正在尝试调用一个具有以下签名的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个回答

13
当编写交互操作代码时,每个接口的两端必须完全匹配,这是至关重要的。以下是您必须在两端上达成一致的主要问题:
1. 调用约定。 2. 参数列表。 3. 参数类型和语义。
第一个观察结果是,您的调用约定不匹配。您在Delphi侧有“register”,而在C#侧有“stdcall”。Delphi的“register”约定是私有的,因此您应该使用“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 对于返回值使用非标准语义,所以只能使用适合寄存器的简单类型作为返回值。

1
谢谢David,你的帮助非常棒。 - Mike
我通过这篇文章解决了我的问题。+1 MarshalAs起了作用! - Ins

0

Delphi中的默认调用约定是register,而不是stdcall。似乎调用约定细节告诉我们Microsoft fastcall与Borland fastcall(register)不同

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


fastcall确实不同于register,而且在任何情况下都不受pinvoke marshaller支持。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接