20 Eylül 2026 Pazar

Publishing MonoGame Desktop Games to Microsoft Store: The Complete MSIX & WAP Guide




Publishing MonoGame Desktop Games to Microsoft Store: The Complete MSIX & WAP Guide

Bringing an indie game to the Microsoft Store on Windows 10 and Windows 11 gives developers direct access to hundreds of millions of PC players, seamless updates, Windows Game Bar integration, and containerized installation safety. However, if your game is built with MonoGame (.NET 8.0 or .NET 9.0 WindowsDX), getting it into the store presents a unique architectural challenge: bridging a standard Win32 desktop executable (.exe) with the modern MSIX / AppX application model.

At Arar Games, we have walked this road from initial compilation to live store distribution with titles like Paint Trek and Blocked: Pixel Panzer. In this battle-tested guide, we break down the end-to-end technical pipeline: configuring your projects, navigating Visual Studio's Publish options, mastering the Package.appxmanifest, scaling visual tile assets, resolving Windows App Certification Kit (WACK) errors, and submitting your production bundle to the Microsoft Partner Center.


1. Architectural Foundation: Win32 vs. MSIX

Traditional MonoGame games compile into a standard Win32 executable accompanied by framework runtime .dll files and a Content/ directory containing compiled binary assets (.xnb textures, .ogg audio, sprite sheets, and compiled HLSL shaders).

While Microsoft Store supports distributing loose unpackaged Win32 executables, wrapping your game inside a Windows Application Packaging (WAP) project to produce an MSIX bundle provides substantial technical and operational benefits:

flowchart TD
    subgraph "Game Codebase"
        Shared["Shared Library\n(Entities, Systems, Game State, Math)"]
        Desktop["Desktop Project (.NET 9.0 WindowsDX)\n(Win32 Executable Entry Point)"]
        Shared --> Desktop
    end

    subgraph "Packaging Layer (WAP Project)"
        WAP["Windows App Packaging (.wapproj)\n(Microsoft Desktop Bridge)"]
        Manifest["Package.appxmanifest\n(Identity, Capabilities, Tile Assets)"]
        StoreAssoc["Package.StoreAssociation.xml\n(Partner Center Binding)"]
        Desktop --> WAP
        Manifest --> WAP
        StoreAssoc --> WAP
    end

    subgraph "Output & Distribution"
        WAP -->|Create App Packages| Sideload["Sideloading Package\n(*.appxbundle + Add-AppDevPackage.ps1)"]
        WAP -->|Store Upload Mode| UploadBundle["Store Upload Bundle\n(*_bundle.appxupload / *.msixupload)"]
        UploadBundle --> MSStore["Microsoft Partner Center\n(Live Store Ingestion)"]
    end

Why Wrap MonoGame in a WAP Project?

  1. Isolated Containerized Lifecycle: MSIX applications run in an isolated environment. Files, virtualized registry entries, and runtime states are cleanly removed upon uninstallation, leaving zero system clutter.
  2. Dynamic Architecture & Asset Streaming: A single .appxupload bundle packages x86 and x64 binaries together with multiple DPI scale packs (scale-100 through scale-400). Windows Store delivers only the required architecture and screen assets for each player's device, significantly reducing download sizes.
  3. Automated Crash Telemetry: Visual Studio packages your debugging symbols (.appxsym) into the upload bundle. If your game encounters an unhandled exception on a player's machine, the Microsoft Partner Center analytics dashboard displays the exact stack trace with function names and line numbers.

2. Project Hierarchy & Configuration

A clean MonoGame solution should maintain strict separation between platform-agnostic game logic and platform packaging:

SolutionDir/
│
├── YourGame.Shared/               # Core game mechanics, systems, levels, entities
│   └── YourGame.Shared.csproj
│
├── YourGame.Desktop/              # Main desktop entry point (WinExe)
│   ├── Content/                   # MonoGame Content Pipeline assets (.mgcb -> .xnb)
│   ├── Program.cs
│   └── YourGame.Desktop.csproj
│
└── YourGame.Package/              # Windows App Packaging Project (.wapproj)
    ├── Images/                    # Scaled logos, tiles, splash screen
    ├── Package.appxmanifest       # Identity, capabilities, visual elements
    ├── Package.StoreAssociation.xml
    └── YourGame.Package.wapproj

Step 1: Main Game Project Configuration (.csproj)

Ensure your desktop project is configured for multi-architecture building:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net9.0-windows</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
    <Platforms>AnyCPU;x64;x86</Platforms>
  </PropertyGroup>

  <!-- Ensure game content is copied during packaging -->
  <ItemGroup>
    <Content Include="Content\**\*.*">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="MonoGame.Framework.WindowsDX" Version="3.8.*" />
    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
  </ItemGroup>
</Project>

Step 2: Multi-Platform NuGet Restoration

Before compiling a multi-architecture bundle, restore packages explicitly for both 64-bit and 32-bit runtimes:

dotnet restore YourGame.Desktop.csproj -r win-x64
dotnet restore YourGame.Desktop.csproj -r win-x86

3. Demystifying Visual Studio's Publish Menu

When you right-click your Windows Application Packaging project in Visual Studio and expand the Publish submenu, you are presented with three distinct options:

graph TD
    Menu["Right Click WAP Project > Publish"]
    Menu --> Opt1["1. Associate App with the Store..."]
    Menu --> Opt2["2. Convert Content Group Map File"]
    Menu --> Opt3["3. Create App Packages... (Primary Workflow)"]
    
    Opt1 --> Sync["Synchronizes Cloud App Identity with Local Manifest\n(Generates Package.StoreAssociation.xml)"]
    Opt2 --> Streaming["Streaming Install Asset Conversion\n(For massive games with staged downloads)"]
    Opt3 --> Wizards["Package Wizard:\n- Sideloading (Local QA Testing)\n- Microsoft Store Upload (_bundle.appxupload)"]

1. Associate App with the Store...

  • Purpose: Connects your local Visual Studio solution with your Microsoft Partner Center developer account.
  • What It Does: You sign in with your developer credentials and select your reserved app name. Visual Studio queries the Partner Center API, retrieves your official Publisher ID, Package Name, Publisher Display Name, and Package Family Name (PFN), and generates Package.StoreAssociation.xml.
  • Why It Matters: Without this association, your package will be signed with a temporary local certificate that Microsoft Partner Center will immediately reject upon upload due to identity mismatches.

2. Convert Content Group Map File

  • Purpose: Supports Microsoft's Streaming Installation architecture.
  • What It Does: In massive games (e.g., 50+ GB AAA titles), streaming install allows users to launch the first level while subsequent game content downloads in the background. Developers write a SourceAppxContentGroupMap.xml (which supports wildcards), and this menu command transforms it into the final AppxContentGroupMap.xml required by the Windows packaging pipeline.
  • Relevance for Indie Titles: For standard indie games (under a few gigabytes), streaming installation is unnecessary. You can safely ignore this option.

3. Create App Packages... (The Main Production Wizard)

This is the core tool you will use to build, sign, and package your game for QA testing and store submission.


4. Configuring the Package Creation Wizard

When you click Publish \(\rightarrow\) Create App Packages..., follow this exact production workflow:

Step 1: Select Distribution Method

  • For Store Submission: Select "Microsoft Store under a new or existing app name". This links the build to your verified cloud identity and optimizes the archive for Microsoft Store signing.
  • For Local QA / Sideloading: Select "Sideloading". This creates a .msixbundle or .appxbundle signed with a generated test certificate (.cer) along with installation scripts (Add-AppDevPackage.ps1), allowing you to test on other PCs without publishing.

Step 2: Select and Configure Packages

On the configuration screen, adjust the parameters:

┌─────────────────────────────────────────────────────────────┐
│ Output location: .\AppPackages\                             │
│ Version: 1.0.0.0      [☑ Automatically increment]           │
│                                                             │
│ Generate app bundle: Always                                 │
│                                                             │
│ Architectures:                                              │
│   ☑ x86       Configuration: Release (x86)                  │
│   ☑ x64       Configuration: Release (x64)                  │
│   ☐ ARM       (Not recommended for desktop Win32 games)     │
│   ☐ ARM64     (Not recommended for desktop Win32 games)     │
│                                                             │
│ Options:                                                    │
│   ☑ Include public symbol files                             │
│   ☑ Generate artifacts to validate app with WACK            │
└─────────────────────────────────────────────────────────────┘

Understanding Version Numbering:

Windows packaging follows standard Semantic Versioning: Major.Minor.Build.Revision.

  • Initial release starts at 1.0.0.0.
  • Minor patches increment revision (1.0.1.0), while major releases increment the minor or major digits (1.1.0.0, 2.0.0.0).
  • The Absolute Store Rule: Every new package uploaded to Microsoft Partner Center must have a higher version number than the currently active package.
  • Automatically increment: Keeping this checked increments the Revision digit with every build, preventing accidental upload rejections due to duplicate version numbers.

Why x64 + x86 with Generate app bundle: Always?

  • x64: Targets modern 64-bit Windows installations (98%+ of desktop PC gamers).
  • x86: Provides fallback compatibility for older 32-bit hardware.
  • Always Bundle: Visual Studio bundles both architectures into a single archive (_bundle.appxupload). Players only download the specific binary for their processor architecture.

5. Mastering Package.appxmanifest

The manifest defines runtime requirements, visual assets, display orientation, and permissions:

<?xml version="1.0" encoding="utf-8"?>
<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap rescap">

  <Identity
    Name="YourPublisher.YourGame"
    Publisher="CN=YOUR-OFFICIAL-PUBLISHER-ID"
    Version="1.0.0.0" />

  <Properties>
    <DisplayName>Your Game Title</DisplayName>
    <PublisherDisplayName>Your Studio Name</PublisherDisplayName>
    <Logo>Images\StoreLogo.png</Logo>
  </Properties>

  <Dependencies>
    <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
    <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.26100.0" />
  </Dependencies>

  <Applications>
    <Application Id="App"
      Executable="$targetnametoken$.exe"
      EntryPoint="$targetentrypoint$">
      <uap:VisualElements
        DisplayName="Your Game Title"
        Description="An action-packed 2D arcade shooter built with MonoGame."
        BackgroundColor="transparent"
        Square150x150Logo="Images\Square150x150Logo.png"
        Square44x44Logo="Images\Square44x44Logo.png">
        <uap:DefaultTile 
          Wide310x150Logo="Images\Wide310x150Logo.png"  
          Square71x71Logo="Images\SmallTile.png" 
          Square310x310Logo="Images\LargeTile.png" />
        <uap:SplashScreen Image="Images\SplashScreen.png" />
        <uap:LockScreen BadgeLogo="Images\BadgeLogo.png" Notification="badgeAndTileText"/>
        <uap:InitialRotationPreference>
          <uap:Rotation Preference="landscape"/>
        </uap:InitialRotationPreference>
      </uap:VisualElements>
    </Application>
  </Applications>

  <Capabilities>
    <Capability Name="internetClient" />
    <rescap:Capability Name="runFullTrust" />
  </Capabilities>
</Package>

Essential Settings:

  1. <rescap:Capability Name="runFullTrust" />: Because MonoGame relies on DirectX 11, unmanaged hardware drivers, and raw Win32 message handling via SharpDX or SDL, it cannot execute inside a sandbox app-container. runFullTrust grants desktop privileges while retaining containerized file safety.
  2. InitialRotationPreference set to landscape: Windows gaming handhelds (e.g., ASUS ROG Ally, Lenovo Legion Go, GPD Win) run portrait-native displays with hardware rotation. Explicitly setting landscape prevents the game from opening sideways or flipped.

6. The Visual Asset Scaling Grid & The BadgeLogo Trap

Windows displays application icons across varying desktop DPI settings (scale-100, scale-125, scale-150, scale-200, scale-400). Missing scale variations cause blurry rendering or validation warnings.

Asset Type Base Size (scale-100) scale-200 scale-400 Purpose
Square44x44Logo 44 x 44 px 88 x 88 px 176 x 176 px Taskbar and Start app list
Square150x150Logo 150 x 150 px 300 x 300 px 600 x 600 px Medium Start Menu tile
Wide310x150Logo 310 x 150 px 620 x 300 px 1240 x 600 px Wide Start Menu tile
LargeTile 310 x 310 px 620 x 620 px 1240 x 1240 px Large Start Menu tile
SmallTile 71 x 71 px 142 x 142 px 284 x 284 px Small Start Menu tile
SplashScreen 620 x 300 px 1240 x 600 px 2480 x 1200 px Initial launch window banner
StoreLogo 50 x 50 px 100 x 100 px 200 x 200 px Store catalog tile
BadgeLogo 24 x 24 px 48 x 48 px 96 x 96 px Lock screen notification badge

Warning

The Monochrome BadgeLogo Requirement: The lock screen badge (BadgeLogo) must consist strictly of pure white (#FFFFFF) pixels and alpha transparency. If you include colored pixels or gradients in your BadgeLogo assets, Windows App Certification Kit (WACK) will flag a contrast violation and fail certification.


7. Package Verification: WACK & Troubleshooting

Once Visual Studio finishes building, the Finished creating package screen appears:

Output location: [Your Solution Dir]\AppPackages\
Package that will be validated: ...\YourApp_1.0.0.0_x86_x64.appxbundle

Common Obstacle: "The tool AppCert.exe wasn't found"

Clicking Launch Windows App Certification Kit might trigger this error:

Microsoft Visual Studio:
The tool AppCert.exe wasn't found. Please ensure that the most recent 
installation of the Windows Software Development Kit includes the 
Windows App Certification Kit feature.

Why This Occurs & How to Resolve It:

  • Visual Studio's default workload installation sometimes omits the standalone WACK binary.
  • Resolution: Open Visual Studio Installer \(\rightarrow\) Modify \(\rightarrow\) Navigate to Individual components \(\rightarrow\) Search for "Windows App Certification Kit" \(\rightarrow\) Check the box and complete the installation.
  • Alternative: Running WACK locally is optional. If your manifest and assets are properly configured, you can proceed directly to uploading your package to Microsoft Partner Center. Microsoft's cloud ingestion pipeline runs comprehensive automated certification tests automatically upon submission.

The MonoGame "Blocked Executable" False Positive

When running WACK against a MonoGame application, you might observe a warning listing compiled texture files (.xnb) or audio streams (.ogg) as potential unverified executables.

Why does this happen? Compressed binary data inside .xnb or .ogg files can coincidentally match byte patterns of portable executable (PE) headers. As long as these files reside strictly inside your game's Content/ directory and are not executed via system calls, Microsoft's certification team acknowledges them as static game assets and approves the submission without issue.


8. Sideloading: Testing Before Store Submission

Before submitting to the store, verify your packaged build on a clean machine:

  1. Locate the test output folder:
    AppPackages/YourGame_1.0.0.0_Test/
    
  2. In this folder, you will find:
    • YourGame_1.0.0.0_x86_x64.appxbundle (or .msixbundle)
    • YourGame_1.0.0.0_x86_x64.cer (Local test signing certificate)
    • Add-AppDevPackage.ps1 (PowerShell installer)
  3. Right-click PowerShell and select Run as Administrator, then execute:
    Set-ExecutionPolicy RemoteSigned -Scope Process
    .\Add-AppDevPackage.ps1
    
  4. Follow the interactive prompts to trust the development certificate and install the app.
  5. Launch the game directly from the Windows Start Menu to confirm that gamepad controls, high-DPI scaling, audio playback, and graphics rendering perform smoothly in the containerized environment.

9. Microsoft Partner Center Submission Checklist

With your verified _bundle.appxupload file ready, log in to Microsoft Partner Center:

Dashboard > Apps & Games > [Your Game Title] > Start submission

1. Pricing and Availability

  • Markets: Select All worldwide markets (240 territories).
  • Base Price: Set your price in USD (e.g., $0.99 or Free). Microsoft automatically converts regional prices into local currencies.

2. Properties & Privacy Policy

  • Category: Set to Games \(\rightarrow\) Select up to 3 relevant subgenres (e.g., Action + adventure, Shooter, Arcade).
  • Privacy Policy URL: Because the manifest declares <Capability Name="internetClient" />, Microsoft mandates an active privacy policy URL (a GitHub repository page or website link is sufficient).
  • Game Settings: Check Single player \(\rightarrow\) PC.

3. Age Ratings (IARC Questionnaire)

  • Complete the International Age Rating Coalition (IARC) questionnaire.
  • Accurately declare that your arcade game does not feature graphic gore, profanity, or real-money gambling. Arcade titles like Paint Trek or Blocked typically receive an Everyone / PEGI 3 rating immediately.

4. Store Listings & ASO (App Store Optimization)

  • Description: Detail your game mechanics, weapon systems, level progression, and controller support.
  • Screenshots: Upload 1920x1080 (16:9) PC screenshots showing actual gameplay. Ensure your desktop screenshots do not show mobile on-screen touch joysticks!
  • Keywords: Add relevant search tags (e.g., monogame, pixel, arcade, retro, shooter).

5. Package Upload & Ingestion

  • Navigate to Packages and drag-and-drop your ..._bundle.appxupload file.
  • Partner Center will parse the archive, verify x86 and x64 architectures, extract symbol files, and confirm capabilities.
  • Once all sections display green checkmarks, click Submit to the Store. Certification typically completes within 24 to 72 hours.

10. Automation: Headless MSBuild Pipeline

For automated CI/CD pipelines (GitHub Actions, Azure DevOps, or local automation scripts), you can compile your WAP project directly via MSBuild without opening Visual Studio:

msbuild YourGame.Package\YourGame.Package.wapproj `
  /p:Configuration=Release `
  /p:Platform=x64 `
  /p:AppxBundlePlatforms="x86|x64" `
  /p:AppxBundle=Always `
  /p:UapAppxPackageBuildMode=StoreUpload `
  /p:AppxPackageDir=".\AppPackages\"

Combining this command with the Microsoft Store Submission API allows you to push game updates directly to the store upon tagging a new release in Git.


Conclusion

Publishing a MonoGame desktop application to the Microsoft Store does not require refactoring your codebase for UWP or compromising on .NET 9 performance. By encapsulating your desktop build within a Windows Application Packaging (WAP) project, configuring runFullTrust, standardizing your asset scale grid, and packaging hybrid x86|x64 bundles, you gain a modern, trusted presence on Windows 10 and Windows 11.

With this pipeline in place, you can focus on what matters most: delivering fantastic gameplay experiences to PC gamers across the globe!




Hiç yorum yok:

Yorum Gönder