-
Notifications
You must be signed in to change notification settings - Fork 4
04 architecture
Layers, dependency injection, startup/shutdown lifecycle, host-interface pattern, MVVM. Related: 02 — Projects & Solution · 05 — Configuration
flowchart TB
subgraph App [SimpleLauncher — WPF app]
V[Windows / Pages / Views]
VM[ViewModels]
US[UI services & orchestrators]
LH[Launch handlers / scanners / RA]
DI[App.xaml.cs — DI composition root]
end
subgraph Core [SimpleLauncher.Core]
S[Services]
M[Models]
I[Interfaces]
end
subgraph Infra [Infrastructure]
OS[Emulators, Dokan, CHDMounter, PowerShell, 7za, chdman…]
HTTP[RetroAchievements / ParameterResolver / Stats / GitHub APIs]
FS[system.xml, settings.xml, *.dat, tools\\ payloads]
end
V --> VM --> US
US --> S
LH --> S
DI --> V & VM & US & LH
S --> Infra
S --> I
I --> US & LH
The rule of thumb: Core knows nothing about WPF windows — it exposes services and interfaces; the app implements host interfaces and binds them via Initialize(host).
-
Composition root:
SimpleLauncher\App.xaml.cs. Config is built first (ConfigurationBuilder().AddJsonFile("appsettings.json"),App.xaml.cs:108-112), then ~200 registrations, thenBuildServiceProvider(ValidateOnBuild = true)(App.xaml.cs:491). -
Access pattern:
App.ServiceProvideris a public staticIServiceProvider(App.xaml.cs:89); windows/VMs resolve on demand withApp.ServiceProvider.GetRequiredService<T>()(e.g.MainWindow.xaml.cs:319,EasyModeWindowatMainWindow.xaml.cs:416).
| Group | Lines | Examples |
|---|---|---|
HTTP clients (named, via AddHttpClient) |
141–201 |
LogErrorsClient, StatsClient, UpdateCheckerClient, SupportWindowClient, RetroAchievementsClient (30 s), GameImageClient (20 s), EasyModeClient, GameClassificationClient (30 s), ParameterResolverClient (60 s), DownloadClient (Polly: 5 retries, 5-min handler lifetime) |
| Managers & infrastructure (singleton) | 204–259 |
IConfiguration, IMemoryCache, Serilog ILogger, ICredentialProtector→WindowsCredentialProtector, SettingsManagerService (factory + Load()), CheckForUpdatesService, QuitSimpleLauncher, ReinstallSimpleLauncher, GameLauncherService, IExtractionService, mount services, FavoritesManager/PlayHistoryManager/RetroAchievementsManager (factories) |
| Game platform scanners (singleton) | 261–274 | 11 × IGamePlatformScanner + GameScannerService + ISteamVdfParser, IIconExtractor
|
| UI services (singleton) | 275–303 |
ThemeMenuService, LanguageMenuService, LoadingOverlayService, StartupInitializationService, GameListUiService, GameFileWatcherService, MenuActionHandlerService, IUpdateStatusBar, IMenuCheckMarkService, IUiResetService, IFindCoverImageService, IImageLoader→WpfImageLoader… |
| WPF platform + orchestrators (singleton) | 306–356 |
IMessageDialogService, IResourceProvider, IDispatcherService, IFilePickerService, IApplicationLifetime, IMessageBoxLibraryService, IParameterResolverService, IUiOrchestrator, IGameItemRenderService, IRetroAchievementsHasherTool, ISystemSelectionOrchestrator, IGameFileLoadingOrchestrator, IDiscConverter, IAudioInputService, IApplicationLifecycleService, IMenuOrchestrator, IGameBrowserService, hotkey + screenshot services |
| Emulator config handlers (singleton) | 445–465 | 21 × IEmulatorConfigHandler (Ares…Yumir) |
| Launch strategies (singleton) | 468–475 | 8 × ILaunchStrategy (Default, DOSBox, CommanderGenius, ChdToCue, ChdMount, PbpToCue, XisoMount, ZipMount) |
| Transient | 229, 359–397, 400–442 |
DownloadManager; 44 ViewModels (incl. 21 Inject*ConfigViewModel); 43 windows (incl. MainWindow, EasyModeWindow, 21 Inject*ConfigWindow) |
Plain services are not given a window reference in the constructor. Instead:
service.Initialize(host); // host = the MainWindow (or an orchestrator) implementing the host interfaceExamples (all interfaces in SimpleLauncher\Interfaces\):
| Interface | Implemented by | Consumed by |
|---|---|---|
IUiOrchestratorHost |
MainWindow |
UiOrchestratorService (which also implements ILoadingOverlayHost/IGameListUiHost proxies) |
IMenuCheckMarkHost |
MainWindow (partial MenuCheckMarkHost.cs) |
MenuCheckMarkService |
IUiResetHost |
MainWindow | UiResetService |
IStatusBarHost |
MainWindow | UpdateStatusBarService |
IStartupInitializationHost |
MainWindow | StartupInitializationService |
IThemeMenuHost / ILanguageMenuHost
|
MainWindow |
ThemeMenuService / LanguageMenuService
|
IGameFileLoadingHost, IGameItemRenderHost, ISystemSelectionHost, IMenuActionHost, IMenuOrchestratorHost
|
MainWindow partials | loading/render/system-selection/menu orchestrators |
IWindowContext |
WpfWindowContext (ad-hoc via WpfWindowContext.FromMainWindow(window), not DI-registered) |
GameLauncherService |
MainWindow implements 10 host interfaces and is wired in its constructor (MainWindow.xaml.cs:252-256): UiOrchestratorService.Initialize(this), _gameBrowser.Initialize(this, this, this), _menuOrchestrator.Initialize(...), UiResetService.Initialize(this), UpdateStatusBarService.Initialize(this).
sequenceDiagram
participant App as App.OnStartup
participant SP as ServiceProvider
participant MW as MainWindow
App->>App: Global exception handlers, -debug arg
App->>App: Build config (appsettings.json)
App->>App: Serilog bootstrap (file sink + DebugWindowSink + BugReportApiSink)
App->>App: Register DI (ValidateOnBuild)
App->>App: Temp-folder check → abort if running from %TEMP%
App->>SP: BuildServiceProvider
App->>App: Fire-and-forget CleanupTrash + CleanupTempFiles
App->>App: Single-instance Mutex + EventWaitHandle (skipped with --restarting)
App->>App: ApplyTheme + ApplyLanguage from settings
App->>MW: new MainWindow() via DI → Show()
App->>App: -debug → DebugWindow; -whatsnew → UpdateHistoryWindow
App->>App: Fire-and-forget usage stats
MW->>MW: OnLoadedAsync → StartupInitializationService.InitializeAsync + HandleLoadedAsync
StartupInitializationService.InitializeAsync (Services\StartupInitialization\StartupInitializationService.cs:59-72) order:
- Status-bar timer (
StatusBarTimeoutSeconds, default 3 s) —:74-88 - Theme/language menu state —
:90-98 - UI initial state ("No system selected", view mode) —
:100-109 -
Write-access check on base dir →
MoveToWritableFolderMessageBoxAsync—:111-118 - Pagination defaults —
:120-124 -
Tray icon —
:126-137 -
Required-files check (
CheckForRequiredFilesService) —:139-150 - Overlay-button checkmarks —
:152-158 -
Gamepad controller start/stop per settings —
:160-175
HandleLoadedAsync (MainWindow.xaml.cs:350-430):
-
DisplaySystemSelectionScreenAsync—:354 -
Silent update check (GitHub
releases/latest,CheckForUpdatesService.cs:89-143) —:368 - Usage stats call —
:370 -
First-run flow (
:381-424): ifsystem.xmlhas no systems → loading overlay "Scanning for Windows games..." → all 11 store scanners run in parallel (GameScannerService.cs:77-97) → if still empty →FirstRunWelcomeMessageBoxAsync→ EasyModeWindow wizard → reload system list.
-
MainWindow_Closing(MainWindow.CloseWindowEvents.cs:14-45): defers close until settings are saved; unsubscribes events; disposes watchers/hotkey/tray/CHD mounter. -
Minimize-to-tray hides the window (
:49); tray menu provides Open / Minimize to Tray / Debug Window / Exit. -
QuitSimpleLauncher/ReinstallSimpleLauncherhandle restart/update/reinstall (see 16 — Updater).
-
CommunityToolkit.Mvvm 8.4.2: ViewModels derive from
ObservableObject, commands from[RelayCommand](source generators) — e.g.SystemSelectionViewModel. - 44 ViewModels registered transient; windows resolve them and set
DataContext. -
IWindowContextdecouples the launcher fromMainWindow(Services\WpfServices\WpfWindowContext.cs:10).
- Home
- 01 Overview
- 02 Projects And Solution
- 03 Quickstart
- 04 Architecture
- 05 Configuration
- 06 Systems And Launch
- 07 Core Services
- 08 Ui Layer
- 09 Retroachievements
- 10 Game Scanning
- 11 Bundled Tools
- 12 Data Formats
- 13 Logging And Debug
- 14 Testing
- 15 Development
- 16 Updater
- 17 Release Notes
- 18 Emulator Parameters
- Manual Tests
- Parameters