20

当异常在消息泵中抛出时,我们遇到了 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。
Test.exe 中 0x77c6ee42 处的第一次机会异常:0xC0150010:被停用的激活上下文对于当前执行线程无效。

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

4

7 回答 7

12

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

于 2011-02-02T13:28:46.207 回答
11

在浏览了类似的问题后,我偶然发现了这个答案: OpenGL suppresses exceptions in MFC dialog-based application

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

解决方案是用 try/except 框架包装你的 wndproc(或 hookproc)。”

我已经向 Microsoft 提交了错误报告,您可以在此处查看他们的回复:
http ://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught -in-wndproc-消息

来自微软:

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

于 2010-04-12T14:29:47.697 回答
4

可能感兴趣的功能:

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

PS,请注意 SetUnhandledExceptionFilter() 可以被加载到您的 .exe 中的其他 dll 覆盖。例如,flash 和 nvidia direct3d 就是这样做的。我使用 api hooking 来解决这个问题。

于 2010-04-12T13:08:43.883 回答
4

我遇到了同样的问题,发现这是 Microsoft 错误的结果: 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 位程序,这个问题就消失了。

于 2012-01-10T23:56:15.367 回答
3

对于以后偶然发现此问题的任何人,事后回答。

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

我已经看到了异常代码 c015000f 和 c0150010。

于 2011-08-05T22:53:34.413 回答
2

您可以使用以下代码片段强制 Windows 不忽略异常(来自 Microsoft 的Exceptions that are throw from an application that running in a 64-bit version of Windows are ignored),您将在您的进程代码中放入:

// 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 中提取程序员友好的字符串,您可以看到Is there a function to convert EXCEPTION_POINTERS struct to a string?

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

您添加过滤器:

::SetUnhandledExceptionFilter(my_filter);

您必须在进程的每个线程中执行此操作:虽然前面的代码片段是每个进程的,但过滤器是每个线程的。

于 2012-11-28T08:34:19.740 回答
-1

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

于 2010-04-12T13:21:01.943 回答