MessageBox "Аварийное завершение программы" поддерживает работу моего приложения

...вид. Как показано на этом чрезвычайно упрощенном примере,

введите описание изображения здесь

очень редко (пока сообщалось только один раз) случается, что одно из моих приложений падает таким образом. Я хочу прекратить его, как обычно, когда происходит неопределенное исключение. Моя стратегия состоит в том, чтобы (на низком уровне) зарегистрировать проблему, а затем завершить ее. Приложение является частью подсистемы, и я хочу (пере) запустить его, если обнаружится какая-либо проблема. Он построен на C++-Builder 6 и работает в Windows (XP...7, также 8). Я узнал, что abort() скорее всего, вызвало сообщение об ошибке. В приложении есть графический интерфейс, поэтому вместо простого (разблокирующего) вывода отображается окно сообщения stderr,

И до тех пор, пока окно сообщения не будет принято пользователем, мое приложение, очевидно, продолжает работать, например, оно обрабатывает таймеры (биения в приведенном выше примере увеличиваются) или сообщения между процессами, совершенно не подозревая о проблеме.

После прочтения некоторых ответов на вопрос " Как проще всего вызвать сбой программы на C++?". и Разница между методами повышения (SIGABRT) и abort(), я попробовал следующее

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 "искать решение проблемы".)

Надежно ли это (регистрация обработчика сигнала для прерывания и вызова выхода там) с вашей точки зрения? ... или хотя бы что-то, на что можно опираться?

4 ответа

Решение

В папке установки 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;
}

Я мог бы сделать несколько тестов, и я могу только подтвердить, что регистрация обработчика сигнала SIGABRT - это просто NOOP.

Я попробовал это с очень простым приложением GUI, написанным с Экспрессом VS2008.:

  • нет фреймворка, ни.NET, а только Win API
  • одно меню с выходом и фатальным
  • меню управляется прямо в WndProc
  • Роковая казнь 1/0

Вот результат:

  • нет специальных действий => Windows открывает MessageBox, указывающий на фатальную ошибку...
  • обработчик сигнала для SIGABRT => тот же MessageBox
  • C++ попробуйте catch(...) => тот же MessageBox
  • SEH в WndProc: может перехватить ошибку!
  • SEH вокруг цикла сообщений: может перехватить ошибку!

Если я ставлю обработчики ботов SEH, ловит самый внутренний (WndProc).

Хорошим нововведением для вас является то, что если этого достаточно для защиты цикла сообщений, и вам не нужно заходить в каждый 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++ уже есть такой обработчик исключений в его цикле сообщений.

Надеюсь, поможет...

Возможно, вы сможете использовать отчеты об ошибках Windows для создания дампа процесса, когда необработанное исключение вызывает завершение. Затем вы можете просмотреть дамп на досуге и позволить некоторым родительским процессам или другим сторожевым таймерам перезапустить ваш процесс. Если вы выберете эту стратегию, вы не будете пытаться справиться с ошибкой в ​​вашем коде, а разрешите ее.

Если вы хотите захватить любой выход из программы, вы должны посмотреть на atexit (). Если вы хотите перехватить все события завершения, посмотрите на std::set_terminate (), если вы хотите скрыть все неожиданные исключения, посмотрите на std::set_unexpected (). Если вы хотите захватить только abort() Вы можете вызвать сигнал () с SIGABRT значение сигнала. Вы также можете обернуть свой код с try{your code}catch(...){custom event handler},

Другие вопросы по тегам