【问题标题】:Delphi: Which exception class should be used to raise last Win32/Win64 errors?Delphi:应该使用哪个异常类来引发最后的 Win32/Win64 错误?
【发布时间】:2012-10-04 12:27:27
【问题描述】:
  1. 在编写利用 Windows API 函数或某些 Windows DLL(例如 ntdll.dll)的函数的函数/过程/方法时,应该使用哪个 Delphi 异常类来引发最后的 Win32/Win64 错误?

    引自 Delphi XE3 文档关于 System.SysUtils.EExternal:

    "注意:EExternal 类代表 Win32 异常代码。ExceptionRecord 成员指向 Win32 异常记录。"
  2. 从那时起,我得出结论,Win32 和 Win64 异常机制之间存在差异。它们之间有什么区别?

  3. 出于调试目的——我的意思是关于堆栈帧相关的东西——差异是否会导致每个平台的异常处理的代码实现不同?

【问题讨论】:

  • 除了好奇之外,Delphi 中的异常不能很好地与浮点代码混合。例如,一个线程中的外部错误(例如 AV、FP 数学错误)可能会导致 不同线程中的浮点控制字发生变化!去弄清楚那个!更多细节在这里:qc.embarcadero.com/wc/qcmain.aspx?d=107411

标签: delphi freepascal


【解决方案1】:

首先,我假设您的问题与 Delphi 有关,尽管有 Free Pascal 标签。我的假设是基于您引用 Delphi 文档这一事实。

应通过调用 RaiseLastOSError 将 Windows API 消息转换为异常。这将引发EOSError。这是一个原生的 Delphi 异常。

EExternalError 异常无关。这就是 RTL 转换系统陷阱时使用的内容,例如访问冲突、数学错误等进入本机异常。请注意,Win32 通常用于指代 32 位和 64 位 Windows API。实际上只有一个接口同时具有 32 位和 64 位变体。

32 位和 64 位 Windows 之间的底层异常处理模型完全不同。 32 位模型是基于堆栈的,而 64 位模型是基于表的。这意味着异常处理和 try/finally 的实现在 32 位和 64 位架构之间是完全不同的。

基于 64 位表的模型在 XE2 中的原始实现存在大量错误。很高兴的说,经过我和其他人提交的多份QC报告,在XE3中的实现有了很大的改进。

堆栈溢出不是深入了解这两种架构的异常处理 ABI 的低级细节的地方。相反,我提供以下文章:

【讨论】:

  • @David_Herffernan,非常感谢,EOSError 课程正是我想要的。此外,对于某些 Windows DLL(例如 ntdll.dll)的函数引起的异常,应该使用哪个异常类?
  • 我会说 EOSError 用于所有 Win32 API 调用。您需要一个 Win32 错误代码。大多数函数调用SetLastError 以防失败。所以你可以调用无参数的RaiseLastOSError,它又会调用GetLastError。某些函数返回 Win32 错误代码。在这种情况下,您捕获它并调用以 win32 错误代码作为参数的 RaiseLastOSError 重载。
  • @Astaroth 没什么。如果你调用了这个函数,你就知道它在哪个 DLL 中。这是你能做的最好的。
  • 您调用的函数可能会调用其他 DLL。要获取引发异常的函数,请调用ExceptAddr 以发现指令地址。使用Get_Module_Handle_Ex_Flag_From_Address 标志将该地址传递给GetModuleHandleEx。将句柄传递给GetModuleFileName
  • @RobKennedy 这只有在 WinAPI 函数引发异常时才有用。他们很少这样做。它通常是编程错误,即传入导致 AV 的 duff 指针,而不是 Win32 错误。
猜你喜欢
  • 2016-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多