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

如何向标准C++库中添加WinUI/WinRT XAML窗体

解决跨平台C++20库添加WinUI/WinRT错误弹窗的方案

核心思路

因为你的跨平台库要求无Windows依赖,绝对不能直接在库中嵌入WinUI代码,必须把Windows专属的UI逻辑拆成独立模块,通过条件编译让跨平台库在Windows环境下调用这个模块,其他平台保持原有错误报告逻辑。


步骤1:新建WinUI专属项目

在解决方案中添加一个WinUI 3桌面项目(C++/WinRT)(选桌面而非组件库,因为组件库是给其他WinRT应用调用的,我们需要直接控制窗口逻辑),命名比如WinUIErrorDialogs。

这个项目专门负责封装WinUI错误弹窗的显示逻辑,和你的跨平台库完全解耦。


步骤2:封装WinUI弹窗函数

在新建的WinUI项目中,写一个简单的全局函数(或静态类方法)来处理错误显示:

// WinUIErrorDialogs.h
#pragma once
#include <winrt/Microsoft.UI.Xaml.h>
#include <winrt/Microsoft.UI.Xaml.Controls.h>

namespace winrt::WinUIErrorDialogs::implementation
{
    struct ErrorDialogHelper
    {
        // 初始化WinUI运行时(仅调用一次)
        static void InitializeWinUI();
        // 显示错误弹窗
        static void ShowError(const winrt::hstring& title, const winrt::hstring& message);
    };
}

实现文件:

// WinUIErrorDialogs.cpp
#include "pch.h"
#include "WinUIErrorDialogs.h"
#include <winrt/Microsoft.UI.Xaml.Hosting.h>
#include <windows.h>

namespace winrt::WinUIErrorDialogs::implementation
{
    void ErrorDialogHelper::InitializeWinUI()
    {
        // 初始化WinUI XAML运行时,必须在调用任何UI API前执行
        Microsoft::UI::Xaml::XamlCheckProcessRequirements();
        Microsoft::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread();
    }

    void ErrorDialogHelper::ShowError(const winrt::hstring& title, const winrt::hstring& message)
    {
        // 创建ContentDialog
        Microsoft::UI::Xaml::Controls::ContentDialog dialog;
        dialog.Title(winrt::box_value(title));
        dialog.Content(winrt::box_value(message));
        dialog.PrimaryButtonText(L"确认");
        dialog.DefaultButton(Microsoft::UI::Xaml::Controls::ContentDialogButton::Primary);

        // 创建临时窗口承载对话框(如果没有现有窗口的话)
        auto window = Microsoft::UI::Xaml::Window();
        window.Content(dialog);
        window.Activate();

        // 等待用户关闭对话框
        dialog.ShowAsync().get();
    }
}

步骤3:在跨平台库中添加条件编译调用

修改你的跨平台库的错误报告子系统,通过_WIN32宏区分Windows平台:

// 跨平台库的ErrorReporter.h
#pragma once
#include <string>

class ErrorReporter
{
public:
    static void ReportError(const std::string& title, const std::string& message);
};
// 跨平台库的ErrorReporter.cpp
#include "ErrorReporter.h"
#include <mutex>

#ifdef _WIN32
// 引入WinUI项目的头文件,注意路径根据实际项目结构调整
#include "../WinUIErrorDialogs/WinUIErrorDialogs.h"
#include <winrt/base.h>

// 字符串转换:std::string(UTF-8)转hstring(UTF-16)
inline winrt::hstring to_hstring(const std::string& utf8Str)
{
    return winrt::to_hstring(utf8Str);
}

// 确保WinUI仅初始化一次
static std::once_flag s_winuiInitFlag;
#endif

void ErrorReporter::ReportError(const std::string& title, const std::string& message)
{
#ifdef _WIN32
    // 首次调用时初始化WinUI
    std::call_once(s_winuiInitFlag, [](){
        winrt::WinUIErrorDialogs::implementation::ErrorDialogHelper::InitializeWinUI();
    });

    // 调用WinUI弹窗
    winrt::WinUIErrorDialogs::implementation::ErrorDialogHelper::ShowError(
        to_hstring(title), 
        to_hstring(message)
    );
#else
    // 其他平台保留原有错误逻辑,比如控制台输出
    std::cerr << "[Error] " << title << ": " << message << std::endl;
#endif
}

步骤4:配置项目依赖与链接

  1. 在跨平台库项目的项目依赖中,勾选新建的WinUIErrorDialogs项目;
  2. 跨平台库的C/C++ → 常规 → 附加包含目录,添加WinUI项目的头文件路径;
  3. 跨平台库的链接器 → 输入 → 附加依赖项,添加WinUI项目生成的.lib文件(分别配置Debug/Release版本)。

关键注意事项

  • WinUI初始化:必须确保在调用任何UI API前初始化WinRT运行时,否则会直接崩溃。上面用std::once_flag保证仅初始化一次;
  • 窗口关联:如果你的跨平台库是被已有WinUI/WPF应用调用,可以修改弹窗函数,接收现有窗口的XamlRoot来关联,避免创建临时窗口;
  • 编码转换:跨平台库用UTF-8的std::string,WinRT用UTF-16的hstring,转换时注意编码一致性;
  • 平台隔离:所有WinUI相关代码必须放在独立项目中,跨平台库仅通过条件编译调用,确保非Windows平台编译时完全不涉及Windows代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:02:51