FreePascal 64 位 DLL 和调用 C# 应用程序
我正在尝试编译 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);
任何人都可以看到它有什么问题吗?如果不喜欢创建相同的简单场景来尝试让它工作,我已经束手无策了!
I am trying to compile a 64bit dll for use with a 64bit C# application. I have a simple class and a simple app to try and test it and it falls over no matter what I try and do. Here is the code:
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);
Can anyone see anything wrong with it and if not fancy creating the same simple scenario to try and get this to work, I'm at the end of my tether!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题在于 C# 编组器将临时内存块作为
aName
传递到函数中。当函数返回时,该内存将被销毁。但您还要求 C# 编组器将同一内存块编组到 C# 字符串中。无论如何,从本机 DLL 函数返回以 null 结尾的字符串都不是一个好习惯。您有几个选择:
StringBuilder
为字符串预分配内存。这需要您以某种方式掌握所需的大小。这是互操作字符串的最常见方法。BSTR
返回,C# 编组器知道如何编组和处置BSTR
,并且可以访问 COM 分配器来执行此操作。我不知道如何在 FreePascal 中使用BSTR
,但在 Delphi 中您只需使用WideString
。您还需要告诉 C# 编组器您正在返回一个BSTR
。我个人更喜欢选项 2。不过有一个问题,那就是不同的编译器对函数返回值使用不同的 ABI,正如这个问题中所讨论的:为什么 WideString 不能用作互操作的函数返回值?最简单的方法解决方法是在参数中返回字符串,而不是使用函数返回值。
代码如下所示:
Pascal
C#
The problem with this is that the C# marshaller passes a temporary block of memory into the function as
aName
. This memory is the destroyed when the function returns. But you are also asking the C# marshaller to marshal this same block of memory into a C# string.It's not good practice to return a null-terminated string from a native DLL function anyway. You have a couple of options:
StringBuilder
on the C# side to pre-allocate the memory for the string. This requires you to get hold of the required size somehow. This is the most common way to interop strings.BSTR
and the C# marshaller knows how to marshall and dispose aBSTR
, and has access to the COM allocator to do so. I have no knowledge about usingBSTR
in FreePascal but in Delphi you simply useWideString
. You also need to tell the C# marshaller that you are returning aBSTR
.I personally have a preference for option 2. There is one wrinkle though and that is that different compilers use a different ABI for function return values, as discussed at this question: Why can a WideString not be used as a function return value for interop? The easy way around that is to return the string in a parameter rather than using the function return value.
The code looks like this:
Pascal
C#