Jon*_*Jon 6 c# delphi freepascal lazarus
我正在尝试编译一个64位的dll,用于64位C#应用程序.我有一个简单的类和一个简单的应用程序来尝试和测试它,它无论我尝试做什么都会失败.这是代码:
德尔福
library project1;
{$mode objfpc}{$H+}
uses
Classes;
function Encrypt(aName:PChar):PChar;stdcall;
begin
Result := aName;
end;
exports Encrypt;
begin
end.
Run Code Online (Sandbox Code Playgroud)
C#
[DllImport("project1.dll")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern String Encrypt([MarshalAs(UnmanagedType.LPStr)] String aName);
Run Code Online (Sandbox Code Playgroud)
任何人都可以看到它有什么问题,如果没有花哨创造同样的简单场景试图让这个工作,我就在我的系绳的尽头!
Dav*_*nan 10
这个问题是C#marshaller将一个临时的内存块传递给函数aName.当函数返回时,该内存被销毁.但是你也要求C#marshaller将这个相同的内存块编组成一个C#字符串.
无论如何,从本机DLL函数返回以null结尾的字符串并不是一个好习惯.你有几个选择:
StringBuilder在C#端使用a 为字符串预分配内存.这要求您以某种方式获得所需的大小.这是互操作字符串的最常用方法.BSTRC#marshaller知道如何编组和处理a BSTR,并且可以访问COM分配器来执行此操作.我不知道BSTR在FreePascal中使用,但在Delphi中你只是使用WideString.你还需要告诉C#marshaller你要回来了BSTR.我个人偏好选项2.但是有一个皱纹,那就是不同的编译器对函数返回值使用不同的ABI,正如这个问题所讨论的:为什么WideString不能用作interop的函数返回值?简单的方法是在参数中返回字符串而不是使用函数返回值.
代码如下所示:
帕斯卡尔
procedure Encrypt(Input: WideString; out Output: WideString); stdcall;
begin
Output := Input;
end;
Run Code Online (Sandbox Code Playgroud)
C#
[DllImport("project1.dll")]
public static extern void Encrypt(
[MarshalAs(UnmanagedType.BStr)] string input;
[MarshalAs(UnmanagedType.BStr)] out string output
);
Run Code Online (Sandbox Code Playgroud)