Compartilhar via


Escrevendo um filtro de exceção

Você pode lidar com uma exceção indo diretamente ao nível do manipulador de exceção ou continuando a execução. Em vez de usar um código de manipulador de exceção para manipular a exceção e a queda, você pode usar um a expressão de filtro para limpar o problema. Em seguida, ao retornar EXCEPTION_CONTINUE_EXECUTION (-1), você pode retomar o fluxo normal sem limpar a pilha.

Observação

Algumas exceções não podem ser retomadas. Se filter avalia uma exceção como -1, o sistema gera uma nova exceção. Ao chamar RaiseException, você determina se uma exceção continuará.

Por exemplo, o código a seguir usa uma chamada de função na expressão filter: essa função manipula o problema e retorna -1 para retomar o fluxo de controle normal:

// 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;
}

Essa é uma boa ideia usar uma chamada de função na expressão filter sempre que filter precisar fazer algo complexo. Avaliar a expressão causa a execução da função, nesse caso, Eval_Exception.

Observe o uso de GetExceptionCode para determinar a exceção. Essa função deve ser chamada dentro da expressão de filtro da instrução __except. Eval_Exception não pode chamar GetExceptionCode, mas deve ter o código de exceção passado para ele.

Esse manipulador passa o controle para outro manipulador, a menos que a exceção seja um inteiro ou um estouro de ponto flutuante. Se for o caso, o manipulador chamará uma função (ResetVars é apenas um exemplo, não uma função de API) para redefinir alguns variáveis globais. O bloco de instruções __except, que neste exemplo está vazio, nunca pode ser executado porque Eval_Exception nunca retorna EXCEPTION_EXECUTE_HANDLER (1).

Usar uma chamada de função é uma boa técnica de uso geral para lidar com expressões de filtro complexas. Outros dois recursos da linguagem C úteis são:

  • O operador condicional

  • O operador vírgula

O operador condicional é frequentemente útil aqui. Ele pode ser usado para verificar se há um código de retorno específico e retornar um de dois valores diferentes. Por exemplo, o filtro no código a seguir confirma a exceção apenas se a exceção for STATUS_INTEGER_OVERFLOW:

__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ? 1 : 0 ) {

O propósito do operador condicional nesse caso é basicamente fornecer clareza, pois o código a seguir gera os mesmos resultados:

__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ) {

O operador condicional é mais útil em situações em que talvez você queira que o filtro seja avaliado em -1,EXCEPTION_CONTINUE_EXECUTION.

O operador de vírgula permite executar várias expressões em sequência. Em seguida, retorna o valor da última expressão. Por exemplo, o código a seguir armazena o código de exceção em uma variável e o testa:

__except( nCode = GetExceptionCode(), nCode == STATUS_INTEGER_OVERFLOW )

Confira também

Escrevendo um manipulador de exceção
Tratamento de exceções estruturado (C/C++)