Launcher Lifecycle
This file covers what happens from the moment the operating system starts Stride.Launcher.exe until it exits — process entry, single-instance enforcement, argument parsing, app startup, Game Studio launch, and crash reporting.
Entry point
flowchart TD
OS["OS spawns Stride.Launcher.exe"]
PM["Program.Main<br/>STAThread"]
LM["Launcher.Main<br/>unhandled-exception handler,<br/>ProcessArguments, ProcessAction"]
FL["FileLock.TryLock<br/>launcher.lock in EditorPath.DefaultTempPath"]
RUN["Program.RunNewApp<App>"]
APPMAIN["AppMainAsync:<br/>dispatch LauncherArguments.Actions"]
TR["TryRun → show MainWindow"]
UN["UninstallAsync"]
EXIT["Return LauncherErrorCode"]
OS --> PM --> LM --> FL
FL -- "got lock" --> RUN --> APPMAIN
APPMAIN --> TR
APPMAIN --> UN
TR --> EXIT
UN --> EXIT
FL -- "already locked" --> EXIT
- Program.cs is the
[STAThread]entry point. It immediately delegates toLauncher.Mainand casts theLauncherErrorCodeenum tointfor the process exit code. - Launcher.cs installs an
AppDomain.UnhandledExceptionhandler, parses arguments, and dispatches to the right action.
Single-instance enforcement
Launcher.ProcessAction acquires a FileLock over {EditorPath.DefaultTempPath}/launcher.lock (see Stride.Core.IO.FileLock). The lock is stored in the static Launcher.Mutex so the self-updater can release it before spawning a replacement process. If the lock is already held, the launcher pops up a warning dialog through a separate minimal Avalonia app and returns LauncherErrorCode.ServerAlreadyRunning (value 1).
Command-line arguments
LauncherArguments.cs defines the argument model. Arguments are parsed by Launcher.ProcessArguments:
| Argument | Meaning |
|---|---|
| (none) | Default action — show the launcher window and manage versions |
/Uninstall |
Clears all other actions and runs UninstallAsync |
/UpdateTargets |
Appended by SelfUpdater.RestartApplication after a self-update (currently not interpreted separately from the default Run) |
/LauncherWindowHandle <hwnd> |
Outgoing, not incoming — the launcher passes this to Game Studio when AutoCloseLauncher is on, so Game Studio can signal back |
To add a new action:
- Add a value to
LauncherArguments.ActionType. - Parse it in
Launcher.ProcessArguments. - Handle it in the
AppMainAsyncswitch insideLauncher.ProcessAction. - Reserve a new error code range in LauncherErrorCode.cs.
Error codes
Exit codes are defined in LauncherErrorCode.cs. The convention is:
0→Success- Positive → non-error outcomes (
ServerAlreadyRunning = 1) - Negative → errors, grouped by action:
-1..-100— RunServer errors-101..-200— UpdateTargets errors-201..-300— Uninstall errors-10000—UnknownError
External installers and wrappers rely on these codes to decide whether to retry, surface a dialog, etc.
App startup
Once the lock is acquired, Program.RunNewApp<App> builds the Avalonia app:
AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
App.axaml.cs then:
- Attaches Avalonia dev tools in Debug builds.
- Initializes the global MarkView/Markdig pipeline (alert blocks, footnotes, figures, Mermaid, SVG, TextMate highlighting, link handler that opens URLs via
ShellExecute). - Creates the
ViewModelServiceProviderwith aDispatcherServiceand aDialogService. - Instantiates
MainViewModeland wires it asMainWindow.DataContext.
MinimalApp : App (same file) is a cut-down app used for secondary windows (crash report, "already running" message, self-update progress). It overrides OnFrameworkInitializationCompleted to a no-op so nothing is built beyond what the caller schedules.
Game Studio launch
Clicking Start invokes MainViewModel.StartStudio(string argument):
- If
AutoCloseLauncheris on, the launcher prepends/LauncherWindowHandle {MainViewModel.WindowHandle}to the argument string so Game Studio can message it back. ActiveVersion.LocateMainExecutable()resolves the path — the folder remembered forSelectedEditorundertools/orlib/, falling back to the legacy pathlib/net472/Stride.GameStudio.exe.- With an explicit runtime choice the launcher runs
dotnet exec --runtimeconfig <generated> <dll> <args>(DotNetHostSelector.RelaunchStartInfo); otherwise it runs the apphost, ordotnet <dll>where there is none (NativeStartInfo).WorkingDirectoryis set to the directory of the executable soglobal.jsonresolves correctly. - The command is disabled for five seconds to debounce double-clicks, then re-enabled if the version is still
CanStart. - The active version is persisted through
LauncherSettings.ActiveVersion.
MainViewModel.WindowHandle is a static IntPtr set by the view code-behind once the main window is realized — the launcher keeps it on a static so the dialog helpers can reach it without plumbing through another service.
Crash reporting
Two entry points feed the same pipeline:
Launcher.Main'stry/catch(synchronous exceptions during argument parsing / action dispatch).AppDomain.CurrentDomain.UnhandledException(asynchronous exceptions).
Both call HandleException, which:
- Uses
Interlocked.CompareExchangeonterminatingto make sure we report only once. - Forces
en-USculture so the report is reproducible. - Builds a
CrashReportArgswith the exception, the crash location, and the current thread name. - Calls
CrashReport, which spins up aMinimalApp, shows aCrashReportWindowbound to aCrashReportViewModel, and blocks until it is closed.