Delphi:应该使用哪个异常类来引发最后的Win32/Win64错误?

3
  1. 在编写一个利用Windows API函数或某些Windows DLL函数(如ntdll.dll)的函数/过程/方法时,应使用哪个Delphi异常类来引发最后的Win32/Win64错误?

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

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

  3. 为了调试目的——我是指与堆栈帧相关的内容——这些差异是否导致每个平台的异常处理具有不同的代码实现?


2
作为一个好奇的旁注,Delphi中的异常与浮点代码不太兼容。例如,一个线程中的外部错误(如AV、FP数学错误)可能会导致另一个线程中的浮点控制字发生变化!去想象一下吧!更多细节请参见:http://qc.embarcadero.com/wc/qcmain.aspx?d=107411 - David Heffernan
1个回答

6
首先,我假设你的问题涉及Delphi,尽管有Free Pascal标签。我基于你引用了Delphi文档来做出这个假设。
应该通过调用RaiseLastOSError将Windows API消息转换为异常。这将引发一个EOSError。那是一个本地的Delphi异常。 EExternalError异常与此无关。当RTL将系统陷阱(例如访问冲突、数学错误等)转换为本地异常时,就会使用它。请注意,Win32通常用于指代32位和64位Windows API。实际上只有一个接口,其中包括32位和64位变体。
32位和64位Windows之间的基础异常处理模型完全不同。32位模型是基于堆栈的,而64位模型是基于表格的。这意味着,在32位和64位架构之间,异常处理和try/finally的实现完全不同。
XE2中64位基于表格的模型的原始实现存在许多缺陷。我很高兴地说,在我和其他人提交了大量QC报告之后,XE3中的实现得到了很大改进。
Stack Overflow不是讨论这两种体系结构的异常处理ABI的低级细节的地方。相反,我提供以下文章:
- Win32™结构化异常处理深度速成课 - x64结构化异常处理

@David_Herffernan,非常感谢,EOSError类正是我所需要的。此外,对于由某些Windows DLL函数(例如ntdll.dll)引起的异常,应使用哪个异常类? - Astaroth
对于所有的Win32 API调用,我会使用EOSError。你需要一个Win32错误代码。大多数函数在失败时调用SetLastError。因此,您可以调用无参数的RaiseLastOSError,它将依次调用GetLastError。有些函数返回Win32错误代码。在这种情况下,您需要捕获它并调用带有Win32错误代码参数的RaiseLastOSError重载函数。 - David Heffernan
谢谢,我知道这个。实际上,我上面进一步提出问题的目的是想知道是否有本地异常类可以给我提供发生错误的 DLL 名称。 - Astaroth
2
@Astaroth 没有这样的事情。如果你调用了函数,你就知道它在哪个 DLL 中。这是你能做的最好的事情。 - David Heffernan
1
你调用的函数可能会调用其他 DLL。要获取引发异常的函数,请调用 ExceptAddr 来查找指令地址。将该地址与 Get_Module_Handle_Ex_Flag_From_Address 标志一起传递给 GetModuleHandleEx。将句柄传递给 GetModuleFileName - Rob Kennedy
1
@RobKennedy 只有在 WinAPI 函数引发异常时才有用。但这种情况非常罕见。通常是编程错误,即传递了一个不良指针而导致 AV,而不是 Win32 错误。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接