从c#调用dll中的Delphi方法

Mik*_*ike 5 c# delphi pinvoke

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

 function SMap4Ovr(const OverFileName       : ShortString    ;
                    const Aclay              : Integer        ;
                    const Acarbon            : Double         ;
                    out   errstr             : ShortString): WordBool;
Run Code Online (Sandbox Code Playgroud)

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

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

但我得到一个AccessViolationException.

我似乎能够调用DLL中的几个更简单的方法,这些方法有字符串参数但不是int或double.

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

Dav*_*nan 11

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

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

第一个观察是您的调用约定不匹配.你有registerDelphi方面和stdcallC#方面.Delphi register约定对Delphi是私有的,所以你应该使用它stdcall.

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

您需要使用接口两端都可以使用的字符串类型.你可以使用空值终止的C字符串,而是一个更好更简单的选择是COM BSTRWideString在Delphi中.

因此,最终结果如下.

德尔福

function SMap4Ovr(
    OverFileName: WideString;
    Aclay: Integer;
    Acarbon: Double;
    out errstr: WideString
): WordBool; stdcall;
Run Code Online (Sandbox Code Playgroud)

C#

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

我没有DllImport在默认情况下指定调用约定stdcall.如果你愿意,你可以明确这一点.

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