异常 (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::COMException 从 Platform::Exception派生。 当跨 ABI 边界引发异常时,必须引发一个标准异常。

不能从 Platform::Exception派生您自己的异常类型。 若要引发自定义异常,请使用用户定义的 HRESULT 构造 COMException 对象。

下表列出了标准异常。

名称 基础 HRESULT 说明
COMException 用户定义的 hresult 从 COM 方法调用返回无法识别的 HRESULT 时引发。
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 尝试取消引用空对象引用时引发。
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::Core::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 语言参考
命名空间参考