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}\""; }