将一个字符串从delphi dll返回到64位C#调用者

将一个字符串从delphi dll返回到64位C#调用者,c#,delphi,pinvoke,C#,Delphi,Pinvoke,我有一个C#应用程序,它使用以下代码调用本机Delphi dll: C# Delphi function GetString(out a: PChar): Integer; stdcall; begin a := PChar('abc'); Result := 1; end; function GetString(a: PChar): PChar; stdcall; var inp: string; begin inp := a; Result := PChar('test

我有一个C#应用程序,它使用以下代码调用本机Delphi dll:

C#

Delphi

function GetString(out a: PChar): Integer; stdcall;
begin
  a := PChar('abc');
  Result := 1;
end;
function GetString(a: PChar): PChar; stdcall;
var
  inp: string;
begin
  inp := a;
  Result := PChar('test ' + inp);
end;
它在32位应用程序中运行良好。但是当我为64位编译C#exe和Delphi dll时,我遇到了一个奇怪的问题。在Delphi调试器中调用GetString后,我可以看到.NET代码中的某个地方出现异常,调试器输出窗口中出现以下字符串:“检测到严重错误c0000374”。谷歌说这个错误与堆损坏有关。 我尝试使用ref/var参数修饰符而不是out/out。还是不走运。为什么会出现这个错误?我应该为64位使用不同的呼叫约定吗

顺便说一句,以下组合效果良好:

C#

Delphi

function GetString(out a: PChar): Integer; stdcall;
begin
  a := PChar('abc');
  Result := 1;
end;
function GetString(a: PChar): PChar; stdcall;
var
  inp: string;
begin
  inp := a;
  Result := PChar('test ' + inp);
end;

很好。但我确实需要返回一个字符串作为输出参数。

您不能通过这种方式从本机管理的文件传递字符串。您的代码在32位也是错误的,您正好侥幸逃脱了。代码的第二个版本也是错误的。它似乎只起作用

您需要:

  • 从共享堆进行分配,以便托管代码可以从该堆中取消分配。p/invoke的共享堆是COM堆
  • 在托管端分配内存,并将内容复制到本机端的缓冲区中
  • 选择2总是可取的。看起来是这样的:

    [DllImport("NativeDLL.dll", CharSet = CharSet.Unicode)]
    public static extern int GetString(StringBuilder str, int len);
    
    在本土,你会有

    function GetString(str: PChar; len: Integer): Integer; stdcall;
    begin
      StrLCopy(str, 'abc', len);
      Result := 1; // real code would have real error handling
    end;
    
    那么就这样称呼它:

    StringBuilder str = new StringBuilder(256);
    int retval = GetString(str, str.Capacity);
    
    如果要尝试选项1,则在托管端看起来如下所示:

    [DllImport("NativeDLL.dll", CharSet = CharSet.Unicode)]
    public static extern int GetString(out string str);
    
    就像这个本地人:

    function GetString(out str: PChar): Integer; stdcall;
    begin
      str = CoTaskMemAlloc(SizeOf(Char)*(Length('abc')+1));
      StrCopy(str, 'abc');
      Result := 1; // real code would have real error handling
    end;
    
    当托管代码将
    str
    的内容复制到字符串值时,它会对返回的指针调用
    CoTaskMemFree

    这很容易被称为:

    string str;
    int retval = GetString(out str);
    

    非常感谢你!你帮我省了很多时间来解决这个问题。
    PChar
    ?这是一场偶然的游戏,是“潘斯卡”还是“普维德查”?(是的,我们可以推断它是64位XE2,但我们无法确保此代码不会使用64位FPC编译或复制粘贴到32位项目等)@Arioch'Then然后使用
    PWideChar
    ,如果您愿意。最近在我的