C# with CNA.NET

CNA snapshot b0e97bb1

ⓘ

In one sentence: CNA.NET is a thin managed layer that gives C# games the Microsoft.Xna.Framework API on top of CNA’s native C++ runtime, through CNA’s C ABI. It is not a second engine written in C#: every frame is drawn, mixed and timed by the same C++ code that C++ games use.

What CNA.NET is

CNA is implemented in C++23. Its C ABI exposes that implementation to other languages, and CNA.NET (repository libcna/cna-cs) is the actively developed binding built on it. Its primary goal is XNA 4.0 source compatibility: an existing XNA 4.0 C# game is rebuilt from its original .cs files and its original .xnb content, usually without editing the game’s own source. Engine adaptation lives in a small SDK-style project file and the platform host, not in the game code.

For an XNA 4.0 C# codebase this makes CNA.NET another source-compatible migration and runtime route, next to established projects such as MonoGame and FNA, backed by CNA’s native C++ runtime. What it adds is the native C++ core shared with C++ and C programs, the renderer abstraction underneath, direct consumption of XNA-built .xnb content, a WebAssembly route and an Android route, and an unusually large qualification effort against the original Microsoft XNA samples.

Architecture: one native core, one managed facade

C# XNA 4.0 game (unchanged .cs files)
        ↓
CNA.XnaCompat      Microsoft.Xna.Framework.* public facade
        ↓
CNA.Framework      idiomatic CNA.* managed API (SafeHandle-owned resources)
        ↓
CNA.Interop        internal P/Invoke boundary (1,419 source-generated imports)
        ↓
CNA C ABI          libcna_c_api (cna_* functions, ABI 0.44.0)
        ↓
CNA C++            the same runtime C++ games link
LayerNamespacesResponsibility
CNA.XnaCompatMicrosoft.Xna.Framework, .Graphics, .Audio, .Content, .Input, .Input.Touch, .Media, .Storage, .GamerServices, .Net, .DesignReproduces the XNA 4.0 public type system. Game code compiles against this assembly.
CNA.FrameworkCNA, CNA.Graphics, CNA.Input, CNA.Content, CNA.Audio, CNA.MediaIdiomatic managed API: value types in pure C#, native resources in SafeHandles, native failures turned into CnaException.
CNA.InteropCNA.Interop (internal)All P/Invoke declarations and ABI structs, the native-library loader and the ABI admission check.
CNA C ABIcna_*Owned by CNA itself (modules/c-api); CNA.NET only consumes it.

Optional assemblies cover what XNA games often used beside XNA itself: CNA.PhoneCompat (Microsoft.Devices and sensors from Windows Phone), a small System.Windows.Forms subset, isolated storage for the browser runtime, and Roslyn source generators. The multi-language 3D demo shows the layering from the outside: one small 3D game written in C++ against CNA’s C++ API, in C99 against the C ABI, and in C# as a single StarfieldGame.cs that builds unchanged against either CNA.NET or FNA (chosen in MSBuild only). All three drive the same native runtime; the C# one adds a facade, not an engine.

Source compatibility, not binary compatibility

  • Source: the primary contract. Game source written against XNA 4.0 compiles against CNA.XnaCompat. The public metadata matches the selected XNA 4.0 Windows runtime profile exactly (256 of 256 types, plus 75 of 75 GamerServices, Avatar and Net types), as measured by CNA.NET’s own API comparison tool.
  • Behaviour: XNA 4.0 behaviour is the compatibility contract, measured by a behaviour corpus and by running real games. CNA.NET describes itself as not yet behaviourally complete; known differences are listed in its docs/native-behavior-blockers.md.
  • Binaries: not a goal. CNA.NET ships XNA-named forwarding assemblies (version 4.0.0.0) without Microsoft’s public key, so prebuilt pure-IL libraries compiled against XNA can load, but CNA.NET does not take Microsoft’s assembly identity and a game’s own .exe is never run as a binary.

Status and evidence

CNA.NET is beta and source-first (revision 860f92c, 4 October 2026). There are no published NuGet packages or prebuilt native libraries yet; you build CNA’s C ABI and CNA.NET from source. Each CNA.NET revision admits exactly one reviewed C ABI version, currently 0.44.0 — the version CNA exports at this documentation snapshot, so the two are a matched pair. A different CNA build is refused when the library loads, with a diagnostic naming both versions.

PlatformWhat was actually runNot covered yet
Linux x86_64Managed and native test suites (1,261 tests per configuration, Debug and Release), the Microsoft sample set and dozens of real games; on private X or Wayland displays (Xvfb, or a headless compositor on the real GPU), not the interactive desktoprenderers outside the tested matrix
Browser (WebAssembly)A plain Microsoft.NET.Sdk.WebAssembly project with CNA statically linked, driven by requestAnimationFrame; the sample set in headless Chromium with SwiftShader WebGL 2; threaded builds for games that start threadsinteractive browsers, hardware GPUs, audio, video, UDP networking; threaded WebGL is proxied and slow
AndroidThe sample set on the x86_64 Android emulator (API 35): drawing, touch, Back, pause and resumephysical devices, ARM runtime (arm64 packages build but did not run), audible audio
Windows, macOSBuild steps are documented; only compile-time ABI header checks ran in CIeverything at run time — future qualification work
iOS—planned (static linking), not started

These are local measurements recorded in CNA.NET’s campaign ledgers (CSX-001 to CSX-155, closed on 4 October 2026), not continuous-integration results; nothing was re-run for this page. CNA’s own campaign handoff says it plainly: this is not a claim of 100% compatibility with every game.

Original XNA samples, unchanged, on CNA.NET

cna-cs-samples is not a port. It keeps the original C# source of Microsoft’s XNA 4.0 samples byte-for-byte and adds only a wrapper project and host per sample. At its revision 1e6d763:

  • 83 Microsoft XNA 4.0 sample projects (84 programs) are built from upstream C# source that a checker compares with the original archive (scripts/check-verbatim.sh: 84 checked, 0 failures), using the original XNA-built content (2,138 files identical).
  • All 84 build in Debug and Release and run on Linux; all 84 run single-threaded in headless Chromium; all 84 draw on the x86_64 Android emulator.
  • 83 of the 91 completed C++ sample ports also run this way from their original C#; 26 of the 84 programs were compared pixel for pixel with the C++ port and match, and four were compared with frames from the real XNA runtime.
  • Beyond Microsoft’s samples, 95 external XNA projects — books’ examples, open-source and commercial games such as Speedy Blupi — were investigated by compiling their unchanged game source; most run on Linux, and the ones that stop do so on non-XNA causes that are recorded per project.

Microsoft’s Racing Game Kit is the hardest case: from unchanged C# source it builds without warnings and races on Linux, but in headless Chromium and on the emulator it so far reaches only its attract mode.

How this relates to the C++ samples

The two sample collections answer different questions. cna-samples ports the same XNA samples to C++ against CNA’s C++ API (91 complete; 90 of them, plus one partial, are playable in the browser); cna-cs-samples runs the original C# against the same runtime through CNA.NET. Comparing the two is how a defect is placed in the right layer: a difference that also appears in the C++ port is a native CNA issue; one that does not is a binding issue.

Three ways in

You haveStart with
a new C# gamecna-cs-template: dotnet new install it, then dotnet new cna-game. One shared game source with a desktop project and browser and Android heads; see Tutorial 171.
an existing XNA 4.0, FNA or MonoGame C# gamea thin SDK-style wrapper project plus CNA.XnaCompat; see Migrating C# games to CNA.NET.
a question about how something behavesthe reference programs in cna-cs-samples, and the matching C++ port in cna-samples.

Requirements at a glance

  • Desktop: .NET 8 SDK or later (the source generators need SDK 8.0.4xx); a C++23 compiler, CMake 3.20 or newer and the CNA source tree with its sibling checkouts, to build cna_c_api.
  • Browser and Android heads: .NET 11 with the wasm-tools or android workload (the campaign used .NET 11 RC1); the native staging scripts are Linux-only (WSL 2 on Windows).
  • Native library lookup: CNA_NATIVE_LIBRARY (an absolute path, fail-fast), then CNA_NATIVE_DIR, then next to the application or under runtimes/<rid>/native. CNA_NATIVE_DIAGNOSTICS=1 adds loader detail.

Known limitations

  • No releases yet; builds come from source, and every CNA.NET revision pairs with exactly one C ABI version.
  • XNA 4.0 is the contract: MonoGame- or FNA-specific extensions are not implemented, and the XNA Content Pipeline (build-time assemblies) is not provided — use the original XNA-built content, or rebuild it with XNA 4.0’s own tools.
  • XNA songs are WMA, which CNA does not decode; place an .ogg, .oga or .qoa next to the unchanged song .xnb.
  • Some native refusals still surface as CNA.CnaException rather than the exception type XNA throws; a few members are deliberately unsupported (for example GraphicsDevice.Present with non-default arguments).
  • Host APIs outside XNA are not supplied: Win32 P/Invoke, WPF, full Windows Forms, Silverlight and retired online services.
  • For compatibility, the XNA-era BinaryFormatter is enabled by default for applications that need it; use it with trusted legacy data only, and opt out with <CnaBinaryFormatter>false</CnaBinaryFormatter>.

See also: the C ABI and language bindings, XNA compatibility, porting C# to C++ when you want a native C++ game instead.