65.9K
CodeProject 正在变化。 阅读更多。
Home

自动将 Win32 项目转换为 WinUI3

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2024 年 1 月 20 日

CPOL

3分钟阅读

viewsIcon

9085

一套自动创建新 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.xamlApp.xaml.hApp.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:首次发布
© . All rights reserved.