自动将 Win32 项目转换为 WinUI3





5.00/5 (3投票s)
一套自动创建新 VCXPROJ 文件的工具。
背景
这是我 之前的文章 的续篇,旨在帮助 C++ Win32 开发人员迁移到 Windows 10 中提供的 WinUI3。 您有 两种选择 来做到这一点
- 不要更改您的项目,而是调用 Bootstrapper API 来启用 WinUI3。
- 优点
- 您只有一个可执行文件。
- 缺点
- 您必须安装 Windows APP SDK 可再发行组件,具体取决于 WindowsAPP SDK 版本。 这需要管理员权限。 如果用户以某种方式从控制面板中删除它,或者与任何较新版本存在不兼容的情况,你就彻底完蛋了,因为它不会再次重新安装,除非通过一些 PowerShell 魔法将其完全删除。 如果您的应用程序想要使用较新的 WindowsAPP SDK 版本,则必须重新安装该可再发行组件。
- 您必须创建另一个 WinUI 项目来编译 Xaml 文件
- Xaml 编译的文件 (xbf) 不能具有 XAML 级别的绑定。 实际上,您需要用代码来完成所有操作。
- 优点
- 创建另一个 VCXPROJ 并将其设置为“Self Contained”(自包含)。 这会将所有需要的文件放入输出目录,您可以重新分发它们。
- 优点
- 无需管理员权限,您可以自己管理可再发行文件。
- 您拥有所有 XAML 工具。
- 缺点
- 如果运行 Windows 7,您必须有两个可执行文件。 “Self Contained”(自包含)项目创建的可执行文件与 Windows < 10 不兼容。
- 优点
所以,让我们选择第二种方法,当然。
准备 Win32 项目
- 将其切换到 C++17 或更高版本
- 将预编译头(如果不存在,则创建)更改为 pch.h/pch.cpp。 这不是必需的,但可以节省您的时间,因为 Visual Studio 默认生成的所有内容都包含 pch.h。
使用转换器
转换器是一个 XML 工具,用于在现有的 Win32 项目中创建修改
- 加载 vcxproj
- 将“
ToolsVersion
”更改为15
- 更新您的 PCH.h 以包含
#ifdef Win32_WINUI3 #undef GetCurrentTime #include <winrt/Windows.Foundation.h> #include <winrt/Windows.Foundation.Collections.h> #include <winrt/Windows.Storage.Streams.h> #include <winrt/Windows.ApplicationModel.Activation.h> #include <winrt/Microsoft.UI.Composition.h> #include <winrt/Microsoft.UI.Xaml.h> #include <winrt/Microsoft.UI.Xaml.Controls.h> #include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h> #include <winrt/Microsoft.UI.Xaml.Data.h> #include <winrt/Microsoft.UI.Xaml.Interop.h> #include <microsoft.ui.xaml.window.h> #include <winrt/Microsoft.UI.Xaml.Markup.h> #include <winrt/Microsoft.UI.Xaml.Media.h> #include <winrt/Microsoft.UI.Xaml.Navigation.h> #include <winrt/Microsoft.UI.Xaml.Shapes.h> #include <winrt/Microsoft.UI.Xaml.Media.h> #include <winrt/Microsoft.UI.Xaml.Media.Imaging.h> #include <winrt/Microsoft.UI.Dispatching.h> #include <wil/cppwinrt_helpers.h> #include <appmodel.h> #endif
- 安装 NuGet 包(如果不存在)。 在撰写本文时,这些是最新版本,当它们更新时更改它们
//CppWinRT const char* p1v = "2.0.240111.5"; // WIL const char* p2v = "1.0.231216.1"; // SDK Build Tools const char* p3v = "10.0.22621.2428"; // AppSdk const char* p4v = "1.4.231219000";
- 创建默认的
Package.appxmanifest
- 更改中间构建目录,以便 WinUI 文件在新目录中构建
- 添加预处理器定义
Win32_WINUI3
- 将全局变量放入项目中,以便与 WinUI 项目模板一起使用
<CppWinRTOptimized>true</CppWinRTOptimized> <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> <AppContainerApplication>false</AppContainerApplication> <AppxPackage>true</AppxPackage> <ApplicationType>Windows Store</ApplicationType> <ApplicationTypeRevision>10.0</ApplicationTypeRevision> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformMinVersion>10.0.17763.0</WindowsTargetPlatformMinVersion> <UseWinUI>true</UseWinUI> <WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained> <WindowsPackageType>None</WindowsPackageType> <EnableMsixTooling>true</EnableMsixTooling>
- 添加 Nuget Stuff
<Import Project="packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" /> <Import Project="packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" /> <Import Project="packages\Microsoft.WindowsAppSDK.1.4.231219000\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.1.4.231219000\build\native\Microsoft.WindowsAppSDK.props')" /> <ImportGroup Label="ExtensionTargets"> <Import Project="packages\Microsoft.WindowsAppSDK.1.4.231219000\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.1.4.231219000\build\native\Microsoft.WindowsAppSDK.targets')" /> <Import Project="packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" /> <Import Project="packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> <Import Project="packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" /> </ImportGroup>
- 添加默认资源并复制 png
<Image Include="Assets\LockScreenLogo.scale-200.png" /> <Image Include="Assets\SplashScreen.scale-200.png"> <DeploymentContent>true</DeploymentContent> </Image> <Image Include="Assets\Square150x150Logo.scale-200.png" /> <Image Include="Assets\Square44x44Logo.scale-200.png" /> <Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" /> <Image Include="Assets\StoreLogo.png" /> <Image Include="Assets\Wide310x150Logo.scale-200.png" />
- 创建 App.xaml、App.xaml.h 和 App.xaml.cpp
<?xml version="1.0" encoding="utf-8"?> <Application x:Class="App2.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:App2"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" /> <!-- Other merged dictionaries here --> </ResourceDictionary.MergedDictionaries> <!-- Other app resources here --> </ResourceDictionary> </Application.Resources> </Application> #pragma once #include "App.xaml.g.h" namespace winrt::%s::implementation { struct App : AppT<App> { App(); void OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&); private: winrt::Microsoft::UI::Xaml::Window window{ nullptr }; }; } #include "pch.h" #include "App.xaml.h" // #include "MainWindow.xaml.h" using namespace winrt; using namespace Microsoft::UI::Xaml; // To learn more about WinUI, the WinUI project structure, // and more about our project templates, see: http://aka.ms/winui-project-info. namespace winrt::%s::implementation { App::App() { #if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION UnhandledException([](IInspectable const&, UnhandledExceptionEventArgs const& e) { if (IsDebuggerPresent()) { auto errorMessage = e.Message(); __debugbreak(); } }); #endif } /// <summary> /// Invoked when the application is launched. /// </summary> /// <param name="e">Details about the launch request and process.</param> void App::OnLaunched([[maybe_unused]] LaunchActivatedEventArgs const& e) { // window = make<MainWindow>(); // window.Activate(); } }
最后,它将新项目另存为 Win32ProjectWUI.vcxproj,您可以将其添加到解决方案中。
添加 WinUI Stuff
该项目仍然运行 WinMain
和您的 Win32 代码。 要添加例如一个窗口
- 添加 新项 -> WinUI -> 空白窗口
- 像往常一样编辑 XAML、IDL、H 和 CPP 以创建窗口
- 以 WinUI 风格执行
WinMain init
操作WinMain #ifdef Win32_WINUI3 { void (WINAPI *pfnXamlCheckProcessRequirements)(); auto module = ::LoadLibrary(L"Microsoft.ui.xaml.dll"); if (module) { pfnXamlCheckProcessRequirements = reinterpret_cast<decltype (pfnXamlCheckProcessRequirements)>(GetProcAddress (module, "XamlCheckProcessRequirements")); if (pfnXamlCheckProcessRequirements) { (*pfnXamlCheckProcessRequirements)(); } ::FreeLibrary(module); } } winrt::init_apartment(winrt::apartment_type::single_threaded); ::winrt::Microsoft::UI::Xaml::Application::Start( [](auto&&) { ::winrt::make<::winrt::your_project_namespace::implementation::App>(); });
只有在没有可见窗口时,此
Start()
调用才会返回。 所以现在,您可以编辑 app.xaml.h 以包含,例如,blankwindow.xaml.h 并在OnLaunched
方法中显示该窗口window = make<winrt::your_namespace::BlankWindow>(); window.Activate();
代码
该代码包含一个示例 Win32 项目和转换器。 转换器将创建一个 WUI vcxproj 文件,您可以将其添加到项目中,并按照描述的方式进行操作。
玩得开心!
历史
- 2024 年 1 月 21日:首次发布