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

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

6

Решение

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

Другие решения

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

1

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

1

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

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

1
По вопросам рекламы [email protected]