From 91b3f0c1c11a1e371a8b7ffee0b5b6fd3677ee0a Mon Sep 17 00:00:00 2001 From: Ednunp <29843396+Ednunp@users.noreply.github.com> Date: Sun, 12 Jul 2026 20:34:34 +0100 Subject: [PATCH] Service: menu before Options + start-after-audio dependency Local checkpoint - NOT for public release. - Service menu now sits before Options in the menu bar (File / Record / Service / Options / Help), per Ed. - The service is registered with depend= Audiosrv/AudioEndpointBuilder, so Windows starts it the instant the audio services are ready at boot (before login) - the earliest point WASAPI capture can find any audio. It CANNOT start before the audio services (there'd be no endpoints to capture, and no sound exists before audio is up), so this is the earliest useful start. DoInstall now uses the single BuildCreateArgs source of truth. Gate 25/25. Co-Authored-By: Claude Opus 4.8 --- src/RemSound.App/MainForm.cs | 2 +- src/RemSound.App/ServiceControl.cs | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/RemSound.App/MainForm.cs b/src/RemSound.App/MainForm.cs index dd02fda..b415d4b 100644 --- a/src/RemSound.App/MainForm.cs +++ b/src/RemSound.App/MainForm.cs @@ -2170,8 +2170,8 @@ public sealed class MainForm : Form // and the arrow keys. menu.Items.Add(fileMenu); menu.Items.Add(recordMenu); - menu.Items.Add(optionsMenu); menu.Items.Add(BuildServiceMenu()); + menu.Items.Add(optionsMenu); menu.Items.Add(helpMenu); return menu; } diff --git a/src/RemSound.App/ServiceControl.cs b/src/RemSound.App/ServiceControl.cs index b88136a..44d6e4d 100644 --- a/src/RemSound.App/ServiceControl.cs +++ b/src/RemSound.App/ServiceControl.cs @@ -94,11 +94,7 @@ public static class ServiceControl var exe = Environment.ProcessPath; if (string.IsNullOrEmpty(exe)) return 2; - // sc.exe's key= value syntax needs a space after '='. The binPath value is the quoted exe path - // plus the run verb, and that whole value is itself quoted — hence the escaped inner quotes. - var createArgs = - $"create {ServiceName} binPath= \"\\\"{exe}\\\" {RunVerb}\" start= auto DisplayName= \"{DisplayName}\""; - var rc = RunSc(createArgs); + var rc = RunSc(BuildCreateArgs(exe)); if (rc != 0) return rc; // Best-effort description; failure here doesn't fail the install. RunSc($"description {ServiceName} \"{Description}\""); @@ -164,7 +160,13 @@ public static class ServiceControl } /// Builds the exact sc.exe "create" argument string for a given exe path. Pure and - /// side-effect-free so a self-test can verify the fiddly quoting without touching the SCM. + /// side-effect-free so a self-test can verify the fiddly quoting without touching the SCM. + /// + /// depend= Audiosrv/AudioEndpointBuilder makes the service start as EARLY as it usefully + /// can: the Windows Audio and Audio Endpoint Builder services must be running for WASAPI capture to + /// find any audio at all, so Windows launches RemSound the instant they're ready (at boot, before + /// login) rather than at some arbitrary later point. Starting it BEFORE the audio services isn't + /// possible — there'd be no endpoints to capture — and there's no sound to miss before audio is up. internal static string BuildCreateArgs(string exePath) => - $"create {ServiceName} binPath= \"\\\"{exePath}\\\" {RunVerb}\" start= auto DisplayName= \"{DisplayName}\""; + $"create {ServiceName} binPath= \"\\\"{exePath}\\\" {RunVerb}\" start= auto depend= Audiosrv/AudioEndpointBuilder DisplayName= \"{DisplayName}\""; }