Windows Dev Center

Exceptions (C++/CX)

Error handling in Visual C++ component extensions (C++/CX) is based on exceptions. At the most fundamental level, Windows Runtime components report errors as HRESULT values. In C++/CX, these values are converted to strongly typed exceptions that contain an HRESULT value and, in Windows 8.1, a string description that you can access programmatically. Exceptions are implemented as a ref class that derives from Platform::Exception. The Platform namespace defines distinct exception classes for the most common HRESULT values; all other values are reported through the Platform::COMException class. All exception classes have an Exception::HResult Property field that you can use to retrieve the original HRESULT. In Windows 8.1, you can also examine call-stack information for user code in the debugger that can help pinpoint the original source of the exception, even if it originated in code that was written in a language other than C++.

In your C++ program, you can throw and catch an exception that comes from a Windows Runtime operation, an exception that's derived from std::exception, or a user-defined type. You have to throw a Windows Runtime exception only when it will cross the application binary interface (ABI) boundary, for example, when the code that catches your exception is written in JavaScript. When a non-Windows Runtime C++ exception reaches the ABI boundary, the exception is translated into a Platform::FailureException exception, which represents an E_FAIL HRESULT. For more information about the ABI, see Creating Windows Runtime Components in C++.

You can declare a Platform::Exception by using one of two constructors that take either an HRESULT parameter, or an HRESULT parameter and a Platform::String^ parameter that can be passed across the ABI to any Windows Store app that handles it. Or you can declare an exception by using one of two Exception::CreateException method overloads that take either an HRESULT parameter, or an HRESULT parameter and a Platform::String^ parameter.

C++/CX supports a set of standard exceptions that represent typical HRESULT errors. Each standard exception derives from Platform::COMException, which in turn derives from Platform::Exception. When you throw an exception across the ABI boundary, you must throw one of the standard exceptions.

You can't derive your own exception type from Platform::Exception. To throw a custom exception, use a user-defined HRESULT to construct a COMException object.

The following table lists the standard exceptions.

Name

Underlying HRESULT

Description

COMException

user-defined hresult

Thrown when an unrecognized HRESULT is returned from a COM method call.

AccessDeniedException

E_ACCESSDENIED

Thrown when access is denied to a resource or feature.

ChangedStateException

E_CHANGED_STATE

Thrown when methods of a collection iterator or a collection view are called after the parent collection has changed, thereby invalidating the results of the method.

ClassNotRegisteredException

REGDB_E_CLASSNOTREG

Thrown when a COM class has not been registered.

DisconnectedException

RPC_E_DISCONNECTED

Thrown when an object is disconnected from its clients.

FailureException

E_FAIL

Thrown when an operation fails.

InvalidArgumentException

E_INVALIDARG

Thrown when one of the arguments that are provided to a method is not valid.

InvalidCastException

E_NOINTERFACE

Thrown when a type can't be cast to another type.

NotImplementedException

E_NOTIMPL

Thrown if an interface method hasn't been implemented on a class.

NullReferenceException

E_POINTER

Thrown when there is an attempt to de-reference a null object reference.

ObjectDisposedException

RO_E_CLOSED

Thrown when an operation is performed on a disposed object.

OperationCanceledException

E_ABORT

Thrown when an operation is aborted.

OutOfBoundsException

E_BOUNDS

Thrown when an operation attempts to access data outside the valid range.

OutOfMemoryException

E_OUTOFMEMORY

Thrown when there's insufficient memory to complete the operation.

WrongThreadException

RPC_E_WRONG_THREAD

Thrown when a thread calls via an interface pointer which is for a proxy object that does not belong to the thread's apartment.

All exceptions have an HResult property and a Message property. The Exception::HResult property gets the exception's underlying numeric HRESULT value. The Exception::Message property gets the system-supplied string that describes the exception. In Windows 8, the message is available only in the debugger and is read-only. This means that you cannot change it when you rethrow the exception. In Windows 8.1, you can access the message string programmatically and provide a new message if you rethrow the exception. Better callstack information is also available in the debugger, including callstacks for asynchronous method calls.

This example shows how to throw a Windows Runtime exception for synchronous operations:

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);
}

The next example shows how to catch the exception.

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());
    //...
}

To catch exceptions that are thrown during an asynchronous operation, use the task class and add an an error-handling continuation. The error-handling continuation marshals exceptions that are thrown on other threads back to the calling thread so that you can handle all potential exceptions at just one point in your code. For more information, see Asynchronous Programming in C++.

In Windows 8.1 you can subscribe to the Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected static event, which provides access to unhandled errors that are about to bring down the process. Regardless of where the error originated, it reaches this handler as a Windows::ApplicationModel::Core::UnhandledError object that's passed in with the event args. When you call Propagate on the object, it creates and throws a Platform::*Exception of the type that corresponds to the error code. In the catch blocks, you can save user state if necessary and then either allow the process to terminate by calling throw, or do something to get the program back into a known state. The following example shows the basic pattern:


// In app.xaml.h:
void OnUnhandledException(Platform::Object^ sender, Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs^ e);

// In 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 does not use the finally clause.

Show:
© 2015 Microsoft