Skip to content

Add a named-event single-instance guard - #88

Merged
danielchalmers merged 1 commit into
mainfrom
single-instance-guard
Oct 5, 2026
Merged

danielchalmers merged 1 commit into
mainfrom
single-instance-guard

Conversation

@danielchalmers

Copy link
Copy Markdown
Owner

Problem

Launching Radial Actions while it was already running started a second copy. That happened from the Start menu, from the installer after an install or update while a copy was still running, and from the Run key. The second copy's hotkey registration failed, so it showed "Couldn't register Ctrl+Alt+Space. Another app may be using it." on every extra launch, which blames another app for Radial Actions itself. The two copies could also overwrite each other's settings.

Changes

  • Guard. New Services/SingleInstance.cs uses a named auto-reset event, Local\RadialActions.
    • The name doesn't depend on the install path, so portable and installed copies detect each other.
    • Debug builds use Local\RadialActions.Debug, so they can run next to an installed copy.
  • Startup. App.xaml drops StartupUri, and App.OnStartup builds and shows MainWindow only for the first copy.
    • A later launch passes its right to come to the foreground to the running copy (AllowSetForegroundWindow), signals it, and calls Shutdown() before any window, tray icon, or settings access exists.
    • The running copy opens Settings on the General tab (MainWindow.OpenSettingsForRelaunch).
  • Different accounts. If the event can't be opened because a copy under another account in the same session created it, the new copy logs it and exits.
  • AGENTS.md. Adds the single-instance product invariant.

Validation

  • dotnet build in Debug and Release: 0 warnings. dotnet test: 598 passed. New SingleInstanceTests cover four cases:
    • which copy is first;
    • a later copy signalling the first;
    • the next launch after the first copy exits;
    • the can't-open branch, using a deny ACE.
  • Tested on Windows 11 with an isolated test install of this code:
    • launching the installed exe again, one at a time or two at once, exited in under 1 s;
    • Settings opened on the General tab in the running copy and came to the foreground;
    • one copy remained;
    • the installer's post-install launch next to a running copy also handed off to it.
  • Reviewed against dotnet/wpf Application.cs:
    • with no StartupUri, DoStartup does nothing;
    • Shutdown() inside OnStartup exits with code 0;
    • the first window created still becomes Application.MainWindow, which GeneralSettingsView relies on.

Risks

  • v0.7.0 has no guard. The guard only works between copies that have it. If an update from v0.7.0 leaves the old version running (the user picks "Do not close applications"), both versions run once.
  • "Do not close" from a guarded version. The new copy hands off to the old one, which keeps running until it exits. A possible follow-up: have the running copy restart when its exe on disk is a newer version.
  • Relaunch picks the General tab. It switches an already open Settings window to General, the same as the existing notifications do.

Launching the app while it was running (from Start, the installer, or the Run key) started a second copy whose hotkey registration failed with a misleading 'another app may be using it' notification. A named event now lets only the first copy build its window; a later launch asks the running copy to open Settings and exits.
@danielchalmers danielchalmers changed the title Keep one running copy and open Settings on relaunch Add a named-event single-instance guard Oct 5, 2026
@danielchalmers
danielchalmers merged commit 668a8c8 into main Oct 5, 2026
1 check passed
@danielchalmers
danielchalmers deleted the single-instance-guard branch October 5, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant