using Microsoft.Win32; namespace RemSound.App; /// /// Wires "run RemSound automatically when this user logs in" via the per-user Run /// registry key at HKCU\Software\Microsoft\Windows\CurrentVersion\Run. This is the /// same mechanism many Windows apps use for "launch on login"; the entry shows up in Task /// Manager's Startup tab so the user can also toggle it off there if they ever want to. /// /// Why HKCU\...\Run rather than dropping a .lnk into the Startup folder: /// - No COM interop / IShellLink wrangling; just RegistryKey.SetValue. /// - User-scoped (HKCU): no admin elevation needed and only affects this user. /// - Manageable via Task Manager → Startup, which is where Windows users now expect to /// find login-launched apps. /// /// All methods catch all exceptions and return success bools — flipping the toggle in the /// Startup behaviour dialog should never throw, even on policy-locked machines. /// internal static class StartupAutoStart { private const string RunKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Run"; private const string ValueName = "RemSound"; /// True when an entry called "RemSound" exists under the per-user Run key. /// Reads the registry each call (cheap; single key open + value read). Never throws. public static bool IsEnabled { get { try { using var key = Registry.CurrentUser.OpenSubKey(RunKeyPath, writable: false); if (key is null) return false; var value = key.GetValue(ValueName) as string; return !string.IsNullOrWhiteSpace(value); } catch { return false; } } } /// Add or update the Run-key entry to point at the currently-running exe. /// Quotes the path so spaces work. Returns true on success. public static bool TryEnable() { try { using var key = Registry.CurrentUser.OpenSubKey(RunKeyPath, writable: true) ?? Registry.CurrentUser.CreateSubKey(RunKeyPath, writable: true); if (key is null) return false; var exePath = Environment.ProcessPath; if (string.IsNullOrEmpty(exePath)) { // Fallback: use AppContext.BaseDirectory. .NET hosting produces a // different process path for self-contained vs framework-dependent // publish, but BaseDirectory is reliable. exePath = System.IO.Path.Combine(AppContext.BaseDirectory, "RemSound.exe"); } // Wrap in double-quotes so a path containing spaces (e.g. C:\Program Files\) // parses correctly when Windows launches it. key.SetValue(ValueName, $"\"{exePath}\""); return true; } catch { return false; } } /// Remove the Run-key entry. Returns true if the entry is gone afterwards /// (whether we deleted it or it never existed). Returns false only on registry /// access errors. public static bool TryDisable() { try { using var key = Registry.CurrentUser.OpenSubKey(RunKeyPath, writable: true); if (key is null) return true; // No Run subkey at all → nothing to disable. key.DeleteValue(ValueName, throwOnMissingValue: false); return true; } catch { return false; } } }