Repository navigation
architecture
github-actions[bot] edited this page Oct 11, 2026
·
1 revision
This page describes how CHDMounter is put together for developers who want to understand, debug or extend the codebase.
| Project | Target | Purpose |
|---|---|---|
CHDMounter |
net10.0 (Windows/Linux/macOS) |
The cross-platform Avalonia application |
CHDMounter.Tests |
net10.0-windows |
xUnit unit and integration tests |
CHDMounter_Tester |
net10.0-windows |
WPF batch-parsing/benchmarking tool (developer only) |
The application consumes two external libraries: CHDSharp (CHD decoding, pulled in by the parser package) and VideoGameFileSystemParser 1.4.0 (console file system parsing and the console alias registry).
┌────────────────────────────────────────────────────────────────────┐
│ Avalonia UI (CHDMounter/Views) │
│ MainWindow · SettingsWindow · ConsoleSelectionWindow · AboutWindow│
│ MessageDialog · Dialogs │
└───────────────┬────────────────────────────────────────────────────┘
│ service locator (ServiceProvider)
┌───────────────▼────────────────────────────────────────────────────┐
│ Services (CHDMounter/Services) │
│ ILoggingService/LoggingService ISettingsService/Settings │
│ IMountService/MountService ──► Dokan · WinFsp · FUSE backends │
│ IScreenshotService/ScreenshotService │
│ StatsClient · UpdateChecker · BugReportClient │
└───────────────┬────────────────────────────────────────────────────┘
│ parsed volume (ChdContainer from VideoGameFileSystemParser)
┌───────────────▼────────────────────────────────────────────────────┐
│ Mount backends (CHDMounter/Mounting) │
│ Dokan → ChdFs : IDokanOperations │
│ WinFsp → ChdFs : FileSystemBase │
│ FUSE → ChdFuseVolume : IFuseVolume + FuseSharp interop │
└────────────────────────────────────────────────────────────────────┘
-
Program.Mainbuilds the Avalonia application (AppBuilder.Configure<App>()). -
App.OnFrameworkInitializationCompletedcallsInitializeApplication:-
DiagnosticLogger.Initialize()configures Serilog (file + debug sinks) and enables the bug report sink. -
ServiceProviderregisters the logging, settings, mount and screenshot services. -
Console.Out/Console.Errorare redirected throughLogTextWriterso console output is mirrored into the UI log and Serilog. -
ErrorLoggerinstalls global handlers for unhandled and unobserved exceptions. -
StatsClient.SendStats()andUpdateChecker.CheckForUpdates()run in the background.
-
-
MainWindowopens;Openedhandles command-line arguments and starts polling the update result to prompt the user when a newer release exists.
| Service | Implementation | Responsibility |
|---|---|---|
ILoggingService |
LoggingService |
Thread-safe UI log collection (bounded at 5000 entries) + Serilog writes |
ISettingsService |
SettingsService |
Load/save AppSettings (DPAPI on Windows, JSON elsewhere) |
IMountService |
MountService |
Routes mount/unmount to the selected backend and owns backend lifetime |
IScreenshotService |
ScreenshotService |
F8 capture of the active window (Avalonia) |
ServiceProvider is a small static service locator used as the composition root. Interfaces live
in CHDMounter/Interfaces, models in CHDMounter/Models.
-
MountServiceresolves the backend from settings (Dokan,WinFsporFUSE; FUSE is forced on Linux/macOS). - The backend opens the CHD file with
ChdContainer, parses the selected console/format and computes mount-point candidates (drive letters or folders, with suffixed fallbacks). - The backend adapts the parsed container to its driver interface:
-
Dokan —
ChdFsimplementsIDokanOperations(path lookup, file reads, directory enumeration, read-only volume information). -
WinFsp —
ChdFsextendsFileSystemBase(stable file indexes, permissive DACL for cross-integrity folder mounts when elevated). -
FUSE —
ChdFuseVolumeimplementsIFuseVolume;FuseMountServiceruns the blocking FUSE session on a dedicated background thread and stops it throughFuseFileSystem.Exit().
-
Dokan —
-
MountPathHelpershares folder-name sanitization, candidate generation and volume creation time across the folder-based backends.
Guidance dialogs ("driver not installed") are posted to the UI thread without blocking the
mount worker (Dialogs.ConfirmLater) so mount locks are never held while waiting for the UI.
application code ──► Serilog.Log ──► file sink (debug_*.log)
├─► debug sink (IDE output)
└─► BugReportSink ──► BugReportClient ──► bug report API
console output ────► LogTextWriter ──► ILoggingService (UI pane) + Serilog
unhandled errors ──► ErrorLogger ──► Serilog
- Log files roll daily and are pruned after 7 days on startup.
-
BugReportSinkforwards Warning+ events; user/environment errors are logged below Warning so they never become bug reports (see Privacy).
| Client | Endpoint | Behaviour |
|---|---|---|
StatsClient |
ApplicationStats/stats |
Once per process; fire-and-forget; failures logged at Information |
UpdateChecker |
GitHub Releases API | Runs once per process; result polled by the UI; failures logged at Information |
BugReportClient |
bugreport/api/send-bug-report |
Queued (one at a time, ~6 s spacing); fail-closed in tests; test hosts excluded |
- UI work runs on the Avalonia dispatcher; dialogs are marshaled to it.
- Mount/unmount operations run on background tasks (
Task.Run) so the UI stays responsive. - The FUSE session blocks by design and therefore owns a dedicated background thread; the mount
service waits for the FUSE
initcallback (30 s timeout) before reporting success. -
LoggingServiceposts collection updates to the UI thread and bounds the log at 5000 entries.
CHDMounter/
App.axaml(.cs) Application lifecycle and composition root
Program.cs Entry point
FuseSharp/ Bundled FUSE 3 interop (resolver, session, availability)
Interfaces/ Service and FUSE contracts
Logging/ Serilog setup, sinks, console writer, error handlers
Models/ Settings, log entry, mount backend, update result
Mounting/ Mount router + Dokan/WinFsp/FUSE backends, shared path helper
Services/ Logging, settings, mounting, screenshots, stats, updates, bug reports
Themes/ Dark theme resources
Views/ Windows, dialogs and code-behind