Windows默默捕获异常,如何手动处理?
当异常在消息泵内抛出时,我们遇到了 Windows 静默处理异常并允许应用程序继续运行的问题。例如,我们创建了一个测试 MFC MDI 应用程序,并覆盖了 OnDraw:
void CTestView::OnDraw(CDC* /*pDC*/)
{
*(int*)0 = 0; // Crash
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
}
运行该应用程序时您会期望出现令人讨厌的错误消息,但实际上您什么也得不到。该程序似乎运行得很好,但是如果您检查输出窗口,您将看到:
第一次机会异常 Test.exe 中的 0x13929384: 0xC0000005:写入访问冲突 位置 0x00000000。
0x77c6ee42 处的第一次机会异常 在Test.exe中:0xC0150010: 激活上下文被停用 对于当前线程不活跃 执行。
我知道为什么我会收到应用程序上下文异常,但为什么它会被静默处理?这意味着我们的应用程序在使用时可能会遇到严重的问题,但我们永远不会知道,因为我们的用户永远不会报告任何问题。
We're having problems with Windows silently eating exceptions and allowing the application to continue running, when the exception is thrown inside the message pump. For example, we created a test MFC MDI application, and overrode OnDraw:
void CTestView::OnDraw(CDC* /*pDC*/)
{
*(int*)0 = 0; // Crash
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
}
You would expect a nasty error message when running the application, but you actually get nothing at all. The program appears to be running perfectly well, but if you check the output window you will see:
First-chance exception at
0x13929384 in Test.exe:
0xC0000005: Access violation writing
location 0x00000000.
First-chance exception at 0x77c6ee42
in Test.exe: 0xC0150010: The
activation context being deactivated
is not active for the current thread
of execution.
I know why I'm receiving the application context exception, but why is it being handled silently? It means our applications could be suffering serious problems when in use, but we'll never know about it, because our users will never report any problems.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如果您在 x64 操作系统上运行,您可能会遇到以下问题:
http://blog.paulbetts.org/ index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/
或者(在这种情况下不太可能),它可能是这样的:
http://blogs.msdn.com/b/oldnewthing/archive/2011/01/20/10117963.aspx
If you're running on an x64 OS you may have been bitten by this:
http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/
Or (less likely in this case), it may be this:
http://blogs.msdn.com/b/oldnewthing/archive/2011/01/20/10117963.aspx
在浏览类似的问题后,我偶然发现了这个答案:
OpenGL 抑制基于 MFC 对话框的应用程序中的异常
我已向 Microsoft 提交了错误报告,您可以在此处查看他们的回复:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages
来自 Microsoft:
After browsing similar questions I stumbled across this answer:
OpenGL suppresses exceptions in MFC dialog-based application
I've filed a bug report with Microsoft, you can see their response here:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages
From Microsoft:
可能感兴趣的函数:
PS,请注意 SetUnhandledExceptionFilter() 可以被加载到 .exe 中的其他 dll 覆盖。例如,flash 和 nvidia direct3d 可以执行此操作。我使用 api hooking 来解决这个问题。
functions that may be of interest:
PS, be aware that SetUnhandledExceptionFilter() can be overriden by other dlls loaded into your .exe. eg, flash and nvidia direct3d do this. I use api hooking to cure this.
我遇到了同样的问题,发现这是 Microsoft 错误的结果:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages
Microsoft 提供了一个修复程序,但如果您有多个目标平台,部署它会有些困难:
http://support.microsoft.com/kb /976038
这是一篇关于该主题的文章,描述了该行为:
http://blog.paulbetts.org/index.php/2010/07/20/the-case-of- the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/
问题基本上是 32 位程序中的硬件异常在 64 位操作系统上的 WndProc 例程中被静默捕获,除非你发送命令告诉它不要这样做。 Microsoft 针对此问题提供了一个修补程序,如果您运行的是 Vista SP2,则需要该修补程序,但 Windows 7 SP1 则不需要该修补程序(不确定不带 SP 的 Win7 是否如此)。
即使使用修补程序,您也需要通过设置注册表项或对内核进行一些调用来告诉它您的进程在 WndProc 期间遇到硬件异常时会崩溃,以启用正确的行为。
根据上面的 PaulBetts 链接,这样做是为了向后兼容 Windows Server 2003。
如果您的程序是 64 位程序,则此问题就会消失。
I experienced this same issue, and found it was a result of this Microsoft bug:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages
There’s a fix available from Microsoft, though deploying it is somewhat challenging if you have multiple target platforms:
http://support.microsoft.com/kb/976038
Here's an article on the subject describing the behavior:
http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/
The issue is basically that Hardware exceptions in 32-bit programs are silently caught in the WndProc routine on 64-bit OSs, unless you send commands telling it not to. Microsoft has a hotfix for the issue that is required if you're running Vista SP2, but isn't required with Windows 7 SP1 (not sure about Win7 without the SP).
Even WITH the hotfix, you need to enable the correct behavior by setting a registry key or making some calls to the kernel to tell it your process expects hardware exceptions to crash when encountered during WndProc.
According to the PaulBetts link above, this was done for backwards compatibility with Windows Server 2003.
If you program is a 64-bit program, this issue goes away.
您可以使用此代码片段强制 Windows 不忽略异常(来自 Microsoft 的 从应用程序抛出的异常在 64 位版本的 Windows 中运行的内容将被忽略),您将把它放入进程代码中:
您可能还必须添加 未处理的异常过滤器:过滤器的作用类似于“顶级异常处理程序”最上面的
catch
块。要从 _EXCEPTION_POINTERS 中提取程序员友好的字符串,您可以看到 是否有一个函数可以将 EXCEPTION_POINTERS 结构转换为字符串?您添加过滤器:
并且您必须在进程的每个线程中执行此操作:虽然前面的代码片段是每个进程的,但过滤器是每个线程的。
You can force Windows to not ignore the exceptions with this code snippet (from Microsoft's Exceptions that are thrown from an application that runs in a 64-bit version of Windows are ignored) that you will put in your process code:
It may be you have to add also an unhandled exception filter: the filter acts like a "top level exception handler" that is like a topmost
catch
block. For extracting a programmer-friendly string from _EXCEPTION_POINTERS you can see Is there a function to convert EXCEPTION_POINTERS struct to a string?You add the filter with:
and you have to do it in every threads of your process: while the previous snippet is per-process, the filter is per-thread.
对于后来偶然发现这一点的人来说,事后回答。
这是由 Windows http://support.microsoft.com/kb/976038 - 确保您处于最新状态,根据需要安装热补丁,并将您的应用程序标记为与 Windows 7 兼容。 http://msdn.microsoft.com/en -us/library/dd371711%28v=vs.85%29.aspx
我已经看到了异常代码 c015000f 和 c0150010。
ANSWER IN HINDSIGHT for anyone who stumbles upon this later.
This was caused by a known issue in Windows http://support.microsoft.com/kb/976038 - make sure you're up to date, install the hotpatch if you need to, and mark your application as Windows 7 compatible. http://msdn.microsoft.com/en-us/library/dd371711%28v=vs.85%29.aspx
I've seen this with exception codes c015000f and c0150010.
您的输出看起来像是您正在使用 Visual Studio...
如果没有忘记我的回答。
您可以指定正常抛出哪些异常,这意味着 Visual Studio 会捕获它们,并且您的程序会在发生访问冲突的地方停止。在“调试/异常...”菜单中执行此操作。如果您不确定要启用什么,只需将它们全部启用...
Your output looks like you're using Visual Studio...
If not forget about my answer.
You can specify which exceptions will be thrown normally, meaning that Visual Studio catches them and your progam stops where the access violation occurred. Do this in the Debug/Exceptions... menu. If you are not sure what to enable, just enable them all...