fix: auto-update relaunch — clear Mark-of-the-Web + wait for exit
The new build downloaded and OpsLog quit, but never came back. Two Windows causes: the freshly written exe carried the internet Zone.Identifier mark, so SmartScreen wanted to prompt "are you sure you want to open this?" — invisibly, since we launch it programmatically — and silently blocked the launch; and starting the new exe while the old one was still exiting raced the single- instance mutex. Now the swapped exe's Zone.Identifier stream is removed, and the relaunch is done by a detached, hidden PowerShell that Wait-Process's on our PID (so we're fully gone and the mutex is free) before Start-Process'ing the new exe.
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
wruntime "github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
@@ -159,14 +160,26 @@ func (a *App) DownloadAndApplyUpdate(url string) error {
|
||||
_ = os.Rename(oldExe, exe) // roll back
|
||||
return fmt.Errorf("install new exe: %w", err)
|
||||
}
|
||||
applog.Printf("update: installed new exe, relaunching")
|
||||
// Clear the "downloaded from the internet" mark (NTFS Zone.Identifier stream).
|
||||
// Otherwise Windows SmartScreen wants to prompt "are you sure you want to open
|
||||
// this?" — but since we launch the exe programmatically that prompt never shows,
|
||||
// and the launch is silently blocked. This is exactly why the relaunch failed.
|
||||
_ = os.Remove(exe + ":Zone.Identifier")
|
||||
applog.Printf("update: installed new exe, scheduling relaunch")
|
||||
|
||||
// Relaunch with a flag so the fresh instance waits for THIS one to exit and
|
||||
// free the single-instance mutex instead of bailing out immediately.
|
||||
cmd := exec.Command(exe, "--post-update")
|
||||
cmd.Dir = dir
|
||||
// Relaunch via a detached, hidden PowerShell that WAITS for this process to exit
|
||||
// (so the single-instance mutex is free) and THEN starts the new exe. Launching
|
||||
// the new exe directly while we're still alive raced the mutex and often left
|
||||
// nothing running; waiting for our own exit first makes the restart reliable,
|
||||
// and the launcher outlives us.
|
||||
quoted := strings.ReplaceAll(exe, "'", "''")
|
||||
ps := fmt.Sprintf(
|
||||
"Wait-Process -Id %d -ErrorAction SilentlyContinue; Start-Sleep -Milliseconds 400; Start-Process -FilePath '%s' -ArgumentList '--post-update'",
|
||||
os.Getpid(), quoted)
|
||||
cmd := exec.Command("powershell", "-NoProfile", "-WindowStyle", "Hidden", "-Command", ps)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true, CreationFlags: 0x08000000} // CREATE_NO_WINDOW
|
||||
if err := cmd.Start(); err != nil {
|
||||
return fmt.Errorf("relaunch: %w", err)
|
||||
return fmt.Errorf("schedule relaunch: %w", err)
|
||||
}
|
||||
if a.ctx != nil {
|
||||
wruntime.Quit(a.ctx)
|
||||
|
||||
Reference in New Issue
Block a user