From 622f02bf21858f0cff95419fc042ce02b8c6b18b Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:38:50 +0800 Subject: [PATCH] fix(updater): check `ShellExecuteW` results (#3516) * fix(updater): check `ShellExecuteW` results * document the exit on windows --- .../updater-check-shell-execute-result.md | 6 ++++++ plugins/notification/guest-js/index.ts | 3 ++- plugins/updater/README.md | 1 + plugins/updater/guest-js/index.ts | 20 ++++++++++++++++--- plugins/updater/src/updater.rs | 15 +++++++++++++- 5 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 .changes/updater-check-shell-execute-result.md diff --git a/.changes/updater-check-shell-execute-result.md b/.changes/updater-check-shell-execute-result.md new file mode 100644 index 000000000..d875d95fd --- /dev/null +++ b/.changes/updater-check-shell-execute-result.md @@ -0,0 +1,6 @@ +--- +"updater": patch +"updater-js": patch +--- + +On Windows, returns an error if failed to spawn the installer in `install` through `ShellExecuteW` diff --git a/plugins/notification/guest-js/index.ts b/plugins/notification/guest-js/index.ts index 685c60c20..7045ac66e 100644 --- a/plugins/notification/guest-js/index.ts +++ b/plugins/notification/guest-js/index.ts @@ -73,7 +73,8 @@ interface Options { /** * The sound resource name or file path for the notification. * - * Platform specific behavior: + * ## Platform-specific behavior: + * * - On macOS: use system sounds (e.g., "Ping", "Blow") or sound files in the app bundle * - On Linux: use XDG theme sounds (e.g., "message-new-instant") or file paths * - On Windows: use file paths to sound files (.wav format) diff --git a/plugins/updater/README.md b/plugins/updater/README.md index b3afb818a..f122e74f1 100644 --- a/plugins/updater/README.md +++ b/plugins/updater/README.md @@ -69,6 +69,7 @@ import { relaunch } from '@tauri-apps/plugin-process' const update = await check() if (update) { await update.downloadAndInstall() + // Relaunch the app on macOS and Linux to run the newly install version await relaunch() } ``` diff --git a/plugins/updater/guest-js/index.ts b/plugins/updater/guest-js/index.ts index 1a120921a..d53165eb2 100644 --- a/plugins/updater/guest-js/index.ts +++ b/plugins/updater/guest-js/index.ts @@ -84,7 +84,7 @@ class Update extends Resource { this.rawJson = metadata.rawJson } - /** Download the updater package */ + /** Download the updater package. Call {@linkcode install} later to install it */ async download( onEvent?: (progress: DownloadEvent) => void, options?: DownloadOptions @@ -102,7 +102,14 @@ class Update extends Resource { this.downloadedBytes = new Resource(downloadedBytesRid) } - /** Install downloaded updater package */ + /** + * Install downloaded updater package. Must be called after {@linkcode download}. + * + * ## Platform-specific: + * + * - **Windows:** This function exits the app after launching the updater installer successfully + * - **macOS / Linux:** You need to relaunch the app to run the newly install version + */ async install(options?: InstallOptions): Promise { if (!this.downloadedBytes) { throw new Error('Update.install called before Update.download') @@ -118,7 +125,14 @@ class Update extends Resource { this.downloadedBytes = undefined } - /** Downloads the updater package and installs it */ + /** + * Downloads the updater package and installs it + * + * ## Platform-specific: + * + * - **Windows:** This function exits the app after launching the updater installer successfully + * - **macOS / Linux:** You need to relaunch the app to run the newly install version + */ async downloadAndInstall( onEvent?: (progress: DownloadEvent) => void, options?: DownloadOptions & InstallOptions diff --git a/plugins/updater/src/updater.rs b/plugins/updater/src/updater.rs index 69a7fd0f8..e877820a7 100644 --- a/plugins/updater/src/updater.rs +++ b/plugins/updater/src/updater.rs @@ -743,11 +743,21 @@ impl Update { } /// Installs the updater package downloaded by [`Update::download`] + /// + /// ## Platform-specific: + /// + /// - **Windows:** This function exits the app after launching the updater installer successfully + /// - **macOS / Linux:** You need to relaunch the app to run the newly install version pub fn install(&self, bytes: impl AsRef<[u8]>) -> Result<()> { self.install_inner(bytes.as_ref()) } /// Downloads and installs the updater package + /// + /// ## Platform-specific: + /// + /// - **Windows:** This function exits the app after launching the updater installer successfully + /// - **macOS / Linux:** You need to relaunch the app to run the newly install version pub async fn download_and_install), D: FnOnce()>( &self, on_chunk: C, @@ -849,7 +859,7 @@ impl Update { let file = encode_wide(file); let parameters = encode_wide(parameters); - unsafe { + let result = unsafe { ShellExecuteW( std::ptr::null_mut(), w!("open"), @@ -859,6 +869,9 @@ impl Update { SW_SHOW, ) }; + if result as isize <= 32 { + return Err(crate::Error::Io(std::io::Error::last_os_error())); + } std::process::exit(0); }