为什么在win32计时器回调中抛出未处理的异常不会被调试器视为未处理的异常?

时间:2012-01-18 00:00:36

标签: c++ winapi exception

我一直在追踪工作中一个非常阴险的错误。似乎导致我一直在跟踪的非常奇怪的行为的事件似乎是在处理计时器回调时抛出的异常。异常不是由我的任何代码处理的,因此我希望调试器会收到未处理异常的通知,并提醒我一个不错的弹出窗口。不,相反,“第一次机会”异常消息会跟踪到调试器,并且所有内容都会静默移动。

我已经写了以下程序来演示这个问题:

#include "stdafx.h"
#include <Windows.h>

class FooExcept
{
};

VOID CALLBACK Timer(HWND hwnd,
    UINT uMsg,
    UINT_PTR idEvent,
    DWORD dwTime)
{
    printf("Here\n");
    throw FooExcept();
    printf("Also Here\n");
}


int _tmain(int argc, _TCHAR* argv[])
{
    SetTimer(0, 0, 1000, Timer);

    int bRet;
    HWND hWnd;
    MSG msg;
    // Standard Win32 message pump
    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
    { 
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }
    }

    return 0;
}

此程序到Visual Studio输出窗口的输出重复:

First-chance exception at 0x76dbb9bc in TimerTest.exe: Microsoft C++ exception: FooExcept at memory location 0x0034f743..

当然,我的项目要复杂得多,并且会向调试器打印出大量的TRACE信息。第一次机会异常很容易在输出中丢失。

无论其

这不是我关心的问题。这显然是一个例外,我没有处理。 Windows是否偷偷地决定为我处理这个问题?为什么?如果没有,为什么不给我一个明确的弹出窗口警告我未处理的异常?这样的弹出窗口可以节省我几天的调试时间。

这种行为在XP / VS 2008和Win7 / VS 2010之间似乎是一致的。

2 个答案:

答案 0 :(得分:7)

在Windows 7 SP1中已经在某种程度上修复了这个问题(见下文)。

在文章http://support.microsoft.com/kb/976038中,您会发现有关错误修正的说明以及如何使用它来禁用此行为的说明。你必须要么:

  • 在注册表中设置流程选项或
  • SetProcessUserModeExceptionPolicy
  • 导出的调用函数kernel32.dll

我已经在Updates in Win7 and WS08R2 SP1.xls验证了此错误修复确实包含在Windows 7 Service Pack 1中,因此您所要做的就是启用它(假设您已经安装了Windows 7 SP1)。

至于解释为什么要这样做,我们可以猜测一些不明智的尝试,以防止遗留应用程序以向后兼容性的名义崩溃。< / p>

答案 1 :(得分:0)

对于消息本身,我不知道,但是对于错误路径,这是因为回调来自操作系统。然后,异常返回到OS,而不是返回到您的程序或调试器。在Linux上相同。在这种情况下,您会得到一个奇怪的错误。解决方案是使用自定义接口或错误回调将错误返回给程序调用者。同样的问题也出现在多线程应用程序中,其中线程是由操作系统创建的,并且异常也会返回到操作系统而不是您的程序。操作系统对您的异常处理程序一无所知。