Исключения (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 предложение.

См. также

Справочник по языку C++/CX
Справочник по пространствам имен