Здравствуйте, MT, Вы писали:
MT>Можно ли перехватить фатальные ошибки вроде "Memory could not be read"?
MT>Пробовал так:
MT>MT> try {
MT> } catch (...) {
MT> }
MT>
MT>Но очевидно что не все ошибки перехватываются...
Рассказываю (и показываю). То что вы называете фатальными ошибками на самом деле являются SEH-исключениями операционной системы (внимательно читаем Рихтера). Они возбуждаются в различных ситуациях, как то: доступ по неправильному адресу, переполнение стека, деление на нуль, ошибка сопроцессора и.т.д. Будучи неперехваченным, SEH-исключение вызывает появление хорошо известного окна с предложением впаять разработчику и принудительной остановки процесса. Как перехватывать такие исключения в C++. Метод __try __except обсуждать не буду, поскольку его использование в C++ программах -- это дурной тон и возможный конфликт с родными C++ исключениями. Наиболее простой подход -- использовать catch(...).
Для того, чтобы это работало, необходимо правильно настоить компилятор. Насчет VC++ 6.0 не помню, а вот в 7.0/7.1 придётся повыделываться. Заходим на вкладочку свойств проекта C/C++ Code Generation. Там есть строчка Enable C++ exception. Смело ставим в этой строчке No. Дальше двигаемся в конец к секции Command Line. На соотвествующей вкладочке есть окошко, Additional Options. Вот здесь надо прописать /EHac. Почему так, спросите у Билла Гейтса.
Чтобы жизнь была интересней и разнообразней, наверное. Не всё ж галочки в property tab мышкой переключать. В чем недостаток этого подхода -- невозможно определить тип исключения, и ,что более серьёзно, возникают проблемы с плавающей арифметикой. Имеется более усовершенствованный метод. Заключается он в использовании так называемого se транслятора. Вот примерный код.
#include <eh.h>
static void se_translator(unsigned int code,_EXCEPTION_POINTERS *)
{
if( code==EXCEPTION_FLT_DENORMAL_OPERAND ||
code==EXCEPTION_FLT_DIVIDE_BY_ZERO ||
code==EXCEPTION_FLT_INEXACT_RESULT ||
code==EXCEPTION_FLT_INVALID_OPERATION ||
code==EXCEPTION_FLT_OVERFLOW ||
code==EXCEPTION_FLT_STACK_CHECK ||
code==EXCEPTION_FLT_UNDERFLOW
)
{
short cw=???;
__asm {
fninit
fldcw cw
}
}
throw Exception(CPUError(code));
}
void Setup_SE_translator()
{
_set_se_translator(se_translator);
}
Смысл в следующем. Вызовом функции _set_se_translator можно инсталировать функцию, которая будет получать управление в случае возникновения в
текущем потоке SEH-исключения. Главное назначение этой функции -- получить код SEH-исключения, завернуть в подходящую обёртку и выбросить нормальное C++ исключение. Которое в дальнейшем можно поймать обычным catch. Коды этих исключений можно получить из windows.h, а описание -- в MSDN в статье про EXCEPTION_RECORD. Среди этих кодов есть семейство особо важных, связанных с плавающей точкой. При получении одного из этих кодов, надо делать маленькую дополнительную обработку. А именно, нужно командой fninit сбросить сопроцессор в нормальное состояние. Ну и загрузить подходящее слово управление. Иначе флаги исключений по-прежнему будут висеть в сопроцессоре, что вызовет возбуждение нового исключения при попытке его снова заюзать. Вообще, использование исключений сопроцессора -- это отдельный нетривиальный вопрос. Поскольку с ним связан целый рад фокусов, на которые можно напороться.
... << RSDN@Home 1.1 beta 2 >>