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);
有人能看出它有什么不对劲吗?如果不想创造同样简单的场景来尝试让它发挥作用,我就无能为力了!
这个问题是C#编组器将一个临时内存块作为aName
传递到函数中。当函数返回时,此内存将被销毁。但是您也要求C#整理器将相同的内存块整理成C#字符串。
无论如何,从本机DLL函数返回以null结尾的字符串都不是一种好的做法。你有几个选择:
- 使用C#端的
StringBuilder
为字符串预分配内存。这需要你以某种方式掌握所需的尺寸。这是互操作字符串的最常见方法 - 以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
);