diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs index f45f3bc..c2cd10e 100644 --- a/apps/desktop/src-tauri/src/lib.rs +++ b/apps/desktop/src-tauri/src/lib.rs @@ -90,6 +90,35 @@ fn tray(app: &tauri::App) -> tauri::Result<()> { } /// A tray menu pick (a menu panel row or the native fallback menu): tray.rs maps the id to what it does. +/// Whether the person turned storebound off in Windows' Startup apps (Settings / Task Manager), from the `reg query` +/// output of HKCU\...\Explorer\StartupApproved\Run /v storebound: the first byte of the REG_BINARY is even when enabled +/// (02, 06), odd when disabled (03, 07). No entry: not turned off. Pure. +pub fn startup_approved_off(reg_query_out: &str) -> bool { + reg_query_out + .lines() + .find(|l| l.contains("REG_BINARY")) + .and_then(|l| l.split_whitespace().last()) + .and_then(|hex| u8::from_str_radix(hex.get(0..2)?, 16).ok()) + .is_some_and(|b| b & 1 == 1) +} + +#[cfg(windows)] +fn startup_disabled_by_user() -> bool { + use std::os::windows::process::CommandExt; + const CREATE_NO_WINDOW: u32 = 0x0800_0000; + std::process::Command::new("reg") + .args(["query", r"HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run", "/v", "storebound"]) + .creation_flags(CREATE_NO_WINDOW) + .output() + .map(|o| startup_approved_off(&String::from_utf8_lossy(&o.stdout))) + .unwrap_or(false) +} + +#[cfg(not(windows))] +fn startup_disabled_by_user() -> bool { + false +} + pub fn dispatch_menu(app: &AppHandle, id: &str) { match tray::action_of(id) { Some(tray::Action::Open) => show_main(app), @@ -354,9 +383,14 @@ pub fn run() { } // start at logon, in the tray: rewritten on every start (Windows: the HKCU Run entry then points at the // running exe, so a moved or updated install fixes itself) - match app.autolaunch().enable() { - Ok(()) => logs::host("info", "autostart at logon set (--hidden, tray)"), - Err(e) => logs::host("warn", &format!("autostart not set: {e}")), + // ...unless the person turned it off (Windows Settings > Apps > Startup / Task Manager): that choice stands + if startup_disabled_by_user() { + logs::host("info", "autostart at logon left off (turned off in Windows Startup apps)"); + } else { + match app.autolaunch().enable() { + Ok(()) => logs::host("info", "autostart at logon set (--hidden, tray)"), + Err(e) => logs::host("warn", &format!("autostart not set: {e}")), + } } app.manage(state); app.manage(menu_panel::MenuPanels::default()); diff --git a/apps/desktop/src-tauri/tests/d5.rs b/apps/desktop/src-tauri/tests/d5.rs index 6232f5b..6342910 100644 --- a/apps/desktop/src-tauri/tests/d5.rs +++ b/apps/desktop/src-tauri/tests/d5.rs @@ -142,3 +142,13 @@ fn background_updater_schedule_and_defer() { assert!(updates::take_kick()); assert!(!updates::take_kick()); } + +#[test] +fn startup_apps_choice_is_read_from_startup_approved() { + use storebound_desktop::startup_approved_off; + let on = "\r\nHKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run\r\n storebound REG_BINARY 020000000000000000000000\r\n"; + let off = "\r\nHKEY_CURRENT_USER\\Run\r\n storebound REG_BINARY 0300000020D1D3B1F0B3DC01\r\n"; + assert!(!startup_approved_off(on)); + assert!(startup_approved_off(off)); + assert!(!startup_approved_off("ERROR: The system was unable to find the specified registry key or value.")); +}