代码之家  ›  专栏  ›  技术社区  ›  Mark Ingram

Windows自动捕获异常,如何手动处理?

  •  20
  • Mark Ingram  · 技术社区  · 15 年前

    当异常被抛出到消息泵中时,我们遇到了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: 正在停用的激活上下文 对当前线程无效 执行。

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

    7 回复  |  直到 10 年前
        2
  •  11
  •   Community CDub    7 年前

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

    “好吧,我发现了更多的信息 关于这个。在我的例子中是Windows7 安装 kiusercallbackexceptionhandler为 异常处理程序,在调用 wndproc和给我执行 控制。这是由 NTDLL!KiuserCallbackDispatcher。我 怀疑这是保安 微软为防止 侵入SEH。

    解决办法是把你的wndproc包起来 (或hookproc)尝试/except 框架。”

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

    来自Microsoft:

    谢谢你的报告。我发现这是一个Windows问题, 还有一个热修复程序。请看 http://support.microsoft.com/kb/976038 对于可以安装的修复程序 如果你愿意的话。

        3
  •  4
  •   SteelBytes    15 年前

    可能感兴趣的功能:

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

    注意,setunhandledExceptionFilter()可以被加载到.exe中的其他dll重写。例如,Flash和Nvidia Direct3D可以做到这一点。我用API挂钩来解决这个问题。

        4
  •  4
  •   Brian    13 年前

    我也遇到过同样的问题,并发现这是由于这个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位OSS上的wndproc例程中被悄悄捕获,除非您发送命令告诉它不要这样做。微软对这个问题有一个修补程序 如果您运行的是Vista SP2,则是必需的,但对于Windows 7 SP1则不是必需的(不确定没有该SP的Win7)。

    即使有了热修复程序,您也需要通过设置注册表项或对内核进行一些调用来启用正确的行为,以告诉它您的进程希望在wndproc期间遇到硬件异常时崩溃。

    根据上面的paulbetts链接,这样做是为了向后兼容WindowsServer2003。

    如果您的程序是64位程序,这个问题就会消失。

        5
  •  3
  •   David    13 年前

    事后给以后偶然发现的人答复。

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

    我见过这个,例外代码是C015000F和C0150010。

        6
  •  2
  •   Community CDub    7 年前

    您可以强制Windows不忽略此代码段的异常(来自Microsoft的 Exceptions that are thrown from an application that runs 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); 
       }
    }
    

    可能你还得加一个 unhandled exception filter :筛选器的作用类似于“顶级异常处理程序”,类似于最顶端的 catch 阻止。从“异常”指针中提取对程序员友好的字符串时,可以看到 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);
    

    您必须在流程的每个线程中都这样做:虽然前面的代码段是每个流程,但是过滤器是每个线程。

        7
  •  -1
  •   Simon Linder    15 年前

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