我有一个 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 位中也是错误的,您只是碰巧逃脱了它。第二版的代码也是错误的。它只是看起来有效。
您需要:
- 从共享堆分配,以便托管代码可以从该堆中释放。 p/invoke 的共享堆是 COM 堆。
- 在托管端分配内存,并将内容复制到 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/