Winapi 为什么Windows在WM_关闭期间会吞下异常
当我试图弄清楚为什么我正在开发的应用程序无法关闭时,我意识到它在其Winapi 为什么Windows在WM_关闭期间会吞下异常,winapi,exception-handling,Winapi,Exception Handling,当我试图弄清楚为什么我正在开发的应用程序无法关闭时,我意识到它在其WM\u close处理程序中抛出了一个异常。然而,应用程序并没有崩溃(它应该崩溃),异常会被默默地忽略 为了确保没有其他事情发生,我在VisualStudio中创建了一个新的C++ Win32应用程序,并添加了: case WM_CLOSE: (*(int*)NULL) = 0; break; 同样的事情:没有崩溃,只是调试日志中第一次出现异常。如果我将相同的代码添加到WM_命令处理程序中,它会按预期崩溃 所以
WM\u close
处理程序中抛出了一个异常。然而,应用程序并没有崩溃(它应该崩溃),异常会被默默地忽略
<>为了确保没有其他事情发生,我在VisualStudio中创建了一个新的C++ Win32应用程序,并添加了:
case WM_CLOSE:
(*(int*)NULL) = 0;
break;
同样的事情:没有崩溃,只是调试日志中第一次出现异常。如果我将相同的代码添加到WM_命令
处理程序中,它会按预期崩溃
所以我很好奇:WM_CLOSE
有什么特别之处,以至于Windows认为它抛出的异常应该被忽略
(顺便说一句:这是在运行x86程序的Windows 7 x64上)Win 64上的
WindowProc
会吞噬异常是预期行为。()
也可以在博客上看到更好的解释,尤其是他的笔记
为什么这种情况不会一直发生?
这就是为什么这种情况似乎只发生在某些窗口消息上——
请记住,窗口消息可以来自不同的来源,
任何人(*)都可以将消息排入窗口队列。然而,某些窗口
消息直接通过win32k.sys发送(最值得注意的是
WM_CREATE)作为用户模式调用的直接同步结果
似乎对这个问题有所启发
对所有这些内核模式ex吞咽行为有一些很好的解释:
根本没有停下来
几年前,一个同样令人不安的问题被提出
64位Windows,它会导致一些崩溃被静默忽略
结构化异常。。。依赖于能够展开堆栈
(不调用或不调用析构函数)以便传输
catch/\uuu except块发生异常的位置执行
64位Windows的引入使这一点变得复杂。在64位Windows上
不可能跨内核边界展开堆栈。也就是说,如果。。。在回调中引发异常,该回调是
应该在内核边界的另一侧处理,然后
Windows无法处理此问题
这似乎有点深奥,也不太可能——编写内核回调
这似乎是一种罕见的活动,但实际上相当普遍。在里面
特别是,WindowProc是一个回调,它通常由
内核
还有一个额外的好处:请看。WM\u CLOSE本身没有什么特别之处。通过调用
\u try
/\u处理程序下的WndProc
,您的WndProc
回调中未处理的异常始终被静默忽略。这是唯一安全的实现,因为。默认情况下,WindoWProcedure调用destroy window来销毁窗口。这可能是一个原因,任何异常都会被重定向到“/dev/null”:并且@IInspectable,我不认为Raymond Chen在他的文章中说WndProc
回调受到保护。实际上,看起来他说的正好相反:由于这种总体思维,Win32代码不太担心从异常中恢复。如果发生异常,则意味着您的流程已经结束,并且没有必要尝试修复它
。此外,如果回调受到保护,则在WM_命令
处理程序中,空指针取消引用也不会崩溃。@Brad如果您不想吞没异常,则需要为应用程序提供与Win7兼容的清单,并编译为64位。否则,“旧的”Win2k3行为将生效,这将吞噬异常。@拥有有效的Windows 7清单足以更改该行为。详细信息请参见。我应该说得更准确一些:默认情况下并不是所有的异常都会被吞没,只有那些WndProc
是内核函数的用户模式回调的异常才会被吞没(例如,WM\u CREATE
/WM\u NCCREATE
是调用CreateWindow
的结果).我认为Windows默默地接受异常是可怕和令人震惊的——Windows默默地忽略崩溃。Raymond Chen的文章指出了在没有所有人参与的情况下处理异常的危险,这使得Windows这样做更加奇怪。顺便说一句,我是这个答案中链接的随机ASCII文章的作者。@BruceDawson-我确实同意可怕的说法,但毕竟我经历过wrt。Windows崩溃处理(从XP开始),我不太确定我是否发现了太多令人震惊的事情。:-。。。感谢您提供的随机ASCII-这里总是有大量资源!