无声无息地被Windows捕获的exception,如何手动处理?

我们遇到了Windows的问题,静静地吃着exception,并允许应用程序继续运行,当exception在消息泵中抛出时。 例如,我们创build了一个testingMFC 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的第一次机会exception:0xC0000005:访问冲突写入位置0x00000000。
Test.exe中0x77c6ee42的第一次机会exception:0xC0150010:当前正在执行的线程未激活正在激活的激活上下文。

我知道为什么我收到应用程序上下文exception,但为什么它被默默处理? 这意味着我们的应用程序在使用时可能会遇到严重的问题,但我们永远不会知道,因为我们的用户永远不会报告任何问题。

如果您在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

在浏览类似的问题后,我偶然发现了这个答案: OpenGL在MFC基于对话框的应用程序中抑制异常

“好的,我发现了更多关于这个的信息,在我的情况下,它是安装KiUserCallbackExceptionHandler作为异常处理程序的Windows 7,在调用我的WndProc并给予执行控制权之前,这是由ntdll!KiUserCallbackDispatcher完成的,我怀疑这是一个安全微软为防止黑客进入SEH而采取的措施。

解决方法是用你的wndproc(或者hookproc)包装一个try / except帧。

我已经向微软提交了一个错误报告,你可以在这里看到他们的回应:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages

来自微软:

感谢您的报告。 我发现这是一个Windows问题,并有一个可用的修复程序。 请参阅http://support.microsoft.com/kb/976038以获得可以根据需要安装的修复程序。

可能感兴趣的功能:

 SetUnhandledExceptionFilter() _set_invalid_parameter_handler() _RTC_SetErrorFuncW() _CrtSetReportHookW2() 

PS,请注意,SetUnhandledExceptionFilter()可以被加载到您的.exe中的其他dll重写。 例如,闪存和NVIDIA Direct3D做到这一点。 我使用API​​钩来治愈这个。

我遇到了同样的问题,并发现这是由于这个微软的bug: http : //connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught -in-的WndProc的消息

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例程中默默地捕获,除非您发送命令告诉它不要。 如果您运行的是Vista SP2,则Microsoft需要使用此修复程序,但Windows 7 SP1不需要该修复程序(不知道没有SP的Win7)。

即使使用修补程序,也需要通过设置注册表项或调用内核来启用正确的行为,以告知您的进程在WndProc期间遇到硬件异常崩溃。

根据上面的PaulBetts链接,这是为了向后兼容Windows server 2003而完成的。

如果你的程序是一个64位的程序,这个问题就消失了。

对于任何后来遇到这种情况的人来说,

这是由Windows中的一个已知问题引起的http://support.microsoft.com/kb/976038 – 确保您是最新的,如果需要的话安装hotpatch,并将您的应用程序标记为Windows 7兼容。 http://msdn.microsoft.com/en-us/library/dd371711%28v=vs.85%29.aspx

我看过这个例外代码c015000f和c0150010。

您可以强制Windows不要忽略这些代码片段(从忽略在64位版本的Windows中运行的应用程序抛出的 Microsoft 异常)中的异常,这些异常将放入进程代码中:

 // my SDK is v6.0A and the two APIs are not available in the .h files, so I need to get them at runtime #define PROCESS_CALLBACK_FILTER_ENABLED 0x1 typedef BOOL (WINAPI *GETPROCESSUSERMODEEXCEPTIONPOLICY)(__out LPDWORD lpFlags); typedef BOOL (WINAPI *SETPROCESSUSERMODEEXCEPTIONPOLICY)(__in DWORD dwFlags ); HINSTANCE h = ::LoadLibrary(L"kernel32.dll"); if ( h ) { GETPROCESSUSERMODEEXCEPTIONPOLICY GetProcessUserModeExceptionPolicy = reinterpret_cast< GETPROCESSUSERMODEEXCEPTIONPOLICY >( ::GetProcAddress(h, "GetProcessUserModeExceptionPolicy") ); SETPROCESSUSERMODEEXCEPTIONPOLICY SetProcessUserModeExceptionPolicy = reinterpret_cast< SETPROCESSUSERMODEEXCEPTIONPOLICY >( ::GetProcAddress(h, "SetProcessUserModeExceptionPolicy") ); if ( GetProcessUserModeExceptionPolicy == 0 || SetProcessUserModeExceptionPolicy == 0 ) { return; } DWORD dwFlags; if (GetProcessUserModeExceptionPolicy(&dwFlags)) { SetProcessUserModeExceptionPolicy(dwFlags & ~PROCESS_CALLBACK_FILTER_ENABLED); } } 

这可能是你还必须添加一个未处理的异常过滤器 :过滤器就像一个“顶级异常处理程序”就像一个最上面的catch块。 为了从_EXCEPTION_POINTERS提取一个程序员友好的字符串,你可以看到是否有一个函数将EXCEPTION_POINTERS结构转换为字符串?

 LONG WINAPI my_filter(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo) { ::OutputDebugStringA("an exception occured!"); return EXCEPTION_EXECUTE_HANDLER; } 

您添加过滤器:

 ::SetUnhandledExceptionFilter(my_filter); 

而且你必须在你的进程的每个线程中执行它:当前面的代码片段是per-process时,过滤器是每个线程的。

你的输出看起来像你正在使用Visual Studio …
如果不忘记我的答案。
您可以指定哪些异常将被正常抛出,这意味着Visual Studio捕获它们,并且您的程序停止发生访问冲突。 在Debug / Exceptions …菜单中执行此操作。 如果您不确定要启用什么,只需启用它们即可