Partilhar via


Escrever um filtro de exceção

Você pode lidar com uma exceção saltando para o nível do manipulador de exceções ou continuando a execução. Em vez de usar o código do manipulador de exceções para manipular a exceção e cair, você pode usar uma expressão de filtro para limpar o problema. Então, retornando EXCEPTION_CONTINUE_EXECUTION (-1), você pode retomar o fluxo normal sem limpar a pilha.

Observação

Algumas exceções não podem ser mantidas. Se o filtro for avaliado para -1 para tal exceção, o sistema gerará uma nova exceção. Ao ligar RaiseExceptionpara o , você determina se a exceção continuará.

Por exemplo, o código a seguir usa uma chamada de função na expressão de filtro : Esta função lida com o problema e, em seguida, retorna -1 para retomar o fluxo normal de controle:

// exceptions_Writing_an_Exception_Filter.cpp
#include <windows.h>
int Eval_Exception(int);
int main() {
    __try {
        ;
    }
    __except (Eval_Exception(GetExceptionCode())) {
        ;
    }
}
void HandleOverflow() {
    // Gracefully recover
}
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
    HandleOverflow();
    return EXCEPTION_CONTINUE_EXECUTION;
}

É uma boa ideia usar uma chamada de função na expressão de filtro sempre que o filtro precisar fazer algo complexo. A avaliação da expressão provoca a execução da função, neste caso, Eval_Exception.

Observe o uso de GetExceptionCode para determinar a exceção. Esta função deve ser chamada dentro da expressão de filtro da __except instrução. 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 estouro de inteiro ou de ponto flutuante. Se for, o manipulador chama uma função (HandleOverflow é apenas um exemplo, não uma função de API) para tentar recuperar adequadamente da exceção. O __except bloco de instrução, 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. Dois outros recursos da linguagem C que são úteis são:

  • O operador condicional

  • O operador de vírgula

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

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

O objetivo do operador condicional, neste caso, é principalmente fornecer clareza, porque o código a seguir produz os mesmos resultados:

__except (GetExceptionCode() == STATUS_INTEGER_OVERFLOW)

O operador condicional é mais útil em situações em que você pode querer que o filtro avalie para -1, EXCEPTION_CONTINUE_EXECUTION.

O operador de vírgula permite executar várias expressões em sequência. Em seguida, ele 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, em seguida, testa-o:

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

Ver também

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