From 67cd25a10ce3deb1b935e725228e528766f24ad7 Mon Sep 17 00:00:00 2001 From: PathGao <42336971+PathGao@users.noreply.github.com> Date: Fri, 18 Sep 2026 01:23:13 +0800 Subject: [PATCH] fix(single-instance): let the first instance come to front on Windows (#3592) * fix(single-instance): let the first instance come to front on Windows * move the hand-over right after the window lookup --- .changes/single-instance-foreground-rights.md | 5 +++++ .../src/platform_impl/windows.rs | 19 +++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 .changes/single-instance-foreground-rights.md diff --git a/.changes/single-instance-foreground-rights.md b/.changes/single-instance-foreground-rights.md new file mode 100644 index 000000000..57794e69b --- /dev/null +++ b/.changes/single-instance-foreground-rights.md @@ -0,0 +1,5 @@ +--- +"single-instance": patch +--- + +On Windows, the second instance now allows the first instance to bring its window to the front before exiting, so focusing a window from the callback no longer gets refused by Windows. diff --git a/plugins/single-instance/src/platform_impl/windows.rs b/plugins/single-instance/src/platform_impl/windows.rs index d55ec079c..196f7851f 100644 --- a/plugins/single-instance/src/platform_impl/windows.rs +++ b/plugins/single-instance/src/platform_impl/windows.rs @@ -19,10 +19,11 @@ use windows_sys::Win32::{ Threading::{CreateMutexW, ReleaseMutex}, }, UI::WindowsAndMessaging::{ - self as w32wm, CreateWindowExW, DefWindowProcW, DestroyWindow, FindWindowW, - RegisterClassExW, SendMessageW, CREATESTRUCTW, GWLP_USERDATA, GWL_STYLE, - WINDOW_LONG_PTR_INDEX, WM_COPYDATA, WM_CREATE, WM_DESTROY, WNDCLASSEXW, WS_EX_LAYERED, - WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP, WS_VISIBLE, + self as w32wm, AllowSetForegroundWindow, CreateWindowExW, DefWindowProcW, DestroyWindow, + FindWindowW, GetWindowThreadProcessId, RegisterClassExW, SendMessageW, CREATESTRUCTW, + GWLP_USERDATA, GWL_STYLE, WINDOW_LONG_PTR_INDEX, WM_COPYDATA, WM_CREATE, WM_DESTROY, + WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, + WS_OVERLAPPED, WS_POPUP, WS_VISIBLE, }, }; @@ -74,6 +75,16 @@ pub fn init(callback: Box>) -> TauriPlugin let hwnd = FindWindowW(class_name.as_ptr(), window_name.as_ptr()); if !hwnd.is_null() { + // Windows lets us bring a window to the front, but not the first + // instance. Hand that right over before we exit, so focusing a window + // from the callback works. Windows takes it back if the user switches + // to another app in the meantime. + let mut pid = 0; + GetWindowThreadProcessId(hwnd, &mut pid); + if pid != 0 { + AllowSetForegroundWindow(pid); + } + let cwd = std::env::current_dir().unwrap_or_default(); let cwd = cwd.to_str().unwrap_or_default();