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 throw
ou 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
.