Partilhar via


Exceções (C++/CX)

O tratamento de erros em C++/CX é baseado em exceções. No nível mais fundamental, os componentes do Tempo de Execução do Windows relatam erros como valores HRESULT. Em C++/CX, esses valores são convertidos em exceções fortemente tipadas que contêm um valor HRESULT e uma descrição de cadeia de caracteres que você pode acessar programaticamente. As exceções são implementadas como um ref class que deriva de Platform::Exception. O Platform namespace define classes de exceção distintas para os valores HRESULT mais comuns, todos os outros valores são relatados por meio da Platform::COMException classe. Todas as classes de exceção têm um campo Exception::HResult que você pode usar para recuperar o HRESULT original. Você também pode examinar as informações da pilha de chamadas em busca de código de usuário no depurador que pode ajudar a identificar a fonte original da exceção, mesmo que ela tenha se originado em um código que foi escrito em uma linguagem diferente de C++.

Exceções

Em seu programa C++, você pode lançar e capturar uma exceção que vem de uma operação do Tempo de Execução do Windows, uma exceção derivada de std::exception, ou um tipo definido pelo usuário. Você precisa lançar uma exceção do Tempo de Execução do Windows somente quando ela cruzar o limite da interface binária do aplicativo (ABI), por exemplo, quando o código que captura sua exceção estiver escrito em JavaScript. Quando uma exceção C++ que não seja do Tempo de Execução do Windows atinge o limite da ABI, a exceção é convertida em uma Platform::FailureException exceção, que representa um E_FAIL HRESULT. Para obter mais informações sobre a ABI, consulte Criando componentes do Tempo de Execução do Windows em C++.

Você pode declarar um Platform::Exception usando um dos dois construtores que usam um parâmetro HRESULT ou um parâmetro HRESULT e um parâmetro Platform::String^ que pode ser passado pela ABI para qualquer aplicativo do Tempo de Execução do Windows que o manipule. Ou você pode declarar uma exceção usando uma das duas sobrecargas do método Exception::CreateException que usam um parâmetro HRESULT ou um parâmetro HRESULT e um Platform::String^ parâmetro.

Exceções-padrão

C++/CX suporta um conjunto de exceções padrão que representam erros típicos de HRESULT. Cada exceção padrão deriva de Platform::COMException, que por sua vez deriva de Platform::Exception. Quando você lança uma exceção através do limite ABI, você deve lançar uma das exceções padrão.

Não é possível derivar seu próprio tipo de exceção de Platform::Exception. Para lançar uma exceção personalizada, use um HRESULT definido pelo usuário para construir um COMException objeto.

A tabela a seguir lista as exceções padrão.

Nome HRESULT subjacente Descrição
COMException hresult definido pelo usuário Lançado quando um HRESULT não reconhecido é retornado de uma chamada de método COM.
AccessDeniedException E_ACCESSDENIED Lançado quando o acesso é negado a um recurso ou recurso.
ChangedStateException E_CHANGED_STATE Lançado quando os métodos de um iterador de coleção ou uma exibição de coleção são chamados depois que a coleção pai foi alterada, invalidando assim os resultados do método.
ClassNotRegisteredException REGDB_E_CLASSNOTREG Lançado quando uma classe COM não foi registrada.
DisconnectedException RPC_E_DISCONNECTED Lançado quando um objeto é desconectado de seus clientes.
FailureException E_FAIL Lançado quando uma operação falha.
ExceçãoDeArgumentoInválido E_INVALIDARG Lançado quando um dos argumentos fornecidos a um método não é válido.
InvalidCastException E_NOINTERFACE Lançado quando um tipo não pode ser convertido para outro tipo.
NotImplementedException E_NOTIMPL Lançado se um método de interface não tiver sido implementado em uma classe.
Exceção de Referência Nula E_POINTER Lançado quando há uma tentativa de cancelar a referência de uma referência de objeto nulo.
ObjectDisposedException RO_E_CLOSED Lançado quando uma operação é executada em um objeto descartado.
OperationCanceledException E_ABORT Lançado quando uma operação é abortada.
OutOfBoundsException E_BOUNDS Lançado quando uma operação tenta acessar dados fora do intervalo válido.
OutOfMemoryException E_OUTOFMEMORY Lançado quando não há memória suficiente para concluir a operação.
WrongThreadException código de erro RPC_E_WRONG_THREAD (Thread Errada) Lançado quando um thread chama através de um ponteiro de interface que é para um objeto proxy que não pertence ao apartamento do thread.

Propriedades HResult e Message

Todas as exceções têm uma propriedade HResult e uma propriedade Message . A propriedade Exception::HResult obtém o valor numérico HRESULT subjacente da exceção. A propriedade Exception::Message obtém a cadeia de caracteres fornecida pelo sistema que descreve a exceção. No Windows 8, a mensagem está disponível apenas no depurador e é somente leitura. Isso significa que você não pode alterá-lo quando você relançar a exceção. No Windows 8.1, você pode acessar a cadeia de caracteres de mensagem programaticamente e fornecer uma nova mensagem se você relançar a exceção. Melhores informações sobre a pilha de chamadas também estão disponíveis no depurador, incluindo pilhas de chamadas para chamadas de método assíncronas.

Exemplos

Este exemplo mostra como lançar uma exceção do Tempo de Execução do Windows para operações síncronas:

String^ Class1::MyMethod(String^ argument)
{
    
    if (argument->Length() == 0) 
    { 
        auto e = ref new Exception(-1, "I'm Zork bringing you this message from across the ABI.");
        //throw ref new InvalidArgumentException();
        throw e;
    }
    
    return MyMethodInternal(argument);
}

O próximo exemplo mostra como capturar a exceção.

void Class2::ProcessString(String^ input)
{
    String^ result = nullptr;    
    auto obj = ref new Class1();

    try 
    {
        result = obj->MyMethod(input);
    }

    catch (/*InvalidArgument*/Exception^ e)
    {
        // Handle the exception in a way that's appropriate 
        // for your particular scenario. Assume
        // here that this string enables graceful
        // recover-and-continue. Why not?
        result = ref new String(L"forty two");
        
        // You can use Exception data for logging purposes.
        Windows::Globalization::Calendar calendar;
        LogMyErrors(calendar.GetDateTime(), e->HResult, e->Message);
    }

    // Execution continues here in both cases.
    //#include <string>
    std::wstring ws(result->Data());
    //...
}

Para capturar exceções lançadas durante uma operação assíncrona, use a classe de tarefa e adicione uma continuação de tratamento de erros. A continuação de tratamento de erros marshals exceções que são lançadas em outros threads de volta para o thread de chamada para que você possa lidar com todas as exceções potenciais em apenas um ponto do seu código. Para obter mais informações, consulte Programação assíncrona em C++.

Evento UnhandledErrorDetected

No Windows 8.1, você pode assinar o evento estático Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected , que fornece acesso a erros não tratados que estão prestes a derrubar o processo. Independentemente de onde o erro se originou, ele atinge esse manipulador como um objeto Windows::ApplicationModel::Core::UnhandledError que é passado com o evento args. Quando você chama Propagate o objeto, ele cria e lança um Platform::*Exception do tipo que corresponde ao código de erro. Nos blocos catch, você pode salvar o estado do usuário, se necessário, e, em seguida, permitir que o processo termine chamando throw, ou fazer algo para colocar o programa de volta em um estado conhecido. O exemplo a seguir mostra o padrão básico:

Em app.xaml.h:

void OnUnhandledException(Platform::Object^ sender, Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs^ e);

Em app.xaml.cpp:

// Subscribe to the event, for example in the app class constructor:
Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected += ref new EventHandler<UnhandledErrorDetectedEventArgs^>(this, &App::OnUnhandledException);

// Event handler implementation:
void App::OnUnhandledException(Platform::Object^ sender, Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs^ e)
{
    auto err = e->UnhandledError;

    if (!err->Handled) //Propagate has not been called on it yet.
{
    try
    {
        err->Propagate();
    }
    // Catch any specific exception types if you know how to handle them
    catch (AccessDeniedException^ ex)
    {
        // TODO: Log error and either take action to recover
        // or else re-throw exception to continue fail-fast
    }
}

Observações

C++/CX não usa a finally cláusula.

Ver também

Referência da linguagem C++/CX
Referência de namespaces