关于c ++:MessageBox“异常程序终止”使我的应用程序保持运行

MessageBox “Abnormal program termination” keeps my application running

……种类。正如这个极其简单的例子所说明的,

enter image description here

很少(到目前为止只有一次报告),我的一个应用程序会以这种方式崩溃。我想像往常一样在发生非特定异常时终止它。我的策略是(低级)记录问题,然后终止。应用程序是子系统的一部分,如果检测到任何问题,我希望(重新)启动它。它是用C++Builder 6构建的,在Windows上运行(XP…7,也有8)。我了解到一个abort()很可能导致了错误消息。应用程序有一个图形用户界面,这就是为什么显示一个消息框而不只是向stderr输出(解除锁定)。

只要消息框不被用户接受,我的应用程序就会保持明显的运行,例如它处理计时器(上面例子中的生命周期增加)或进程间消息,完全不知道问题所在。

在阅读了一些什么是最简单的方法使C++程序崩溃的答案?以及raise(sigabrt)和abort()方法之间的区别,我尝试了以下方法

1
2
3
4
5
6
7
8
9
10
11
void mySignalHandler(int sig)
{
    // low-level error reporting here
    exit(-1);
}

void __fastcall TForm1::FormCreate(TObject *Sender)
{
    signal(SIGABRT, mySignalHandler);
    // some more initialisation here
}

如果调用abort()raise(SIGABRT),我的应用程序也可以正常终止。(我还希望阻止Windows"搜索问题的解决方案"。)

从您的角度来看,这(注册一个用于中止和调用退出的信号处理程序)是否可靠?…或者至少是可以建立的东西?


在C++Builder安装文件夹中,检查以下文件:

  • sourcecpprtlsourcemiscerrormsg.c-_ErrorMessage的实现
  • source cpprtl source process abort.c-abort的实现,它调用_ErrorMessage
  • source cpprtl source misc assert.c-_assert的实现,它调用_ErrorMessage

errormsg.c定义了一个未记录的_messagefunc函数指针,可以将其设置为重写默认行为。虽然它是未记录的,并且没有在任何头文件中声明,但是您可以将其声明为extern,并以这种方式访问它。样品使用情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
extern int (_RTLENTRY * _EXPDATA _messagefunc)(char *msg);

static int LogAndDie(char *msg)
{
  LogMessageToSomeFile(msg);
  exit(1);
  return 0;
}

void InitializeErrorHandling()
{
  _messagefunc = LogAndDie;
}


我可以做一些测试,我只能确认注册sigabrt信号处理程序只是一个noop。

我用一个用VS2008 Express编写的非常简单的GUI应用程序进行了尝试。:

  • 没有框架,也没有.NET,只有win-api
  • 一个带有退出和致命功能的菜单
  • 直接在wndproc中管理的菜单
  • 致命执行1/0

结果如下:

  • 无特殊操作=>Windows打开一个消息框,指示一个致命错误…
  • sigabrt的信号处理程序=>相同的消息框
  • C++尝试catch(…)= >同样的MessageBox
  • WNDPROC中的SEH:可以拦截错误!
  • SEH消息循环:可以截获错误!

如果我使用bot-seh处理程序,则最内部的(wndproc)捕获。

对您来说,好的新功能是,如果足以保护消息循环,那么您就不必进入每个wndproc。

坏消息是我不知道C++ Builder,不能说在哪里找到消息循环。

为了给您一个提示,下面是我如何保护winapi应用程序中的消息循环:

1
2
3
4
5
6
7
8
9
10
11
12
13
__try {
while (GetMessage(&msg, NULL, 0, 0))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
}
__except (EXCEPTION_EXECUTE_HANDLER){
    ::MessageBox(NULL, _T("FATAL"), _T("MAIN"), MB_OK | MB_ICONERROR);
}

这样,我就可以看到我自己的消息框,但没有其他内容,而且如果我对消息框进行评论,应用程序将自动退出。

但是…由于您显示的消息不是原始Windows一,所以我怀疑C++Builder已经在消息循环中有这样一个异常处理程序。

希望有帮助…


如果要捕获任何程序退出,应查看at exit()。如果要捕获所有终止事件,请查看std::set_terminate(),如果要捕获所有意外的异常,请查看std::set_unexpected()。如果只想捕获abort(),可以使用SIGABRT信号值调用signal()。您还可以使用try{your code}catch(...){custom event handler}包装您的代码。


当未处理的异常导致终止时,您可能可以使用Windows错误报告来创建进程的转储。然后您可以在空闲时查看转储,并允许一些父进程或其他看门狗重新启动您的进程。如果您选择这个策略,您将不会尝试处理代码中的失败,而是允许它。