Написание фильтра исключений
Исключение можно обработать посредством перехода на уровень обработчика исключений или путем продолжения выполнения. Вместо использования кода обработчика исключений для обработки исключения и передачи управления дальше можно использовать фильтр, чтобы устранить проблему и затем, при возврате значения -1, возобновить обычный поток без очистки стека.
Примечание
После некоторых исключений возобновление невозможно.Если для такого исключения фильтр вычисляет значение -1, система создает новое исключение.При вызове функции RaiseException определение возможности возобновления после исключения осуществляется программистом.
Например, в представленном ниже коде в выражении фильтра используется вызов функции: вызванная функция обрабатывает проблему и возвращает значение -1, чтобы возобновить обычный поток управления.
// exceptions_Writing_an_Exception_Filter.cpp
#include <windows.h>
int main() {
int Eval_Exception( int );
__try {}
__except ( Eval_Exception( GetExceptionCode( ))) {
;
}
}
void ResetVars( int ) {}
int Eval_Exception ( int n_except ) {
if ( n_except != STATUS_INTEGER_OVERFLOW &&
n_except != STATUS_FLOAT_OVERFLOW ) // Pass on most exceptions
return EXCEPTION_CONTINUE_SEARCH;
// Execute some code to clean up problem
ResetVars( 0 ); // initializes data to 0
return EXCEPTION_CONTINUE_EXECUTION;
}
Если фильтр должен выполнить какие-либо сложные действия, в выражении фильтра целесообразно использовать вызов функции. Вычисление выражения приводит к выполнению функции, в данном случае — Eval_Exception.
Обратите внимание на использование функции GetExceptionCode для определения исключения. Эту функцию необходимо вызывать внутри фильтра. Функция Eval_Exception не может вызвать функцию GetExceptionCode, но должна содержать передаваемый ей код исключения.
Если исключение не вызвано переполнением при операции с целыми числами или числами с плавающей запятой, этот обработчик передает управление другому обработчику. В этом случае обработчик вызывает функцию (ResetVars — это только пример, а не функция API), чтобы сбросить некоторые глобальные переменные. Блок-оператора-2, который в данном примере пустой, выполняться не может, поскольку функция Eval_Exception никогда не возвращает результат EXCEPTION_EXECUTE_HANDLER (1).
Вызов функции — хороший способ работы со сложными выражениями фильтров. Удобны также две другие функции языка C:
условный оператор;
оператор "запятая".
Условный оператор часто полезен, поскольку его можно использовать для проверки конкретного кода возврата и последующего возврата одного из двух различных значений. Например, фильтр в следующем коде распознает только исключение STATUS_INTEGER_OVERFLOW.
__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ? 1 : 0 ) {
Цель условного оператора в этом случае — в основном, обеспечить ясность, так как следующий код дает такие же результаты.
__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ) {
Условный оператор больше подходит в ситуациях, когда требуется, чтобы фильтр получил значение -1, EXCEPTION_CONTINUE_EXECUTION.
Оператор "запятая" позволяет выполнить несколько независимых операций в одном выражении. Результат, грубо говоря, представляет собой результат выполнения нескольких инструкций с последующим возвратом значения последнего выражения. Например, в следующем коде код исключения сохраняется в переменной и затем проверяется.
__except( nCode = GetExceptionCode(), nCode == STATUS_INTEGER_OVERFLOW )