【问题标题】:Why does Windows swallow exceptions during WM_CLOSE为什么 Windows 在 WM_CLOSE 期间会吞下异常
【发布时间】:2014-05-12 07:34:13
【问题描述】:

在试图弄清楚为什么我正在开发的应用程序无法关闭时,我意识到它在其WM_CLOSE 处理程序中引发了异常。然而,该异常并没有崩溃(应该如此),而是被默默地忽略了。

为了确保没有其他事情发生,我在 Visual Studio 中创建了一个新的 C++ Win32 应用并添加了以下内容:

case WM_CLOSE:
    (*(int*)NULL) = 0;
    break;

同样的事情:没有崩溃,只是调试日志中的第一次机会异常。如果我将相同的代码添加到 WM_COMMAND 处理程序,它会按预期崩溃。

所以我很好奇:WM_CLOSE 有什么特别之处,以至于 Windows 认为应该吞噬它抛出的异常?

(顺便说一句:这是在 Windows 7 x64 上,运行 x86 程序)

【问题讨论】:

  • WM_CLOSE 本身并没有什么特别之处。通过在__try/__except 处理程序下调用WndProc,您的WndProc 回调中未处理的异常总是被静默忽略。这是唯一安全的实现,因为when you transfer control across stack frames, all the frames in between need to be in on the joke
  • 默认情况下,WindoWProcedure 调用destroy window 来销毁窗口。这可能是任何异常都被重定向到“/dev/null”的原因:msdn.microsoft.com/en-us/library/windows/desktop/…msdn.microsoft.com/en-us/library/windows/desktop/…
  • @IInspectable,我不认为 Raymond Chen 说 WndProc 回调在他的文章中受到保护。实际上看起来他说的是相反的:As a result of this overall mindset, Win32 code doesn't worry too much about recovering from exceptions. If an exception happens, then it means your process is already toast and there's no point trying to fix it。此外,如果回调受到保护,则 NULL 指针取消引用也不会在 WM_COMMAND 处理程序中崩溃。
  • @Brad 如果您不想让您的异常被吞下,您需要为您的应用程序提供一个与 Win7 兼容的清单,并编译为 64 位。否则,“旧”的 Win2k3 行为会生效,它会吞下异常。
  • @Brad 拥有有效的 Windows 7 清单足以改变行为。这在The case of the disappearing OnLoad exception 中有详细说明。我应该更准确一点:并非所有异常都默认被吞下,但只有那些WndProc 是内核函数的用户模式回调(例如WM_CREATE/WM_NCCREATE 作为调用CreateWindow 的结果) )。

标签: winapi exception-handling


【解决方案1】:

Win 64 上的WindowProc 吞下异常是预期行为。 (See docs.)

Paul Betts'博客上看到更好的解释,尤其是他的笔记

为什么不是一直都这样?

这就是为什么这似乎只发生在某些窗口消息上的原因—— 请记住,窗口消息可以来自不同的来源, 任何人(*)都可以将消息排队到窗口。但是,某些窗口 消息直接通过 win32k.sys 发送(最值得注意的是 WM_CREATE) 作为用户模式调用的直接同步结果。

似乎对这个问题有所了解。

Random ASCII also 对所有这些 kernel-mode-ex-swallowing 行为都有很好的解释:

根本停不下来

几年前引入了一个同样令人不安的问题 64 位 Windows,它会导致一些崩溃被静默忽略。

结构化异常...依赖于能够展开堆栈 (没有或没有调用析构函数)为了转移 从发生异常的地方执行到 catch/__except 块。

64 位 Windows 的引入使这变得复杂。在 64 位 Windows 上 不可能跨内核边界展开堆栈。也就是说,如果...在回调中抛出异常,即 应该在内核边界的另一侧处理,然后 Windows 无法处理。

这可能看起来有点深奥且不太可能——编写内核回调 似乎是一种罕见的活动——但实际上很常见。在 特别是,WindowProc 是一个回调,它经常由 内核,...

作为奖励:请参阅here on SO on the why

【讨论】:

  • 我认为 Windows 默默地吞下异常是可怕和令人震惊的——Windows 默默地忽略崩溃。 Raymond Chen 的文章指出了在没有每个人都在开玩笑的情况下处理异常的危险,这使得 Windows 这样做更奇怪。顺便说一句,我是此答案中链接的随机 ASCII 文章的作者。
  • @BruceDawson - 我确实同意可怕的说法,但毕竟我已经经历过。 Windows 崩溃处理(从 XP 开始),我不太确定我是否会感到震惊。 :-) ...感谢 Random ASCII - 那里总是有很好的资源!
猜你喜欢
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 2010-11-02
  • 2011-01-05
  • 2018-11-15
  • 1970-01-01
  • 2021-10-22
  • 2015-11-28
相关资源
最近更新 更多