Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
FreePascal 64位DLL和调用C#应用程序_C#_Delphi_Freepascal_Lazarus - Fatal编程技术网

FreePascal 64位DLL和调用C#应用程序

FreePascal 64位DLL和调用C#应用程序,c#,delphi,freepascal,lazarus,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. C# 任何人

我正试图编译一个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#


任何人都能看到它有什么问题吗?如果不想创建相同的简单场景来尝试让它工作,我已经筋疲力尽了

问题在于,C#marshaller将一个临时内存块作为
aName
传递到函数中。当函数返回时,此内存将被销毁。但您也要求C#marshaller将相同的内存块编组为C#字符串

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

  • 使用C端的
    StringBuilder
    为字符串预分配内存。这需要您以某种方式获得所需的大小。这是互操作字符串的最常用方法
  • 以COM
    BSTR
    的形式返回字符串,C#marshaller知道如何对
    BSTR
    进行封送和处置,并且有权访问COM分配器。我不知道如何在FreePascal中使用
    BSTR
    ,但在Delphi中,您只需使用
    WideString
    。您还需要告诉C#marshaller您正在返回一个
    BSTR
  • 我个人倾向于选择2。但有一个缺点,即不同的编译器对函数返回值使用不同的ABI,正如在本问题中所讨论的:简单的方法是在参数中返回字符串,而不是使用函数返回值

    代码如下所示:

    Pascal

    procedure Encrypt(Input: WideString; out Output: WideString); stdcall;
    begin
      Output := Input;
    end;
    
    C#


    @Jon这就是你在Delphi中所做的(
    BSTR
    ==
    WideString
    ),但我不知道它在FP中是否也适用。如果在FP中不能这样做,那么调用
    SysAllocString
    可能很容易,但需要获取UTF-16文本。看看这个答案:我刚刚将PChar改为Widestring并构建了DLL,但是C应用程序仍然不喜欢它。在C端,您需要使用
    marshallas(UnmanagedType.BStr)
    ,看几篇博客文章似乎表明WideString在FP中得到了很好的支持。看看JVCL和JclDotNet单元。
    procedure Encrypt(Input: WideString; out Output: WideString); stdcall;
    begin
      Output := Input;
    end;
    
    [DllImport("project1.dll")]
    public static extern void Encrypt(
        [MarshalAs(UnmanagedType.BStr)] string input;
        [MarshalAs(UnmanagedType.BStr)] out string output
    );