Använda winapp CLI med C++ och CMake

Den här guiden visar hur du använder winapp CLI med ett C++-program för att felsöka med paketidentitet och paketera ditt program som en MSIX.

Paketidentitet är ett grundläggande begrepp i Windows app modellen. Det gör att ditt program kan komma åt specifika Windows API:er (t.ex. meddelanden, säkerhet, AI-API:er osv.), har en ren installations-/avinstallationsupplevelse med mera.

En körbar standard (som en som skapats med cmake --build) har inte paketidentitet. Den här guiden visar hur du lägger till den för felsökning och sedan paketera den för distribution.

Förutsättningar

  1. Byggverktyg: Använd en kompilatorverktygskedja som stöds av CMake. I det här exemplet används Visual Studio. Du kan installera community-utgåvan med (eller uppdatera om den redan är installerad):

    winget install --id Microsoft.VisualStudio.Community --source winget --override "--add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended --passive --wait"
    

    Starta om efter installationen.

  2. CMake: Installera CMake (eller uppdatera om det redan är installerat):

    winget install Kitware.CMake --source winget
    
  3. winapp CLI: Installera winapp cli via winget (eller uppdatera om det redan är installerat):

    winget install Microsoft.winappcli --source winget
    

1. Skapa en ny C++-app

Börja med att skapa ett enkelt C++-program. Skapa en ny katalog för projekt.

mkdir cpp-app
cd cpp-app

Skapa en main.cpp fil med ett grundläggande "Hello, world!"-program:

#include <iostream>

int main() {
    std::cout << "Hello, world!" << std::endl;
    return 0;
}

Skapa en CMakeLists.txt fil för att konfigurera bygget:

cmake_minimum_required(VERSION 3.20)
project(cpp-app)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(cpp-app main.cpp)

Skapa och kör den för att se till att allt fungerar:

cmake -B build
cmake --build build --config Debug
.\build\Debug\cpp-app.exe

Utdata ska vara "Hello, world!"

2. Uppdatera koden för att kontrollera identiteten

Vi uppdaterar appen för att kontrollera om den körs med paketidentitet. Detta hjälper oss att kontrollera att identiteten fungerar korrekt i senare steg. Vi använder Windows Runtime C++ API för att komma åt paket-API:erna.

Lägg först till följande rad i slutet av din CMakeLists.txt för att länka till Windows App-modellbiblioteket:

# Link Windows Runtime libraries
target_link_libraries(cpp-app PRIVATE WindowsApp.lib OneCoreUap.lib)

Ersätt sedan hela innehållet i main.cpp med följande kod. Den här koden försöker hämta den aktuella paketidentiteten med hjälp av Windows Runtime-API:et. Om det lyckas skrivs paketfamiljenamnet ut. annars skrivs "Inte paketerad".

#include <iostream>
#include <windows.h>
#include <appmodel.h>

int main() {
    UINT32 length = 0;
    LONG result = GetCurrentPackageFamilyName(&length, nullptr);
    
    if (result == ERROR_INSUFFICIENT_BUFFER) {
        // We have a package identity
        std::wstring familyName;
        familyName.resize(length);
        
        result = GetCurrentPackageFamilyName(&length, familyName.data());
        
        if (result == ERROR_SUCCESS) {
            std::wcout << L"Package Family Name: " << familyName.c_str() << std::endl;
        } else {
            std::wcout << L"Error retrieving Package Family Name" << std::endl;
        }
    } else {
        // No package identity
        std::cout << "Not packaged" << std::endl;
    }

    return 0;
}

3. Kör utan identitet

Återskapa och kör appen som vanligt:

cmake --build build --config Debug
.\build\Debug\cpp-app.exe

Du bör se utdata "Inte paketerad". Detta bekräftar att den körbara standarden körs utan paketidentitet.

4. Initiera Project med winapp CLI

Kommandot winapp init konfigurerar allt du behöver på en gång: appmanifest, resurser och eventuellt Windows App SDK huvuden för C++-utveckling.

Kör följande kommando och följ anvisningarna:

winapp init .

När du uppmanas att göra det:

  • Paketnamn: Tryck på Enter för att acceptera standardvärdet (cpp-app)
  • Utgivarens namn: Tryck på Enter för att acceptera standardvärdet eller ange ditt namn
  • Version: Tryck på Retur för att acceptera 1.0.0.0
  • Startpunkt: Tryck på Retur för att acceptera standardvärdet (cpp-app.exe)
  • Setup SDK:er: Välj "Stabila SDK:er" för att ladda ned Windows App SDK och generera C++-huvuden

Det här kommandot kommer att:

  • Skapa Package.appxmanifest – manifestet som definierar appens identitet
  • Skapa Assets mapp – ikoner som krävs för MSIX-paketering och Lagringsöverföring
  • Skapa en .winapp-mapp med Windows App SDK rubriker och bibliotek
  • Skapa en winapp.yaml konfigurationsfil för att fästa SDK-versioner

Du kan öppna Package.appxmanifest för att ytterligare anpassa egenskaper som visningsnamn, utgivare och funktioner.

Lägg till köralias (för konsolappar)

Med ett körningsalias kan användare köra din app med namn från valfri terminal (som cpp-app). Det möjliggör winapp run --with-alias även under utveckling, vilket behåller konsolutdata i den aktuella terminalen i stället för att öppna ett nytt fönster.

Du kan lägga till en automatiskt:

winapp manifest add-alias

Eller manuellt: öppna Package.appxmanifest och lägg till uap5 namnområdet i taggen <Package> om det saknas och lägg sedan till tillägget i <Applications><Application><Extensions>...:

<Package
  ...
  xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
+ xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
  IgnorableNamespaces="uap uap2 uap3 rescap desktop desktop6 uap10">

  ...
  <Applications>
    <Application ...>
      ...
+     <Extensions>
+       <uap5:Extension Category="windows.appExecutionAlias">
+         <uap5:AppExecutionAlias>
+           <uap5:ExecutionAlias Alias="cpp-app.exe" />
+         </uap5:AppExecutionAlias>
+       </uap5:Extension>
+     </Extensions>
    </Application>
  </Applications>
</Package>

5. Felsöka med identitet

Om du vill testa funktioner som kräver identitet (t.ex. meddelanden) utan att helt paketera appen kan du använda winapp run. Detta registrerar ett löst layoutpaket (precis som en riktig MSIX-installation) och startar appen i ett steg. Inget certifikat eller signering krävs för felsökning.

  1. Skapa den körbara filen:

    cmake --build build --config Debug
    
  2. Kör med identitet:

    winapp run .\build\Debug --with-alias
    

Flaggan --with-alias startar appen via dess körningsalias så att konsolutdata finns kvar i den aktuella terminalen. Detta kräver uap5:ExecutionAlias, vilket vi lade till i steg 4.

Tips/Råd

winapp run registrerar även paketet i systemet. Därför kan MSIX visas som "redan installerat" när du försöker installera det senare i steg 8. Använd winapp unregister för att rensa utvecklingspaket när du är färdig.

Nu bör du se utdata som liknar:

Package Family Name: cpp-app_12345abcde

Detta bekräftar att din app körs med en giltig paketidentitet!

Alternativ: Gles paketidentitet

Om du behöver glesa paketbeteende specifikt (identitet utan att kopiera filer) kan du använda create-debug-identity i stället:

winapp create-debug-identity .\build\Debug\cpp-app.exe
.\build\Debug\cpp-app.exe

Tips/Råd

Avancerade felsökningsarbetsflöden (koppla felsökningsprogram, IDE-konfiguration, startfelsökning) finns i felsökningsguiden.

6. Använda Windows App SDK (valfritt)

Om du har valt att konfigurera SDK:erna under winapp init har du nu åtkomst till Windows App SDK rubriker i mappen .winapp/include. Detta ger dig tillgång till moderna Windows API:er som meddelanden, fönster, AI på enheten med mera. Om du bara behöver paketidentitet för distribution kan du gå vidare till steg 7.

Nu ska vi lägga till ett enkelt exempel som skriver ut Windows App Runtime-versionen.

Uppdatera CMakeLists.txt

Lägg till följande rad i slutet av din CMakeLists.txt för att inkludera Windows App SDK rubriker:

# Add Windows App SDK include directory
target_include_directories(cpp-app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.winapp/include)

Uppdatera main.cpp

Ersätt hela innehållet i main.cpp för att använda api:et Windows App Runtime:

#include <iostream>
#include <windows.h>
#include <appmodel.h>
#include <winrt/Microsoft.Windows.ApplicationModel.WindowsAppRuntime.h>

int main() {
    // Initialize WinRT
    winrt::init_apartment();
    
    UINT32 length = 0;
    LONG result = GetCurrentPackageFamilyName(&length, nullptr);
    
    if (result == ERROR_INSUFFICIENT_BUFFER) {
        // We have a package identity
        std::wstring familyName;
        familyName.resize(length);
        
        result = GetCurrentPackageFamilyName(&length, familyName.data());
        
        if (result == ERROR_SUCCESS) {
            std::wcout << L"Package Family Name: " << familyName.c_str() << std::endl;
            
            // Get Windows App Runtime version using the API
            auto runtimeVersion = winrt::Microsoft::Windows::ApplicationModel::WindowsAppRuntime::RuntimeInfo::AsString();
            std::wcout << L"Windows App Runtime Version: " << runtimeVersion.c_str() << std::endl;
        } else {
            std::wcout << L"Error retrieving Package Family Name" << std::endl;
        }
    } else {
        std::cout << "Not packaged" << std::endl;
    }
    
    return 0;
}

Skapa och kör

Bygg om applikationen med Windows App SDK headerfiler:

cmake --build build --config Debug
winapp run .\build\Debug --with-alias

Nu bör du se utdata som:

Package Family Name: cpp-app_12345abcde
Windows App Runtime Version: 1.8-stable (1.8.0)

Katalogen .winapp/include innehåller alla nödvändiga rubriker för Windows App SDK, inklusive:

  • winrt/ – WinRT C++-projektionshuvud för åtkomst till Windows Runtime API
  • Microsoft.UI.*.h – WinUI 3-huvuden för moderna gränssnittskomponenter
  • MddBootstrap.h – Windows App SDK bootstrapping
  • WindowsAppSDK-VersionInfo.h – Versionsinformation
  • Och många fler Windows App SDK komponenter

Mer avancerad Windows App SDK användning finns i dokumentationen Windows App SDK.

7. Återställ rubriker när det behövs

Mappen .winapp läggs automatiskt till .gitignore av winapp init, så den checkas inte in i källkontrollen. När andra klonar ditt projekt måste de återställa dessa filer innan bygget.

Manuell konfiguration

Kör dessa två kommandon efter kloning av lagringsplatsen:

# Restore Windows App SDK headers
winapp restore

# Generate development certificate (optional - only if planning to package the app and sideload)
winapp cert generate --if-exists skip

Sedan kan du skapa och köra normalt med cmake -B build och cmake --build build --config Debug.

Automatisk installation med CMake

Du kan också automatisera detta genom att lägga till installationslogik i din CMakeLists.txt. Här är den fullständiga CMakeLists.txt med automatisering, korrekt länkning och minimalt användande av C++20-standarden.

cmake_minimum_required(VERSION 3.20)
project(cpp-app)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Download winapp CLI if not available in PATH
find_program(WINAPP_CLI winapp)
if(NOT WINAPP_CLI)
    set(WINAPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.winapp-tools")
    set(WINAPP_CLI "${WINAPP_DIR}/winapp.exe")
    
    if(NOT EXISTS "${WINAPP_CLI}")
        message(STATUS "Downloading winapp CLI...")
        
        # Determine architecture
        if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64")
            set(WINAPP_ARCH "arm64")
        else()
            set(WINAPP_ARCH "x64")
        endif()
        
        # Download and extract
        set(WINAPP_ZIP "${CMAKE_CURRENT_BINARY_DIR}/winappcli.zip")
        file(DOWNLOAD 
            "https://github.com/microsoft/WinAppCli/releases/latest/download/winappcli-${WINAPP_ARCH}.zip"
            "${WINAPP_ZIP}"
            SHOW_PROGRESS
        )
        
        file(ARCHIVE_EXTRACT INPUT "${WINAPP_ZIP}" DESTINATION "${WINAPP_DIR}")
        file(REMOVE "${WINAPP_ZIP}")
        message(STATUS "winapp CLI downloaded to ${WINAPP_DIR}")
    endif()
endif()

# Automatically restore Windows App SDK headers and generate certificate if needed
# This runs once during CMake configuration, not on every build
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.winapp/include")
    message(STATUS "Restoring Windows App SDK headers...")
    execute_process(
        COMMAND "${WINAPP_CLI}" restore
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        RESULT_VARIABLE RESTORE_RESULT
    )
    if(NOT RESTORE_RESULT EQUAL 0)
        message(WARNING "Failed to restore Windows App SDK. Run 'winapp restore' manually.")
    endif()
endif()

if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/devcert.pfx")
    message(STATUS "Generating development certificate...")
    execute_process(
        COMMAND "${WINAPP_CLI}" cert generate --if-exists skip
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        RESULT_VARIABLE CERT_RESULT
    )
    if(NOT CERT_RESULT EQUAL 0)
        message(WARNING "Failed to generate certificate. Run 'winapp cert generate' manually.")
    endif()
endif()

add_executable(cpp-app main.cpp)

# Link Windows Runtime libraries
target_link_libraries(cpp-app PRIVATE WindowsApp.lib OneCoreUap.lib)

# Add Windows App SDK include directory
target_include_directories(cpp-app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.winapp/include)

Med den här konfigurationen:

  • När någon klonar lagringsplatsen och kör cmake -B build, laddas winapp ned automatiskt om den inte hittas i PATH
  • Windows App SDK-huvuden och certifikat återställs automatiskt
  • Kommandona körs bara en gång under konfigurationen (inte i varje version) eftersom de kontrollerar om filerna redan finns
  • Om kommandona misslyckas visar CMake en varning med instruktioner för att köra dem manuellt
  • Den nedladdade winappen lagras i .winapp-tools/ (lägg till den i .gitignore om det behövs)

8. Paket med MSIX

När du är redo att distribuera din app kan du paketera den som en MSIX med samma manifest. MSIX tillhandahåller ren installation/avinstallation, automatiska uppdateringar och en betrodd installationsupplevelse.

Förbereda paketkatalogen

Börja med att skapa ditt program i versionsläge för optimala prestanda:

cmake --build build --config Release

Skapa sedan en katalog med bara de filer som behövs för distribution och kopiera den körbara versionen:

mkdir dist
copy .\build\Release\cpp-app.exe .\dist\

Generera ett utvecklingscertifikat

MSIX-paket måste signeras. För lokal testning genererar du ett självsignerat utvecklingscertifikat:

winapp cert generate --if-exists skip

Tips/Råd

Certifikatets utfärdare ska matcha Publisher i din Package.appxmanifest. Kommandot cert generate läser detta automatiskt från manifestet.

Signera och packa

Nu kan du paketera och signera:

# package and sign the app with the generated certificate
winapp pack .\dist --cert .\devcert.pfx 

Tips/Råd

Kommandot pack använder automatiskt Package.appxmanifest från din aktuella katalog och kopierar den till målmappen före paketering. Den genererade .msix filen finns i den aktuella katalogen.

Installera certifikatet

Innan du kan installera MSIX-paketet måste du lita på utvecklingscertifikatet på datorn. Kör det här kommandot som administratör (du behöver bara göra det en gång per certifikat):

winapp cert install .\devcert.pfx

Installera och kör

Tips/Råd

Om du använde winapp run i steg 5 kanske paketet redan är registrerat i systemet. Använd winapp unregister först för att ta bort utvecklingsregistreringen och installera sedan versionspaketet.

Kommandot winapp pack genererar MSIX-filen i projektrotkatalogen. Installera paketet genom att dubbelklicka på den genererade .msix filen eller använda PowerShell:

Add-AppxPackage .\cpp-app_1.0.0.0_x64.msix

Tips/Råd

MSIX-filnamnet innehåller versionen och arkitekturen (t.ex. cpp-app_1.0.0.0_arm64.msix). Kontrollera katalogen för det exakta filnamnet.

Nu kan du köra appen var som helst i terminalen genom att skriva:

cpp-app

Du bör se utdata för "Package Family Name" som bekräftar att det är installerat och körs med rätt identitet.

Tips/Råd

Om du behöver packa om din app (t.ex. efter kodändringar), öka `Version` i din `Package.appxmanifest` innan du kör `winapp pack` igen. Windows kräver ett högre versionsnummer för att uppdatera ett installerat paket.

Tips

  1. När du är redo för distribution kan du signera MSIX med ett kodsigneringscertifikat från en certifikatutfärdare så att användarna inte behöver installera ett självsignerat certifikat.
  2. Tjänsten Betrodd Azure-signering är ett bra sätt att hantera dina certifikat på ett säkert sätt och integrera inloggning i CI/CD-pipelinen.
  3. Microsoft Store signerar MSIX åt dig, du behöver inte signera innan det skickas in.
  4. Du kan behöva skapa flera MSIX-paket, ett för varje arkitektur som du stöder (x64, Arm64). Konfigurera CMake med lämpliga generator- och arkitekturflaggor.

Nästa steg