从调用C#DLL中德尔菲法(Calling a Delphi method in a dll fro

2019-09-03 22:59发布

我想调用的方法德尔福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但是这给了我同样的错误。

Answer 1:

在编写代码的互操作至关重要的是在各个方面的接口匹配的两侧。 这里的主要问题是,你必须同意双方:

  1. 调用约定。
  2. 参数列表。
  3. 参数类型和语义。

第一个发现是,你调用约定不匹配。 你必须register在德尔福侧和stdcall在C#的一面。 德尔福register约定是私人德尔福,所以你应该使用stdcall

其次,你的字符串参数类型不匹配。 德尔福shortstring是成为遗留在Delphi 2中被释放,并应被视为从上个世纪遗留下来的数据类型。 这是从来没有一个有效的互操作类型,并没有什么在P / Invoke的框架,可以用来匹配它。 虽然你可以尝试做手工编组,这是很多,当有可用简单的解决方案是根本没有必要的工作。 你应该试着去忘记所有关于shortstring

你需要使用一个字符串类型的接口的两侧可以工作。 你可以使用空值终止的C字符串,而是一个更好更简单的选择是COM BSTR这是WideString德尔福。

所以,最终的结果如下。

德尔福

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使用非标准的语义返回值,你只能使用简单的类型放入一个寄存器作为返回值。



Answer 2:

在Delphi中默认调用约定注册,不STDCALL。 这似乎调用约定细节告诉我们,微软FASTCALL是不一样的FASTCALL Borland公司(注册)

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



文章来源: Calling a Delphi method in a dll from c#