@@ -2,13 +2,17 @@ use std::path::Path;
22#[ cfg( any( target_os = "macos" , target_os = "linux" ) ) ]
33use std:: path:: PathBuf ;
44
5+ #[ cfg( target_os = "windows" ) ]
6+ use crate :: platform:: { is_elevated, run_elevated} ;
57use anyhow:: { Context , Result , bail} ;
68
79#[ cfg( target_os = "macos" ) ]
810const AUTOSTART_LABEL : & str = "io.linuxdo.accelerator" ;
911#[ cfg( any( target_os = "windows" , target_os = "linux" ) ) ]
1012const 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" ) ) ]
1216const AUTOSTART_FLAG : & str = "--autostart" ;
1317
1418pub fn enable ( config_path : & Path ) -> Result < ( ) > {
@@ -32,40 +36,102 @@ fn enable_for_exe(exe: &Path, config_path: &Path) -> Result<()> {
3236fn 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" ) ]
6673fn 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" ) ]
0 commit comments