MessageBox“程序异常终止”让我的应用程序继续运行

Posted

技术标签:

【中文标题】MessageBox“程序异常终止”让我的应用程序继续运行【英文标题】:MessageBox "Abnormal program termination" keeps my application running 【发布时间】:2014-10-07 23:07:18 【问题描述】:

...有点。正如这个极其简单的例子所示,

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

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

在阅读了What is the easiest way to make a C++ program crash?和Difference between raise(SIGABRT) and abort() methods的一些答案后,我尝试了以下

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“寻找问题的解决方案”。)

从您的角度来看,这(为 abort 注册一个信号处理程序并在那里调用 exit)可靠吗? ...或者至少可以建立一些东西?

【问题讨论】:

为什么不简单地尝试调试程序以找出崩溃的原因?如果你修复了崩溃,它们就不会再发生了。 使用 POSIX 信号 api 来捕获 Windows 问题并不能很好地工作。使用 SEH。 @JoachimPileborg 这并不简单,但我这样做了。同时系统无论如何都要运行...... @bmargulies 一个用户报告了这个消息框(直到今天才一次),我的应用程序没有使用 POSIX 信号,它一定是由某些库引起的。 “只要消息框不被用户接受,我的应用程序显然会继续运行,”- wat 【参考方案1】:

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

source\cpprtl\Source\misc\errormsg.c - _ErrorMessage 的实现 source\cpprtl\Source\procses\abort.c - 实现abort,它调用_ErrorMessage source\cpprtl\Source\misc\assert.c - 实现_assert,它调用_ErrorMessage

errormsg.c 定义了一个未记录的_messagefunc 函数指针,您可以将其设置为覆盖默认行为。尽管它没有记录,也没有在任何头文件中声明,但您可以将其声明为 extern 并以这种方式访问​​它。示例用法:

extern int (_RTLENTRY * _EXPDATA _messagefunc)(char *msg);

static int LogAndDie(char *msg)

  LogMessageToSomeFile(msg);
  exit(1);
  return 0;


void InitializeErrorHandling()

  _messagefunc = LogAndDie;

【讨论】:

我认为您的建议需要重新考虑。 _messagefunc 指向的函数应该只处理错误消息,即记录它。被_ErrorMessage间接调用,这个函数也用在非致命的情况下。 @Wolf - 嗯。几年来,我们一直在生产环境中使用 _messagefunc 运行代码(不是按照您的意愿终止,而是使用 _messagefunc 将错误转化为问题跟踪器的问题报告)。我在实践中看到的唯一非致命错误是数学错误(例如取log(0)),这对于您的应用程序域可能不是问题。无论如何,检查strcmp(msg, "Abnormal program termination") == 0 应该足以只得到致命错误。 建议的解决方案没有帮助,但研究的建议有帮助。它帮助我更好地了解发生了什么。所以我接受这是迄今为止最好的最有帮助的答案。【参考方案2】:

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

【讨论】:

除了 Windows 错误报告的想法(我还有待探索):我不认为在这种情况下存在飞行异常。【参考方案3】:

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

【讨论】:

也许我对此不够清楚:异常真的不是我的问题,而是没有异常。 If you want to capture only abort() you can call signal() with the SIGABRT signal value. 这正是我所做的。毫无疑问,这在技术上是可行的。 (您的答案中的所有其他信息都与我的问题无关,所以,对不起,-1)相反,我想知道,在调用此函数时如何正确退出我的程序。我会尝试将此详细信息添加到问题中。 @Wolf 我的回答是在您第一次在这里提出问题时理解您的问题 - 从那时起您已经对原始问题进行了 6 次编辑。您自己在上面承认,您可能不够清楚。 我觉得您的回答与问题的第一个版本不匹配 ***.com/posts/25305653/timeline 我在第一条评论中说过。关于可能的编程错误,您的回答非常普遍(例如,将其与this answer 进行比较)。你不认为你可以更具体吗? @Wolf 如果您的问题一开始就很清楚,那么为什么之后需要对您的问题进行六次编辑?当问题出在你自己写得不好的问题上时,也许你不应该投票给别人。【参考方案4】:

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

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

没有框架,也没有 .NET,只有 Win API 一个带有退出和致命的菜单 直接在 WndProc 中管理的菜单 致命执行 1/0

结果如下:

没有特殊操作 => windows 打开一个 MessageBox 指示致命错误... SIGABRT 的信号处理程序 => 相同的 MessageBox C++ 尝试 catch(...) => 相同的消息框 WndProc 中的 SEH:可以拦截错误! 消息循环周围的 SEH:可以拦截错误!

如果我放置机器人 SEH 处理程序,最内部 (WndProc) 会捕获。

对您来说,好消息是 if 足够 来保护消息循环,并且您不必进入每个 WndProc。

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

只是给你一个线索,下面是我如何保护 WinAPI 应用程序中的消息循环:

__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++ 构建器在其消息循环中已经有这样一个异常处理程序。

希望对你有帮助...

【讨论】:

感谢您的研究! C++-Builder(6) GUI 应用程序基于 VCL 框架。消息循环由Application::Run 运行,不受应用程序源的直接影响。我希望更好地遵守这个约定。 我曾经(很久很久以前)使用过 BC 编译器,如果我没记错的话,主应用程序类扩展了 Application,并且可以覆盖很多东西(包括 run 或 .. 。环形)。还可以吗? 这是在很早的TVision 时代,它在 Windows 下发生了变化,因为 Windows 本身是基于自己的事件控制的 GUI 概念。 不太老,Windows 3.11 时代,但它仍然在我的记忆中很远......由于 VCL 不公开可用,我只能建议你照顾所有可覆盖的方法......

以上是关于MessageBox“程序异常终止”让我的应用程序继续运行的主要内容,如果未能解决你的问题,请参考以下文章

如何在pl sql中跟踪异常终止

我的 C++ 程序在内存不足时究竟是如何终止的?

MessageBox.Show不适用于我的Visual Studio

即使在异常终止时,如何确保调用 UnhookWindowsHookEx?

3-QT程序运行时报错E:SogouInput6.7.0.0329程序异常终止,该怎么解决?

彻底解决win7安装oracle 10g时发生“程序异常终止,发生内部错误”