c# - 将字符串从 delphi dll 返回到 64 位的 C# 调用程序

标签 c# delphi pinvoke

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

C#

[DllImport("NativeDLL.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern int GetString(string out str);

德尔福

function GetString(out a: PChar): Integer; stdcall;
begin
  a := PChar('abc');
  Result := 1;
end;

在 32 位应用程序中运行良好。但是当我为 64 位编译 C# exe 和 Delphi dll 时,我遇到了一个奇怪的问题。在 Delphi 调试器中调用 GetString 后,我可以看到在 .NET 代码中某处引发了异常,并且以下字符串出现在调试器输出窗口中:“检测到严重错误 c0000374”。 Google 表示此错误与堆损坏有关。 我尝试使用 ref/var 参数修饰符而不是 out/out。仍然没有运气。为什么会出现此错误?我应该为 64 位使用不同的调用约定吗?

顺便说一句。以下组合工作正常:

C#

[DllImport("NativeDLL.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern string GetString(string a);

德尔福

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

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

最佳答案

您不能以这种方式从 native 管理传递字符串。您的代码在 32 位中也是错误的,您只是碰巧逃脱了它。第二版的代码也是错误的。它只是看起来有效。

您需要:

  1. 从共享堆分配,以便托管代码可以从该堆中释放。 p/invoke 的共享堆是 COM 堆。
  2. 在托管端分配内存,并将内容复制到 native 端的缓冲区。

选项 2 总是更可取。它看起来像这样:

[DllImport("NativeDLL.dll", CharSet = CharSet.Unicode)]
public static extern int GetString(StringBuilder str, int len);

在 native 端你会拥有

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);

关于c# - 将字符串从 delphi dll 返回到 64 位的 C# 调用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16170360/

相关文章:

c# - C#中的自动编码检测

c# - 为什么 base() 构造函数不是必需的?

arrays - 设置数组(记录)长度时,Delphi 堆栈溢出和访问冲突错误

C# Dll导入麻烦

c# - services.AddSingleton,永远不会调用服务的构造函数

c# - 在 facebook ads api 中获取图像的哈希码

delphi - SOAP 请求使线程挂起

delphi - TFileStream 的行为很奇怪

c# - 将 pair<int,float> 的二维数组从 c# 传递到 c dll

c# - 在带参数的函数上使用 PInvoke 时出现 AccessViolationException