gpt4 book ai didi

c# - 使用字符串函数时,应用程序在 64 位 DllImport 上崩溃

转载 作者:行者123 更新时间:2023-11-30 20:03:59 24 4
gpt4 key购买 nike

我有一个在 .NET 4.0 下运行的 Windows 窗体应用程序。此应用程序导入一个 DLL,可用于:

  • 32 位
  • 64 位

这是我的代码片段:

[DllImport("my64Bit.dll"), EntryPoint="GetLastErrorText"]
private static extern string GetLastErrorText();

// Do some stuff...

string message = GetLastErrorText();

调用此函数(针对 x64 编译)时,应用程序会崩溃。我什至在 Visual Studio 2012 中看不到任何调试消息。与 32 位 DLL(为 x86 编译)相同的代码工作正常。原型(prototype)是:

LPCSTR APIENTRY GetLastErrorText()

很遗憾,我没有关于 DLL 的任何进一步信息,因为它是第三方产品。

最佳答案

函数签名比较麻烦。您的代码是否会崩溃取决于您运行的操作系统。在 XP 上没有任何反应,在 Vista 和更高版本上抛出 AccessViolation 异常。

问题在于返回字符串的 C 函数通常需要通过返回指向存储字符串的缓冲区的指针来实现。该缓冲区需要从堆中分配,并且调用者需要在使用该字符串后释放该缓冲区。 pinvoke 编码器实现该协定,它在将返回的字符串指针转换为 System.String 后调用 CoTaskMemFree()。

结果总是很糟糕,C 函数几乎从不使用 CoTaskMemAlloc() 来分配缓冲区。 XP 堆管理器非常宽容,它会忽略坏指针。不是后来的 Windows 版本,它们故意生成异常。顺便说一句,这是“Vista 糟透了”标签的有力插入者,程序员花了一段时间才修复了他们的指针错误。如果启用了非托管调试,那么您将从堆管理器获得诊断信息,警告指针无效。非常好的功能,但是当您调试托管代码时,非托管调试总是被禁用。

您可以通过将返回值声明为 IntPtr 来阻止 pinvoke 编码器尝试释放字符串。然后,您必须使用 Marshal.PtrToStringAnsi() 或其 friend 之一自己编码字符串。

您仍然遇到必须释放字符串缓冲区的问题。没有办法可靠地执行此操作,您无法调用正确的释放器。您唯一的希望是 C 函数实际上返回一个指向字符串文字的指针,该文字存储在数据段中并且应该被释放。这可能适用于返回错误字符串的函数,前提是它没有实现任何像本地化这样的花哨的东西。 const char* 返回类型令人鼓舞。

您需要对此进行测试,以确保不会因未释放字符串缓冲区而导致内存泄漏。很容易做到,在循环中调用此函数十亿次。如果您没有获得 IntPtr.Zero 作为返回值,并且程序没有因内存不足异常而崩溃,那么您就很好。对于 64 位 pinvoke,您需要密切关注测试程序的内存消耗。

关于c# - 使用字符串函数时,应用程序在 64 位 DllImport 上崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13932309/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com