Функция GetExceptionCode
Часто фильтр исключений должен проанализировать ситуацию, прежде чем опреде лить, какое значение ему вернуть. Например, Ваш обработчик может знать, что делать при делении на нуль, по не знать, как обработать нарушение доступа к памяти Имен но поэтому фильтр отdечает за анализ ситуации и возврат соответствующего значения Этот фрагмент иллюстрирует метод, позволяющий определять тип исключения:
__try
{
x = 0;
У = 4 / x;
}
__except ((GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) ? EXCEPTlON_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// обработка деления иа нуль
}
Встраиваемая функция GetExceptionCode возвращает идентификатор типа исклю чения.
DWORD GotExceptionCode();
Ниже приведен список всех предопределенных идентификаторов исключений с пояснением их смысла (информация взята из докуметации Platform SDK) Эти иден тификаторы содержатся в заголовочном файле WinBase.h. Я сгруппировал исключе ния по категориям.
Исключения, связанные с памятью
Исключения, связанные с обработкой самих исключений
Исключения, связанные с отладкой
Исключения, связанные с операциями над целыми числами
Исключения, связанные с операциями над вещественными числами
Встраиваемую функцию GetExceptionCode можно вызвать только из фильтра ис ключений (между скобками, которые следуют за _except) или из обработчика исклю чений. Скажем, такой код вполне допустим:
__try
{
У = 0;
x = 4 / у;
}
_except
{
{(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) (GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO)) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEAHCH)
{
switch (GetExceptionCode())
{
case EXCEPTION_ACCESS_VIOLATION:
// обработка нарушения доступа к памяти
...
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
// обработка деления целого числа на нуль
...
break;
}
}
Однако GetExceptionCode нельзя вызывать из функции фильтра исключений. Ком пилятор помогает вылавливать такие ошибки и обязательно сообщит о таковой, если Вы попытаетесь скомпилировать, например, следующий код:
__try
{
У = 0;
x = 4 / у;
}
__except (CoffeeFilter())
{
// обрабогка исключения
...
}
LONG CoffeeFilter(void)
{
// ошибка при компиляции: недопустимый вызов GetExceptionCode
return((GetExceptionCode() == EXCFPTION_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH);
}
Нужного эффекта можно добиться, переписав код так:
__try
{
y = 0;
x = 4 / у;
}
__except (CoffeeFi]ter(GetExceptionCode()))
{
// обработка исключения
...
}
LONG CoffeeFilter(DWORD dwExceptionGode)
{
return((dwExceptionCode == EXCEPTION_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH);
}
Коды исключений формируются по тем же правилам, что и коды ошибок, опре деленные в файле WinError.h. Каждое значение типа UWORD разбивается на поля, как показано в таблице 24-1.
Биты | 31-30 | 29 | 28 | 27-16 | 15-0 |
Содержимое | Код степени "тяжести" (severity) | Кем определен — Microsoft или пользователем | Зарезервирован | Код подсистемы (facility code) | Код исключения |
Значение | 0 = успех 1 = информация 2 = предупреждение 3 = ошибка | 0 = Microsoft 1 = пользователь | Должен быть 0 (см таблицу ниже) | Определяется Microsoft | Определяется Microsoft или пользовате лем |
Таблица 24-1, Поля кода ошибки
На сегодняшний день определены такие коды подсистемы.
Код подсистемы | Значение | Код подсистемы | Значение |
FACILITY_NULL | 0 | FACILITY_CONTROL | 10 |
FACILITY_RPC | 1 | FACILITY_CERT | 11 |
FACILITY_DISPATCH | 2 | FACILITY_INTERNET | 12 |
FACILITY_STORAGE | 3 | FACILITY_MEDIASERVER | 13 |
FACILITY_ITF | 4 | FACILITY_MSMQ | 11 |
FACILITY_WIN32 | 7 | FACILITY_SETUPAPI | 15 |
FACILITY_WINDOWS | 8 | FACILITY_SCARD | 16 |
FACILITY_SECURITY | 9 | FACILITY_COMPLUS | 17 |
С 0 0 0 0 0 0 5 (в шестнадцатеричном виде) 1100 0000 0000 0000 0000 0000 0000 0101 (в двоичном виде)
Биты 30 и 31 установлены в 1, указывая, что нарушение доступа является ошиб кой (поток не может продолжить выполнение) Бит 29 равен 0, а это значит, что дан ный код определен Microsoft. Бит 28 равен 0, так как зарезервирован на будущее. Биты 16-27 равны 0, сообщая код подсистемы FACILITY_NULL (нарушение доступа может произойти в любой подсистеме операционной системы, а нс в какой-то одной). Биты 0-15 дают значение 5, которое означает лишь то, что Microsoft присвоила исключе нию, связанному с нарушением доступа, код 5.