Skip to content

Commit 17fff61

Browse files
committed
Switch Windows autostart to scheduled task
1 parent 2a7da70 commit 17fff61

3 files changed

Lines changed: 104 additions & 31 deletions

File tree

src/autostart.rs

Lines changed: 92 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ use std::path::Path;
22
#[cfg(any(target_os = "macos", target_os = "linux"))]
33
use std::path::PathBuf;
44

5+
#[cfg(target_os = "windows")]
6+
use crate::platform::{is_elevated, run_elevated};
57
use anyhow::{Context, Result, bail};
68

79
#[cfg(target_os = "macos")]
810
const AUTOSTART_LABEL: &str = "io.linuxdo.accelerator";
911
#[cfg(any(target_os = "windows", target_os = "linux"))]
1012
const AUTOSTART_DISPLAY_NAME: &str = "Linux.do Accelerator";
11-
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
13+
#[cfg(target_os = "windows")]
14+
const AUTOSTART_TASK_NAME: &str = AUTOSTART_DISPLAY_NAME;
15+
#[cfg(any(target_os = "macos", target_os = "linux"))]
1216
const AUTOSTART_FLAG: &str = "--autostart";
1317

1418
pub fn enable(config_path: &Path) -> Result<()> {
@@ -32,40 +36,102 @@ fn enable_for_exe(exe: &Path, config_path: &Path) -> Result<()> {
3236
fn platform_enable(exe: &Path, config_path: &Path) -> Result<()> {
3337
use std::process::Command;
3438

39+
if !is_elevated() {
40+
return rerun_windows_autostart_command(exe, Some(config_path), "enable-autostart");
41+
}
42+
3543
let exe = absolute_display_path(exe);
3644
let config = absolute_display_path(config_path);
37-
let value = format!(
38-
"\"{}\" --config \"{}\" {} gui",
39-
exe, config, AUTOSTART_FLAG
40-
);
45+
let value = windows_task_action(&exe, &config);
4146

42-
let mut command = Command::new("reg");
47+
let mut command = Command::new("schtasks");
4348
command.args([
44-
"add",
45-
"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
46-
"/v",
47-
AUTOSTART_DISPLAY_NAME,
48-
"/t",
49-
"REG_SZ",
50-
"/d",
49+
"/create",
50+
"/tn",
51+
AUTOSTART_TASK_NAME,
52+
"/sc",
53+
"onlogon",
54+
"/rl",
55+
"HIGHEST",
56+
"/tr",
5157
&value,
5258
"/f",
5359
]);
5460
hide_windows_window(&mut command);
55-
let output = command.output().context("failed to invoke reg.exe")?;
61+
let output = command.output().context("failed to invoke schtasks.exe")?;
5662
if !output.status.success() {
5763
bail!(
58-
"reg add failed: {}",
59-
String::from_utf8_lossy(&output.stderr).trim()
64+
"schtasks /create failed: {}",
65+
windows_command_message(&output)
6066
);
6167
}
68+
remove_legacy_windows_run_entry()?;
6269
Ok(())
6370
}
6471

6572
#[cfg(target_os = "windows")]
6673
fn platform_disable() -> Result<()> {
6774
use std::process::Command;
6875

76+
let scheduled_task_exists = windows_scheduled_task_exists()?;
77+
if scheduled_task_exists && !is_elevated() {
78+
let exe = std::env::current_exe().context("failed to locate current executable")?;
79+
return rerun_windows_autostart_command(&exe, None, "disable-autostart");
80+
}
81+
82+
if scheduled_task_exists {
83+
let mut command = Command::new("schtasks");
84+
command.args(["/delete", "/tn", AUTOSTART_TASK_NAME, "/f"]);
85+
hide_windows_window(&mut command);
86+
let output = command.output().context("failed to invoke schtasks.exe")?;
87+
if !output.status.success() {
88+
bail!(
89+
"schtasks /delete failed: {}",
90+
windows_command_message(&output)
91+
);
92+
}
93+
}
94+
95+
remove_legacy_windows_run_entry()?;
96+
Ok(())
97+
}
98+
99+
#[cfg(target_os = "windows")]
100+
fn platform_is_enabled() -> Result<bool> {
101+
windows_scheduled_task_exists()
102+
}
103+
104+
#[cfg(target_os = "windows")]
105+
fn rerun_windows_autostart_command(
106+
executable: &Path,
107+
config_path: Option<&Path>,
108+
subcommand: &str,
109+
) -> Result<()> {
110+
let mut args = Vec::with_capacity(3);
111+
if let Some(config_path) = config_path {
112+
args.push("--config".to_string());
113+
args.push(absolute_display_path(config_path));
114+
}
115+
args.push(subcommand.to_string());
116+
run_elevated(executable, &args)
117+
.with_context(|| format!("failed to rerun {subcommand} with administrator privileges"))
118+
}
119+
120+
#[cfg(target_os = "windows")]
121+
fn windows_scheduled_task_exists() -> Result<bool> {
122+
use std::process::Command;
123+
124+
let mut command = Command::new("schtasks");
125+
command.args(["/query", "/tn", AUTOSTART_TASK_NAME]);
126+
hide_windows_window(&mut command);
127+
let output = command.output().context("failed to invoke schtasks.exe")?;
128+
Ok(output.status.success())
129+
}
130+
131+
#[cfg(target_os = "windows")]
132+
fn remove_legacy_windows_run_entry() -> Result<()> {
133+
use std::process::Command;
134+
69135
let mut command = Command::new("reg");
70136
command.args([
71137
"delete",
@@ -90,19 +156,17 @@ fn platform_disable() -> Result<()> {
90156
}
91157

92158
#[cfg(target_os = "windows")]
93-
fn platform_is_enabled() -> Result<bool> {
94-
use std::process::Command;
159+
fn windows_task_action(exe: &str, config: &str) -> String {
160+
format!("\"{exe}\" --config \"{config}\" helper-start")
161+
}
95162

96-
let mut command = Command::new("reg");
97-
command.args([
98-
"query",
99-
"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
100-
"/v",
101-
AUTOSTART_DISPLAY_NAME,
102-
]);
103-
hide_windows_window(&mut command);
104-
let output = command.output().context("failed to invoke reg.exe")?;
105-
Ok(output.status.success())
163+
#[cfg(target_os = "windows")]
164+
fn windows_command_message(output: &std::process::Output) -> String {
165+
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
166+
if !stderr.is_empty() {
167+
return stderr;
168+
}
169+
String::from_utf8_lossy(&output.stdout).trim().to_string()
106170
}
107171

108172
#[cfg(target_os = "windows")]

src/cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub struct Cli {
1616
#[arg(long)]
1717
pub config: Option<PathBuf>,
1818

19-
/// Launch the GUI and immediately start acceleration (used by OS auto-start entries)
19+
/// Launch the GUI and immediately start acceleration (used by macOS/Linux auto-start entries)
2020
#[arg(long)]
2121
pub autostart: bool,
2222

src/gui.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,9 +1135,15 @@ impl AcceleratorApp {
11351135
self.set_autostart(enabled);
11361136
}
11371137
ui.add_space(4.0);
1138+
#[cfg(target_os = "windows")]
1139+
let autostart_note =
1140+
"勾选后系统登录时会通过计划任务更早地直接启动后台加速;首次开启或关闭时需要确认一次管理员/UAC 授权,后续开机无需再次确认。";
1141+
#[cfg(not(target_os = "windows"))]
1142+
let autostart_note =
1143+
"勾选后系统登录时会自动拉起本程序并申请权限启动加速;首次启动仍需要在系统弹窗中确认管理员/UAC 授权。";
11381144
subtle_note(
11391145
ui,
1140-
"勾选后系统登录时会自动拉起本程序并申请权限启动加速;首次启动仍需要在系统弹窗中确认管理员/UAC 授权。",
1146+
autostart_note,
11411147
);
11421148
});
11431149
}
@@ -1748,7 +1754,10 @@ impl AcceleratorApp {
17481754
self.autostart_enabled = enabled;
17491755
self.config.autostart = enabled;
17501756
if let Err(error) = self.save_current_config() {
1751-
self.feedback = format!("已切换开机自启,但保存配置失败: {}", format_error_chain(&error));
1757+
self.feedback = format!(
1758+
"已切换开机自启,但保存配置失败: {}",
1759+
format_error_chain(&error)
1760+
);
17521761
return;
17531762
}
17541763
self.feedback = if enabled {

0 commit comments

Comments
 (0)