├── .gitignore ├── CMakeLists.txt ├── HybridCRT.cmake ├── README.md ├── screenshot.png └── src ├── App.idl ├── App.xaml ├── App.xaml.cpp ├── App.xaml.h ├── CMakeLists.txt ├── DemoPage.idl ├── DemoPage.xaml ├── DemoPage.xaml.cpp ├── DemoPage.xaml.h ├── Directory.Build.props ├── Directory.Build.targets ├── MainWindow.idl ├── MainWindow.xaml ├── MainWindow.xaml.cpp ├── MainWindow.xaml.h ├── app.manifest └── pch.h /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(HybridCRT.cmake NO_POLICY_SCOPE) 2 | 3 | project("com.fredemmott.CmakeCppWinRTWinUI3") 4 | cmake_minimum_required(VERSION 3.23) 5 | add_subdirectory(src) 6 | -------------------------------------------------------------------------------- /HybridCRT.cmake: -------------------------------------------------------------------------------- 1 | # Hybrid CRT 2 | # https://github.com/microsoft/WindowsAppSDK/blob/main/docs/Coding-Guidelines/HybridCRT.md 3 | 4 | # Enable CMAKE_MSVC_RUNTIME_LIBRARY variable 5 | cmake_policy(SET CMP0091 NEW) 6 | set( 7 | CMAKE_MSVC_RUNTIME_LIBRARY 8 | # Statically link the C++ runtime libraries, but partially override this below 9 | "MultiThreaded$<$:Debug>" 10 | ) 11 | add_link_options( 12 | "/DEFAULTLIB:ucrt$<$:d>.lib" # include the dynamic UCRT 13 | "/NODEFAULTLIB:libucrt$<$:d>.lib" # ignore the static UCRT 14 | ) 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WinUI 3, C++/WinRT, and Xaml with CMake 2 | 3 | ![A screenshot of the app, showing a left hand navigation view](screenshot.png) 4 | 5 | ## Status 6 | 7 | This is an as-is, unsupported, proof of concept. No help is available. 8 | 9 | ## Notes 10 | 11 | For a real-world application, see https://github.com/openkneeboard/openkneeboard 12 | 13 | * Xaml-related header files **must** be listed as targert sources 14 | * The `Directory.Build.targets` file is currently required; it slightly modifies the CMake generator 15 | * I've avoided `use namespace` to be explicit; I'm not aiming for this to be 'best practice', just to be unambiguous and minimal 16 | * `pch.h` and its' contents are required by the generated code 17 | * `pch.h` is not currently a pre-compiled header 18 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fredemmott/cmake-cpp-winrt-winui3/1b5fb0b325aaa2099cdc2aa945e804752e1c3216/screenshot.png -------------------------------------------------------------------------------- /src/App.idl: -------------------------------------------------------------------------------- 1 | namespace DemoApp 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /src/App.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/App.xaml.cpp: -------------------------------------------------------------------------------- 1 | #include "App.xaml.h" 2 | 3 | #include "MainWindow.xaml.h" 4 | 5 | namespace winrt::DemoApp::implementation { 6 | 7 | App::App() { 8 | InitializeComponent(); 9 | #ifdef DEBUG 10 | UnhandledException( 11 | [this](IInspectable const&, UnhandledExceptionEventArgs const& e) { 12 | if (IsDebuggerPresent()) { 13 | auto errorMessage = e.Message(); 14 | __debugbreak(); 15 | } 16 | throw; 17 | }); 18 | #endif 19 | } 20 | 21 | void App::OnLaunched( 22 | Microsoft::UI::Xaml::LaunchActivatedEventArgs const& 23 | ) noexcept { 24 | window = make(); 25 | window.Activate(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/App.xaml.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pch.h" 4 | #include "App.xaml.g.h" 5 | 6 | namespace winrt::DemoApp::implementation { 7 | struct App : AppT { 8 | App(); 9 | 10 | void OnLaunched( 11 | Microsoft::UI::Xaml::LaunchActivatedEventArgs const&) noexcept; 12 | 13 | private: 14 | winrt::Microsoft::UI::Xaml::Window window {nullptr}; 15 | }; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Patch up the generated vcxproj 2 | configure_file( 3 | "${CMAKE_CURRENT_SOURCE_DIR}/Directory.Build.props" 4 | "${CMAKE_CURRENT_BINARY_DIR}/Directory.Build.props" 5 | COPYONLY 6 | ) 7 | configure_file( 8 | "${CMAKE_CURRENT_SOURCE_DIR}/Directory.Build.targets" 9 | "${CMAKE_CURRENT_BINARY_DIR}/Directory.Build.targets" 10 | COPYONLY 11 | ) 12 | 13 | add_executable( 14 | DemoApp 15 | WIN32 16 | app.manifest 17 | App.xaml.cpp App.xaml.h App.xaml App.idl 18 | DemoPage.xaml.cpp DemoPage.xaml.h DemoPage.xaml DemoPage.idl 19 | MainWindow.xaml.cpp MainWindow.xaml.h MainWindow.xaml MainWindow.idl 20 | ) 21 | set_property( 22 | SOURCE App.xaml 23 | PROPERTY VS_XAML_TYPE 24 | "ApplicationDefinition" 25 | ) 26 | set_property( 27 | TARGET DemoApp 28 | PROPERTY VS_PACKAGE_REFERENCES 29 | "Microsoft.Windows.CppWinRT_2.0.230706.1" 30 | "Microsoft.WindowsAppSDK_1.4.231115000" 31 | "Microsoft.Windows.SDK.BuildTools_10.0.22621.756" 32 | "Microsoft.Windows.ImplementationLibrary_1.0.230629.1" 33 | ) 34 | target_include_directories( 35 | DemoApp 36 | PRIVATE 37 | "${CMAKE_CURRENT_SOURCE_DIR}" 38 | ) 39 | target_precompile_headers( 40 | DemoApp 41 | PRIVATE 42 | pch.h 43 | ) 44 | set_target_properties( 45 | DemoApp 46 | PROPERTIES 47 | CXX_STANDARD 20 48 | CXX_STANDARD_REQUIRED ON 49 | CXX_EXTENSIONS OFF 50 | # ----- C++/WinRT, Windows App SDK, and WinUI stuff starts here ----- 51 | VS_GLOBAL_RootNamespace DemoApp 52 | VS_GLOBAL_AppContainerApplication false 53 | VS_GLOBAL_AppxPackage false 54 | VS_GLOBAL_CppWinRTOptimized true 55 | VS_GLOBAL_CppWinRTRootNamespaceAutoMerge true 56 | VS_GLOBAL_UseWinUI true 57 | VS_GLOBAL_ApplicationType "Windows Store" 58 | VS_GLOBAL_WindowsPackageType None 59 | VS_GLOBAL_EnablePreviewMsixTooling true 60 | VS_GLOBAL_WindowsAppSDKSelfContained true 61 | ) 62 | 63 | # Set source file dependencies properly for Xaml and non-Xaml IDL 64 | # files. 65 | # 66 | # Without this, `module.g.cpp` will not include the necessary headers 67 | # for non-Xaml IDL files, e.g. value converters 68 | get_target_property(SOURCES DemoApp SOURCES) 69 | 70 | foreach(SOURCE ${SOURCES}) 71 | cmake_path(GET SOURCE EXTENSION LAST_ONLY EXTENSION) 72 | 73 | if(NOT "${EXTENSION}" STREQUAL ".idl") 74 | continue() 75 | endif() 76 | 77 | set(IDL_SOURCE "${SOURCE}") 78 | 79 | cmake_path(REMOVE_EXTENSION SOURCE LAST_ONLY OUTPUT_VARIABLE BASENAME) 80 | set(XAML_SOURCE "${BASENAME}.xaml") 81 | 82 | if("${XAML_SOURCE}" IN_LIST SOURCES) 83 | set_property( 84 | SOURCE "${IDL_SOURCE}" 85 | PROPERTY VS_SETTINGS 86 | "SubType=Code" 87 | "DependentUpon=${XAML_SOURCE}" 88 | ) 89 | else() 90 | set_property( 91 | SOURCE "${IDL_SOURCE}" 92 | PROPERTY VS_SETTINGS 93 | "SubType=Code" 94 | ) 95 | set_property( 96 | SOURCE "${BASENAME}.h" 97 | PROPERTY VS_SETTINGS 98 | "DependentUpon=${IDL_SOURCE}" 99 | ) 100 | set_property( 101 | SOURCE "${BASENAME}.cpp" 102 | PROPERTY VS_SETTINGS 103 | "DependentUpon=${IDL_SOURCE}" 104 | ) 105 | endif() 106 | endforeach() -------------------------------------------------------------------------------- /src/DemoPage.idl: -------------------------------------------------------------------------------- 1 | namespace DemoApp 2 | { 3 | [default_interface] 4 | runtimeclass DemoPage: Microsoft.UI.Xaml.Controls.Page 5 | { 6 | DemoPage(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/DemoPage.xaml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla vel massa vitae tellus convallis varius non ut odio. Morbi vel justo pellentesque, tempus turpis in, consequat lectus. Aenean sed commodo augue. Mauris felis lorem, placerat ut lectus et, egestas pharetra lacus. Duis nec dapibus nunc. Integer massa erat, congue vel maximus eget, malesuada sed tortor. Nunc eu elit vitae est auctor sagittis ut et nisi. Proin vel vestibulum dolor. 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/DemoPage.xaml.cpp: -------------------------------------------------------------------------------- 1 | #include "DemoPage.xaml.h" 2 | #if __has_include("DemoPage.g.cpp") 3 | #include "DemoPage.g.cpp" 4 | #endif 5 | 6 | #include 7 | 8 | namespace winrt::DemoApp::implementation { 9 | 10 | DemoPage::DemoPage() { 11 | InitializeComponent(); 12 | } 13 | 14 | void DemoPage::OnNavigatedTo( 15 | const Microsoft::UI::Xaml::Navigation::NavigationEventArgs& args 16 | ) noexcept { 17 | Title().Text(winrt::unbox_value(args.Parameter())); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/DemoPage.xaml.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pch.h" 4 | #include "DemoPage.g.h" 5 | 6 | namespace winrt::DemoApp::implementation { 7 | struct DemoPage : DemoPageT { 8 | DemoPage(); 9 | 10 | void OnNavigatedTo(const Microsoft::UI::Xaml::Navigation::NavigationEventArgs&) noexcept; 11 | }; 12 | } 13 | 14 | namespace winrt::DemoApp::factory_implementation { 15 | struct DemoPage : DemoPageT {}; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | win10-x64 4 | native,Version=v0.0 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/MainWindow.idl: -------------------------------------------------------------------------------- 1 | namespace DemoApp 2 | { 3 | [default_interface] 4 | runtimeclass MainWindow : Microsoft.UI.Xaml.Window 5 | { 6 | MainWindow(); 7 | Microsoft.UI.Xaml.Controls.Frame Frame { get; }; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 10 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/MainWindow.xaml.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.xaml.h" 2 | #if __has_include("MainWindow.g.cpp") 3 | #include "MainWindow.g.cpp" 4 | #endif 5 | 6 | namespace winrt::DemoApp::implementation { 7 | 8 | MainWindow::MainWindow() { 9 | InitializeComponent(); 10 | } 11 | 12 | void MainWindow::Navigate( 13 | const IInspectable& sender, 14 | const Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs& args) noexcept { 15 | if (args.IsSettingsInvoked()) { 16 | // TODO 17 | return; 18 | } 19 | 20 | auto item = args.InvokedItemContainer().try_as< 21 | Microsoft::UI::Xaml::Controls::NavigationViewItem 22 | >(); 23 | 24 | if (!item) { 25 | // FIXME: show an error? 26 | return; 27 | } 28 | 29 | // TODO: you probably want to use item.Tag() to identify a specific item 30 | Frame().Navigate(xaml_typename(), item.Content()); 31 | } 32 | 33 | void MainWindow::GoBack( 34 | const IInspectable& sender, 35 | const Microsoft::UI::Xaml::Controls::NavigationViewBackRequestedEventArgs&) noexcept { 36 | Frame().GoBack(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/MainWindow.xaml.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pch.h" 4 | #include "MainWindow.g.h" 5 | 6 | namespace winrt::DemoApp::implementation { 7 | struct MainWindow : MainWindowT { 8 | MainWindow(); 9 | 10 | void Navigate( 11 | const IInspectable& sender, 12 | const Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs&) noexcept; 13 | 14 | void GoBack( 15 | const IInspectable& sender, 16 | const Microsoft::UI::Xaml::Controls::NavigationViewBackRequestedEventArgs&) noexcept; 17 | }; 18 | } 19 | 20 | namespace winrt::DemoApp::factory_implementation { 21 | struct MainWindow : MainWindowT {}; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | true/PM 8 | PerMonitorV2, PerMonitor 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | ///// These are all required for the generated code to work ///// 4 | 5 | #include 6 | #include 7 | 8 | #undef GetCurrentTime 9 | 10 | #include 11 | #include 12 | --------------------------------------------------------------------------------