Войти
Подсказки

Как перехватить аварийное завершение программы системой

Автор:

Иногда, играя в какую-нибудь игру мы наблюдаем такую картину - игра "вываливается" в Windows с сообщением типа "Программа выполнила некорректное обращение к памяти и будет закрыта". Хорошо еще, если мы незадолго до этого сохранились. Если нет, то уж совсем обидно. Все мы люди и в реальных "больших" проектах мы не всегда можем найти все ошибки. Таким образом, не помешает механизм, когда программа "перехватывает" такие критические ситуации и перед закрытием скидывает на диск важную информацию. Думаю пользователю вашей игры было бы приятно после очередного запуска игры в связи с ее аварийным завершением увидеть в списке "сохраненок" сейв сделаный в момент аварийного завершения. Данная подсказка илюстрирует один из способов обработки таких критических моментов.

Механизм защиты памяти в старших процессорах Intel реализован на аппаратном уровне и в случае возникновения ошибки защиты генерируется исключение для обработки этой ошибки. Windows позволяет установить свой обработчик для данного исключения.

#include "stdafx.h"
#include <windows.h>
#include <fstream>

//Указатель на старый обработчик
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter=0;
//Объявление нового обработчика
LONG WINAPI CurrentFilter(PEXCEPTION_POINTERS pExceptionInfo);
//наши данные
char szStr[]="Информация, которую нужно сохранить";

int _tmain(int argc, _TCHAR* argv[])
{
    //Сначала устанавливаем свой обработчик и запоминаем старый
  oldFilter=SetUnhandledExceptionFilter(CurrentFilter);

  //Создаем критическую ситуацию 
  *(int*)0=0;

  //Сюда мы уже попасть не должны, однако в реальной ситуаци, когда ошибка не возникает
  //мы должны перед выходом востанавливать старый обработчик
    SetUnhandledExceptionFilter( oldFilter );
  return 0;
}


//Функция-обработчик исключения
LONG WINAPI CurrentFilter(PEXCEPTION_POINTERS pExceptionInfo )
{
  //Сохраняем данные и показываем сообщение что ситуация обработана
  std::fstream f;
  f.open("out.txt",std::ios_base::out | std::ios_base::trunc);
  f<<szStr;
  f.close();
  MessageBox(NULL,"Информация сохранена","",0); 

  //Далее выходим передавая управление предыдущему обработчику исключения
  if(oldFilter)
    return oldFilter( pExceptionInfo );
  //Если такого обработчика нет, то выходим и передаем управление стандартному обработчику
  return EXCEPTION_CONTINUE_SEARCH;
  //Кстати, здесь можно выбрать еще один вариант развития событий - продолжить выполнение
  //программы, для этого надо вместо EXCEPTION_CONTINUE_SEARCH, 
  //вернуть EXCEPTION_CONTINUE_EXECUTION,
  //выполнение продолжится с прерваной точки программы, изменить контекст (регистры и пр.) 
  //прерваной прогораммы можно через pExceptionInfo
}

Это только один из способов, есть и другие. Подробнее о них можно посмотреть в MSDN.

12 апреля 2005