Поделиться через


Написание фильтра исключений

Исключение можно обработать посредством перехода на уровень обработчика исключений или путем продолжения выполнения. Вместо использования кода обработчика исключений для обработки исключения и передачи управления дальше можно использовать фильтр, чтобы устранить проблему и затем, при возврате значения -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 )

См. также

Ссылки

Написание обработчика исключений

Структурированная обработка исключений (C/C++)