FreePascal 64位DLL并调用C#Application

时间:2011-06-13 19:24:16

标签: c# delphi freepascal lazarus

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

任何人都可以看到它有什么问题,如果不想创造同样的简单场景试图让它发挥作用,我就在我的系绳的尽头!

1 个答案:

答案 0 :(得分:10)

问题在于C#marshaller将临时内存块作为aName传递给函数。函数返回时会破坏此内存。但是你也要求C#marshaller将这个相同的内存块编组成一个C#字符串。

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

  1. 在C#端使用StringBuilder为字符串预分配内存。这要求您以某种方式获得所需的大小。这是互操作字符串最常用的方法。
  2. 将字符串作为COM BSTR返回,C#marshaller知道如何编组和部署BSTR,并且可以访问COM分配器来执行此操作。我不知道在FreePascal中使用BSTR,但在Delphi中你只需使用WideString。您还需要告诉C#marshaller您要返回BSTR
  3. 我个人偏好选项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
    );