FreePascal 64位DLL并调用C#应用程序

本文关键字:应用程序 调用 64位 DLL FreePascal | 更新日期: 2023-09-27 17:59:07

我正在尝试编译一个64位dll,以便与64位C#应用程序一起使用。我有一个简单的类和一个简单应用程序来尝试和测试它,无论我尝试和做什么,它都会失败

Delphi

library project1;
{$mode objfpc}{$H+}
uses
  Classes;

function Encrypt(aName:PChar):PChar;stdcall;
begin
  Result := aName;
end;

exports Encrypt;
begin
end.

C#

 [DllImport("project1.dll")]
    [return: MarshalAs(UnmanagedType.LPStr)]
    public static extern String Encrypt([MarshalAs(UnmanagedType.LPStr)] String aName);

有人能看出它有什么不对劲吗?如果不想创造同样简单的场景来尝试让它发挥作用,我就无能为力了!

FreePascal 64位DLL并调用C#应用程序

这个问题是C#编组器将一个临时内存块作为aName传递到函数中。当函数返回时,此内存将被销毁。但是您也要求C#整理器将相同的内存块整理成C#字符串。

无论如何,从本机DLL函数返回以null结尾的字符串都不是一种好的做法。你有几个选择:

  1. 使用C#端的StringBuilder为字符串预分配内存。这需要你以某种方式掌握所需的尺寸。这是互操作字符串的最常见方法
  2. 以COM BSTR的形式返回字符串,C#编组器知道如何编组和处理BSTR,并可以访问COM分配器。我不知道在FreePascal中使用BSTR,但在Delphi中只需使用WideString。您还需要告诉C#整理器您将返回一个BSTR

我个人倾向于选择2。不过,有一个问题是,不同的编译器对函数返回值使用不同的ABI,正如本问题所讨论的那样:为什么WideString不能用作interop的函数返回值?解决这个问题的简单方法是在参数中返回字符串,而不是使用函数返回值。

代码如下:

Pascal

procedure Encrypt(Input: WideString; out Output: WideString); stdcall;
begin
  Output := Input;
end;

C#

[DllImport("project1.dll")]
public static extern void Encrypt(
    [MarshalAs(UnmanagedType.BStr)] string input;
    [MarshalAs(UnmanagedType.BStr)] out string output
);