Исключения (C++/CX)
Обработка ошибок в C++/CX основана на исключениях. На самом базовом уровне среда выполнения Windows компоненты сообщают об ошибках в виде значений HRESULT. В C++/CX эти значения преобразуются в строго типизированные исключения, содержащие значение HRESULT и строковое описание, к которым можно получить доступ программным способом. Исключения реализованы как классы ref class
, производные от класса Platform::Exception
. В пространстве имен Platform
определены отдельные классы исключений для наиболее часто встречающихся значений HRESULT. Все остальные значения передаются через класс Platform::COMException
. Все классы исключений имеют Exception::HResult , которое можно использовать для получения исходного значения HRESULT. Вы также можете проверить сведения о стеке вызовов для пользовательского кода в отладчике, который может помочь определить исходный источник исключения, даже если он был создан в коде, написанном на языке, отличном от C++.
Исключения
В программе C++ можно создавать и перехватывать исключение, полученное из операции среда выполнения Windows, исключение, которое является производным от std::exception
пользователя или определяемого пользователем типа. Необходимо создать исключение среда выполнения Windows только в том случае, если он пересекает границу двоичного интерфейса приложения (ABI), например, если код, перехватывающий исключение, записывается в JavaScript. Если исключение, отличное от среда выполнения Windows C++, достигает границы ABI, исключение преобразуется в Platform::FailureException
исключение, представляющее E_FAIL HRESULT. Дополнительные сведения об интерфейсе ABI см. в разделе Creating Windows Runtime Components in C++.
Вы можете объявить platform::Exception с помощью одного из двух конструкторов, которые принимают либо параметр HRESULT, либо параметр HRESULT и параметр Platform::String^, который можно передать через ABI любому приложению среда выполнения Windows, которое обрабатывает его. Либо можно объявить исключение, воспользовавшись одним из двух перегрузок метода Exception::CreateException , которые могут принимать параметр HRESULT или параметры HRESULT и Platform::String^
.
Стандартные исключения
C++/CX поддерживает набор стандартных исключений, представляющих типичные ошибки HRESULT. Каждое стандартное исключение наследуется от класса Platform::COMException, который, в свою очередь, наследуется от Platform::Exception
. Если вы вызываете исключение через границы интерфейса ABI, оно должно быть одним из стандартных исключений.
Делать собственные типы исключений производными от класса Platform::Exception
не допускается. Чтобы создать пользовательское исключение, используйте определяемое пользователем значение HRESULT для создания объекта COMException
.
В следующей таблице перечислены стандартные исключения.
Имя. | Значение HRESULT | Description |
---|---|---|
COMException | Определяемое пользователем значение hresult | Возникает при возвращении неизвестного значения HRESULT после вызова метода COM. |
AccessDeniedException | E_ACCESSDENIED | Возникает при запрете доступа к ресурсу или функции. |
ChangedStateException | E_CHANGED_STATE | Возникает, если метод итератора коллекции или представления коллекции вызван после изменения родительской коллекции, что делает результаты метода недействительными. |
ClassNotRegisteredException | REGDB_E_CLASSNOTREG | Возникает, если COM-класс не зарегистрирован. |
DisconnectedException | RPC_E_DISCONNECTED | Возникает, если объект отключен от своих клиентов. |
FailureException | E_FAIL | Возникает, если операция завершается неудачно. |
InvalidArgumentException | E_INVALIDARG | Вызывается, если один из передаваемых методу аргументов является недопустимым. |
InvalidCastException | E_NOINTERFACE | Возникает, если тип не удается привести к другому типу. |
NotImplementedException | E_NOTIMPL | Возникает, если метод интерфейса не реализован в классе. |
NullReferenceException | E_POINTER | Возникает при попытке разыменовать ссылку на объект NULL. |
ObjectDisposedException | RO_E_CLOSED | Вызывается при выполнении операции над ликвидированным объектом. |
OperationCanceledException | E_ABORT | Возникает при отмене операции. |
OutOfBoundsException | E_BOUNDS | Возникает, когда операция пытается получить доступ к данным за пределами допустимого диапазона. |
OutOfMemoryException | E_OUTOFMEMORY | Возникает, если недостаточно памяти для выполнения операции. |
WrongThreadException | RPC_E_WRONG_THREAD | Вызывается, если поток выполняет вызов посредством указателя на интерфейс для прокси-объекта, который не принадлежит к подразделению потока. |
Свойства HResult и Message
Все исключения имеют свойство HResult и свойство Message . Свойство Exception::HResult получает базовое числовое значение HRESULT соответствующего исключения. Свойство Exception::Message получает предоставленную системой строку с описанием исключения. В Windows 8 сообщение доступно только в отладчике и доступно только для чтения. Это означает, что его невозможно изменить после повторного создания исключения. В Windows 8.1 к строке сообщения можно получить доступ программным образом и предоставить новое сообщение, если необходимо заново создать исключение. В отладчике доступны более подробные данные стеков вызовов, включая данные об асинхронных вызовах методов.
Примеры
В этом примере показано, как создать исключение среда выполнения Windows для синхронных операций:
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);
}
В следующем пример показано, как перехватить исключение.
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());
//...
}
Чтобы перехватывать исключения, создаваемые во время асинхронной операции, используйте класс задач и добавьте продолжение обработки ошибок. Продолжение обработки ошибок маршалирует исключения, вызванные в других потоках, обратно вызывающему потоку, что позволяет обрабатывать все возможные исключения в одной структурной единице кода. Дополнительные сведения см. в статье Асинхронное программирование в C++.
Событие UnhandledErrorDetected
В Windows 8.1 вы можете подписаться на статическое событие Windows::ApplicationModel::CoreApplication::UnhandledErrorDetected статического события, которое обеспечивает доступ к необработанным ошибкам, которые собираются сократить процесс. Независимо от того, где возникла ошибка, она достигнет этого обработчика в виде объекта Windows::ApplicationModel::Core::UnhandledError , который передается с аргументами события. При вызове метода Propagate
для объекта он создает исключение Platform::*Exception
типа, соответствующего коду ошибки. В блоках catch можно при необходимости сохранить состояние пользователя, а затем либо разрешить завершение процесса путем вызова throw
, либо каким-либо образом вернуть программу в известное состояние. В следующем примере демонстрируется использование основного подхода:
В app.xaml.h:
void OnUnhandledException(Platform::Object^ sender, Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs^ e);
В 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
}
}
Замечания
C++/CX не использует finally
предложение.