Windows для профессионалов

Перехват структурных исключений в С++


Обычно механизм обработки исключений в С++ не позволяет приложению восста новиться после таких серьезных исключений, как нарушение доступа или деление на нуль. Однако Microsoft добавила поддержку соответствующей функциональности в свой компилятор. Так, следующий код предотвратит аварийное завершение процесса.

void main()
{

try
{

* (PBYTE) 0 = 0; // нарушение доступа

}

catch ( ..)
{

// этот код обрабатывает исключения, связанные с нарушением доступа

}

// процесс завершается корректно

}

И это прекрасно, так как приложение может корректно справляться с серьезны ми исключениями. Но было бы еще лучше, если бы блок catch как-то различал коды исключений — чтобы мы могли писать, например, такой исходный код

void Functastic()
{

try
{



* (PBYTE) 0 = 0; // нарушение доступа

int x = 0;

x = 5 / x; // деление на нуль

}

catch (StructuredFxception)
{

switch (StructuredExceptionCode)
{

case EXCEPTION_ACCESS_VIOLATION:

// здесь обрабатывается нарушение доступа
break;

case EXCEPTION_INT_OIVIDE_BY_ZERO:

// здесь обрабатывается деление на нуль
break;

default:

// другие исключения мы не обрабатываем throw;
// может, какой-нибудь другой блок catch
// обработает это исключение

break;

// никогда не выполняется

}

}

}

Так вот, хочу Вас порадовать. В Visual С++ теперь возможно и такое. От Вас потре буется создать С++-класс, используемый специально для идентификации структурных исключений. Например:

#include <eh.h> // для доступа к _set_se_translator

...

class CSE
{

public:

// вызовите эту функцию для каждого потока

static void MapSEtoCE() { _set_se_translator(TranslateSEtoCE); }

operator DWORD() { return(m_er.ExcepUonCude); }

privale:

CSE(PEXCEPTION_POINTERS pep)
{

m_er = *pep->ExceptionRecord;
m_context = *pep->ContextRecord;

}

static void _cdecl TranslateSEtoCE(UINT dwEC, PEXCEPTION_POINTERS pep)
{

throw CSE(pep);

}

private:

EXCEPTION_RECORD m_er;
// машинно-независимая информация ofi исключении

CONTEXT m_context;
// машинно-зависимая информация об исключении


};

Внутри входных функций потоков вызывайте статическую функцию-член Map SEtoCE. В свою очередь она обращается к библиотечной С-функции _set_sefranslator, передавая ей адрес функции TranslateSEtoCE класса CSE. Вызов _set_se_translator сооб щает С++, что при возбуждении структурных исключений Вы хотите вызывать Trans lateSEtoCE. Эта функция вызывает конструктор CSE-объектя и инициализирует два элемента данных машинно-зависимой и машинно-независимой информацией об исключении. Созданный таким образом CSE-объскт может быть вытолкнут ак же, как и любая другая переменная. И теперь Ваш С++-код способен обрабатывать структур ные исключения, захватывая (catching) переменную этого типа.

Вот пример захвата такого С++-объекта.

void Functastic()
{

CSE::MapSEtoCE(); // должна быть вызвана до возникновения исключений

try
{

* (PBYTE) 0 = 0; // нарушение доступа

int x = 0;

x = 5 / x; // деление на нуль

}

catch (CSE se)
{

switch (se)
{

// вызывает функцию-член оператора DWORD()

case EXCEPTION_ACCESS_VIOLATION

// здесь обрабатывается исключение вызванное нарушением доступа
break;

case EXCEPTION_INT_DIVIDE_BY_ZERO

// здесь обрабатывается исключение, вызванное делением на нуль
break;

default:

// другие исключения мы не обрабатываем throw;
// может, какой-нибудь другой блок catch
// обработает это исключение
break;

// никогда не выполняется

}

}

}


Содержание раздела