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

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 manipulador chama uma função (HandleOverflow é apenas um exemplo, não uma função de API) para tentar se recuperar adequadamente da exceção. 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ções
Tratamento de exceções estruturado (C/C++)