【问题标题】:FreePascal 64 bit DLL and calling C# ApplicationFreePascal 64 位 DLL 和调用 C# 应用程序
【发布时间】:2011-09-14 04:22:42
【问题描述】:

我正在尝试编译一个 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.

C#

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

任何人都可以看出它有什么问题吗?如果不想创建相同的简单场景来尝试让它发挥作用,那么我已经走到了尽头!

【问题讨论】:

  • 看看 JVCL 和 JclDotNet 单元。

标签: c# delphi freepascal lazarus


【解决方案1】:

问题在于 C# 编组器将临时内存块作为 aName 传递给函数。该内存在函数返回时被销毁。但是您还要求 C# 编组器将同一块内存编组为 C# 字符串。

无论如何,从本机 DLL 函数返回以空字符结尾的字符串并不是一个好习惯。您有两种选择:

  1. 在 C# 端使用 StringBuilder 为字符串预分配内存。这需要您以某种方式掌握所需的大小。这是互操作字符串的最常见方式。
  2. 将字符串作为 COM BSTR 返回,C# 编组器知道如何编组和处置 BSTR,并且可以访问 COM 分配器来执行此操作。我不知道如何在 FreePascal 中使用 BSTR,但在 Delphi 中您只需使用 WideString。您还需要告诉 C# 编组器您正在返回 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
);

【讨论】:

  • @Jon 这就是你在 Delphi 中所做的 (BSTR == WideString) 但我不知道它在 FP 中是否同样有效。如果您不能在 FP 中这样做,那么调用 SysAllocString 可能很容易,但您需要获取 UTF-16 文本。看看这个答案,看看如何:stackoverflow.com/questions/5308584/…
  • 我刚刚将 PChar 更改为 Widestring 并构建了 DLL,但是 C# 应用程序仍然不喜欢它
  • 在C#端你需要使用MarshalAs(UnmanagedType.BStr)
  • 实际上,看几篇博文似乎表明 WideString 在 FP 中得到了很好的支持。
猜你喜欢
  • 1970-01-01
  • 2011-12-25
  • 2013-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多