@@ -45,7 +45,7 @@ pub fn eject_drive(root: &Path) -> Result<()> {
4545pub fn open_path ( path : & Path ) -> Result < ( ) > {
4646 #[ cfg( target_os = "windows" ) ]
4747 {
48- return run_hidden ( "explorer.exe" , & [ & path. display ( ) . to_string ( ) ] ) ;
48+ return start_process_windows ( & path. display ( ) . to_string ( ) ) ;
4949 }
5050 #[ cfg( target_os = "macos" ) ]
5151 {
@@ -62,7 +62,7 @@ pub fn open_path(path: &Path) -> Result<()> {
6262pub fn open_url ( url : & str ) -> Result < ( ) > {
6363 #[ cfg( target_os = "windows" ) ]
6464 {
65- return run_hidden ( "explorer.exe" , & [ url] ) ;
65+ return start_process_windows ( url) ;
6666 }
6767 #[ cfg( target_os = "macos" ) ]
6868 {
@@ -116,6 +116,68 @@ pub fn prompt_for_update(current_version: &str, latest_version: &str) -> bool {
116116 )
117117}
118118
119+ pub fn show_wizard_loading_indicator ( signal_path : & Path ) -> Result < ( ) > {
120+ #[ cfg( target_os = "windows" ) ]
121+ {
122+ let signal_path = powershell_single_quoted ( & signal_path. display ( ) . to_string ( ) ) ;
123+ let script = format ! (
124+ "Add-Type -AssemblyName System.Windows.Forms; \
125+ Add-Type -AssemblyName System.Drawing; \
126+ $signal = '{signal_path}'; \
127+ $form = New-Object System.Windows.Forms.Form; \
128+ $form.Text = 'ShadowSync'; \
129+ $form.StartPosition = 'CenterScreen'; \
130+ $form.Size = New-Object System.Drawing.Size(360, 128); \
131+ $form.TopMost = $true; \
132+ $form.FormBorderStyle = 'FixedDialog'; \
133+ $form.ControlBox = $false; \
134+ $form.MinimizeBox = $false; \
135+ $form.MaximizeBox = $false; \
136+ $label = New-Object System.Windows.Forms.Label; \
137+ $label.Text = 'Opening Setup Wizard...'; \
138+ $label.AutoSize = $true; \
139+ $label.Location = New-Object System.Drawing.Point(22, 18); \
140+ $label.Font = New-Object System.Drawing.Font('Segoe UI', 11); \
141+ $bar = New-Object System.Windows.Forms.ProgressBar; \
142+ $bar.Style = 'Marquee'; \
143+ $bar.MarqueeAnimationSpeed = 25; \
144+ $bar.Size = New-Object System.Drawing.Size(300, 20); \
145+ $bar.Location = New-Object System.Drawing.Point(22, 54); \
146+ $hint = New-Object System.Windows.Forms.Label; \
147+ $hint.Text = 'This should only take a moment.'; \
148+ $hint.AutoSize = $true; \
149+ $hint.Location = New-Object System.Drawing.Point(22, 82); \
150+ $hint.ForeColor = [System.Drawing.Color]::DimGray; \
151+ $form.Controls.Add($label); \
152+ $form.Controls.Add($bar); \
153+ $form.Controls.Add($hint); \
154+ $timer = New-Object System.Windows.Forms.Timer; \
155+ $timer.Interval = 150; \
156+ $timer.Add_Tick({{ if (-not (Test-Path -LiteralPath $signal)) {{ $form.Close() }} }}); \
157+ $timer.Start(); \
158+ $timeout = New-Object System.Windows.Forms.Timer; \
159+ $timeout.Interval = 20000; \
160+ $timeout.Add_Tick({{ $form.Close() }}); \
161+ $timeout.Start(); \
162+ [void]$form.ShowDialog()"
163+ ) ;
164+ return run_hidden_detached (
165+ "powershell.exe" ,
166+ & [
167+ "-NoLogo" ,
168+ "-NoProfile" ,
169+ "-NonInteractive" ,
170+ "-ExecutionPolicy" ,
171+ "Bypass" ,
172+ "-Command" ,
173+ & script,
174+ ] ,
175+ ) ;
176+ }
177+ #[ allow( unreachable_code) ]
178+ Ok ( ( ) )
179+ }
180+
119181pub fn sleep_short ( duration : Duration ) {
120182 thread:: sleep ( duration) ;
121183}
@@ -227,6 +289,44 @@ fn run_hidden(program: &str, args: &[&str]) -> Result<()> {
227289 }
228290}
229291
292+ #[ cfg( target_os = "windows" ) ]
293+ fn run_hidden_detached ( program : & str , args : & [ & str ] ) -> Result < ( ) > {
294+ use std:: os:: windows:: process:: CommandExt ;
295+
296+ const CREATE_NO_WINDOW : u32 = 0x0800_0000 ;
297+ Command :: new ( program)
298+ . creation_flags ( CREATE_NO_WINDOW )
299+ . args ( args)
300+ . spawn ( )
301+ . with_context ( || format ! ( "failed to start {program}" ) ) ?;
302+ Ok ( ( ) )
303+ }
304+
305+ #[ cfg( target_os = "windows" ) ]
306+ fn start_process_windows ( target : & str ) -> Result < ( ) > {
307+ let command = format ! (
308+ "Start-Process -FilePath '{}'" ,
309+ powershell_single_quoted( target)
310+ ) ;
311+ run_hidden (
312+ "powershell.exe" ,
313+ & [
314+ "-NoLogo" ,
315+ "-NoProfile" ,
316+ "-NonInteractive" ,
317+ "-ExecutionPolicy" ,
318+ "Bypass" ,
319+ "-Command" ,
320+ & command,
321+ ] ,
322+ )
323+ }
324+
325+ #[ cfg( target_os = "windows" ) ]
326+ fn powershell_single_quoted ( value : & str ) -> String {
327+ value. replace ( '\'' , "''" )
328+ }
329+
230330#[ cfg( not( target_os = "windows" ) ) ]
231331fn run_status ( program : & str , args : & [ & str ] ) -> Result < ( ) > {
232332 let status = Command :: new ( program)
0 commit comments