我正在尝试编译一个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);
任何人都可以看到它有什么问题,如果不想创造同样的简单场景试图让它发挥作用,我就在我的系绳的尽头!
答案 0 :(得分:10)
问题在于C#marshaller将临时内存块作为aName
传递给函数。函数返回时会破坏此内存。但是你也要求C#marshaller将这个相同的内存块编组成一个C#字符串。
无论如何,从本机DLL函数返回以null结尾的字符串并不是一个好习惯。你有几个选择:
StringBuilder
为字符串预分配内存。这要求您以某种方式获得所需的大小。这是互操作字符串最常用的方法。BSTR
返回,C#marshaller知道如何编组和部署BSTR
,并且可以访问COM分配器来执行此操作。我不知道在FreePascal中使用BSTR
,但在Delphi中你只需使用WideString
。您还需要告诉C#marshaller您要返回BSTR
。我个人偏好选项2.但是有一个皱纹,那就是不同的编译器对函数返回值使用不同的ABI,正如这个问题所讨论的那样:Why can a WideString not be used as a function return value for interop?简单的方法就是在参数中返回字符串而不是使用函数返回值。
代码如下所示:
<强>帕斯卡强>
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
);