You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取C++/CX中task内部抛出异常的Message信息

如何获取C++/CX中task任务内部发生的异常对应的消息内容?

问题现象

同步调用场景下可以正常获取异常消息:

IAsyncAction^ Foo() {
    throw ref new Platform::Exception(-1, "Foo exception …");
}

…
…

try {
    Foo();
}
catch (Exception^ ex) {
    OutputDebugStringW(ex->Message->Data());
}
// Output: "Foo exception …"

但在异步调用场景中,上述获取方式无法正常生效:

IAsyncAction^ Foo_action() {
    return concurrency::create_async([=] {
        throw ref new Platform::Exception(-1, "Foo_action exception …");
        });
}

…
…

this->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler([this] {
        concurrency::create_task(Foo_action())
            .then([this](concurrency::task<void> previousTask) {
                try {
                    previousTask.get();
                }
                catch (Platform::Exception^ ex) {
                    OutputDebugStringW(ex->Message->Data());
                }
            });
        }));

// Output: "The text associated with this error code could not be found."

异步场景下捕获到异常时,ex->HResult属性可以正常保留原有错误码值,但无法读取到自定义的异常Message内容。

原因

Platform::Exception的自定义Message不会跨WinRT ABI(应用程序二进制接口)边界传递。create_async返回的IAsyncAction属于WinRT标准接口,异常从lambda内部抛出后跨线程、跨异步上下文传递时,只会按照COM规范封送HResult错误码,附加的自定义消息字符串属于C++/CX运行时的进程内私有数据,会在封送过程中被丢弃。最终捕获异常时,系统会尝试根据HResult查找系统内置的错误文本,如果传入的是自定义非标准HResult(比如示例中的-1),就会返回“找不到与该错误码关联的文本”的提示。

解决方法

  • 不要依赖Exception->Message跨异步/WinRT边界传递自定义信息。最稳妥的方式是提前维护自定义HResult和错误文本的映射表,捕获异常拿到HResult后,直接查本地映射表获取对应的错误消息即可。
  • 如果需要传递动态错误信息,不要让异常直接穿过create_async生成的WinRT接口边界:可以在create_async的lambda内部先捕获异常,将动态错误消息存在全局/线程本地/自定义错误管理类中,以HResult为索引存储,捕获到异常后再通过HResult取出提前存储的消息。示例逻辑:
// 简单错误消息存储实现示例
ref class ErrorManager sealed {
private:
    static Platform::Collections::Map<int, Platform::String^>^ _hrToMsg = ref new Platform::Collections::Map<int, Platform::String^>();
public:
    static void SetMsg(int hr, Platform::String^ msg) {
        _hrToMsg->Insert(hr, msg);
    }
    static Platform::String^ GetMsg(int hr) {
        if (_hrToMsg->HasKey(hr)) return _hrToMsg->Lookup(hr);
        return "Unknown error";
    }
};

IAsyncAction^ Foo_action() {
    return concurrency::create_async([=] {
        try {
            throw ref new Platform::Exception(-1, "Foo_action exception …");
        }
        catch (Platform::Exception^ ex) {
            ErrorManager::SetMsg(ex->HResult, ex->Message);
            throw;
        }
    });
}

// 异常捕获处逻辑
catch (Platform::Exception^ ex) {
    auto msg = ErrorManager::GetMsg(ex->HResult);
    OutputDebugStringW(msg->Data());
}
  • 如果不需要兼容其他WinRT语言调用,也可以全程使用concurrency::task而非IAsyncAction/IAsyncOperation实现异步逻辑,避免异常穿过WinRT ABI边界,这种情况下PPL任务会在进程内保留完整的异常信息。

内容的提问来源于stack exchange,提问作者isrepeat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 23:48:23