Exceções (C++/CX)

O tratamento de erro em C++/CX se baseia em exceções. No nível mais fundamental, os componentes do Windows Runtime 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 ref class que deriva de Platform::Exception. O namespace Platform define classes de exceção distinta para os valores HRESULT mais comuns; todos os outros valores são relatados por meio da classe Platform::COMException . 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 informações da pilha de chamadas para o código do usuário no depurador que podem ajudar a identificar a origem da exceção, mesmo que ela seja proveniente de um código escrito em outra linguagem que não C++.

Exceções

No seu programa C++, você pode gerar e capturar uma exceção proveniente de uma operação do Windows Runtime, uma exceção derivada de std::exception ou um tipo definido pelo usuário. Você somente tem que gerar uma exceção do Windows Runtime quando ele for passar pelos limites da ABI (interface binária de aplicativo), por exemplo, quando o código que captura sua exceção está escrito em JavaScript. Quando uma exceção C++ não do Windows Runtime alcança os limites de ABI, a exceção é convertida em uma exceção Platform::FailureException, que representa um E_FAIL HRESULT. Para obter mais informações sobre a ABI, consulte Creating Windows Runtime Components in C++.

Você pode declarar uma 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 possa ser passado pela ABI para qualquer aplicativo da Windows Runtime que o manipule. Ou pode declarar uma exceção usando uma de duas sobrecargas do método Exception::CreateException que adotam um parâmetro HRESULT, ou um parâmetro HRESULT e um parâmetro Platform::String^ .

Exceções padrão

O C++/CX dá suporte a um conjunto de exceções padrão que representam erros HRESULT típicos. Cada exceção padrão é derivada de Platform::COMException, que, por sua vez, é derivada de Platform::Exception. Quando você gera uma exceção através dos limites da ABI, é necessário gerar uma das exceções padrão.

você não pode derivar seu próprio tipo de exceção de Platform::Exception. Para gerar uma exceção personalizada, use um HRESULT definido pelo usuário para construir um objeto COMException .

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

Nome HRESULT subjacente Descrição
COMException hresult definido pelo usuário Gerada quando um HRESULT não reconhecido é retornado de um chamada de método COM.
AccessDeniedException E_ACCESSDENIED Gerada quando o acesso a um recurso é negado.
ChangedStateException E_CHANGED_STATE Gerada quando métodos de um iterador de coleção ou uma exibição de coleção são chamados após a alteração da coleção pai, portanto, invalidando os resultados do método.
ClassNotRegisteredException REGDB_E_CLASSNOTREG Gerada quando uma classe COM não foi registrada.
DisconnectedException RPC_E_DISCONNECTED Gerada quando um objeto é desconectado de seus clientes.
FailureException E_FAIL Gerada quando uma operação falha.
InvalidArgumentException E_INVALIDARG Gerada quando um dos argumentos fornecidos a um método não é válido.
InvalidCastException E_NOINTERFACE Gerada quando um tipo não pode ser convertido em outro tipo.
NotImplementedException E_NOTIMPL Gerada se um método de interface não foi implementado em uma classe.
NullReferenceException E_POINTER Gerada quando ocorre uma tentativa de cancelar a referência de um objeto de referência nula.
ObjectDisposedException RO_E_CLOSED Gerada quando uma operação é executada em um objeto descartado.
OperationCanceledException E_ABORT Gerada quando uma operação é anulada.
OutOfBoundsException E_BOUNDS Gerada quando uma operação tenta acessar dados fora do intervalo válido.
OutOfMemoryException E_OUTOFMEMORY Gerada quando a memória para concluir a operação é insuficiente.
WrongThreadException RPC_E_WRONG_THREAD Gerada quando um thread chama via um ponteiro de interface, que destina-se a um objeto proxy que não pertence ao apartment do thread.

Propriedades de HResult e de Message

Todas as exceções têm uma propriedade HResult e uma propriedade Message . A propriedade Exception::HResult obtém o valor HRESULT numérico 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 somente no depurador e é somente leitura. Isso significa que você não pode alterá-la ao gerar novamente a exceção. No Windows 8.1, você pode acessar a cadeia de caracteres da mensagem programaticamente e fornecer uma nova mensagem se a exceção for gerada novamente. As melhores informações da pilha de chamadas também estão disponíveis no depurador, incluindo pilhas de chamadas de método assíncrono.

Exemplos

Este exemplo mostra como gerar uma exceção do Windows Runtime 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 exemplo a seguir 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 geradas durante uma operação assíncrona, use a classe task e adicione uma continuação de tratamento de erro. A continuação do tratamento de erro realiza marshaling das exceções que são geradas em outros threads de volta para o thread chamador, de modo que você possa tratar todas as exceções potenciais em apenas um ponto no seu código. Para obter mais informações, veja 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 aos erros não tratados que estão prestes a anular o processo. Independentemente da origem do erro, ele chega a esse manipulador como um objeto Windows::ApplicationModel::Core::UnhandledError que é transmitido com os argumentos do evento. Quando você chama Propagate no objeto, ele cria e gera uma exceção Platform::*Exception do tipo correspondente ao código de erro. Nos blocos catch, você pode salvar o estado do usuário, se necessário, e permitir que o processo seja finalizado chamando throwou fazendo algo para colocar o programa novamente 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
    }
}

Comentários

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

Confira também

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