C# with CNA.NET
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
| Layer | Namespaces | Responsibility |
|---|---|---|
CNA.XnaCompat | Microsoft.Xna.Framework, .Graphics, .Audio, .Content, .Input, .Input.Touch, .Media, .Storage, .GamerServices, .Net, .Design | Reproduces the XNA 4.0 public type system. Game code compiles against this assembly. |
CNA.Framework | CNA, CNA.Graphics, CNA.Input, CNA.Content, CNA.Audio, CNA.Media | Idiomatic managed API: value types in pure C#, native resources in SafeHandles, native failures turned into CnaException. |
CNA.Interop | CNA.Interop (internal) | All P/Invoke declarations and ABI structs, the native-library loader and the ABI admission check. |
| CNA C ABI | cna_* | 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
.exeis 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.
| Platform | What was actually run | Not covered yet |
|---|---|---|
| Linux x86_64 | Managed 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 desktop | renderers 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 threads | interactive browsers, hardware GPUs, audio, video, UDP networking; threaded WebGL is proxied and slow |
| Android | The sample set on the x86_64 Android emulator (API 35): drawing, touch, Back, pause and resume | physical devices, ARM runtime (arm64 packages build but did not run), audible audio |
| Windows, macOS | Build steps are documented; only compile-time ABI header checks ran in CI | everything 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 have | Start with |
|---|---|
| a new C# game | cna-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# game | a thin SDK-style wrapper project plus CNA.XnaCompat; see Migrating C# games to CNA.NET. |
| a question about how something behaves | the 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-toolsorandroidworkload (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), thenCNA_NATIVE_DIR, then next to the application or underruntimes/<rid>/native.CNA_NATIVE_DIAGNOSTICS=1adds 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,.ogaor.qoanext to the unchanged song.xnb. - Some native refusals still surface as
CNA.CnaExceptionrather than the exception type XNA throws; a few members are deliberately unsupported (for exampleGraphicsDevice.Presentwith 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
BinaryFormatteris 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.