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
This commit is contained in:
PathGao
2026-09-18 01:23:13 +08:00
committed by GitHub
parent 2df3d93681
commit 67cd25a10c
2 changed files with 20 additions and 4 deletions
@@ -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.
@@ -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<R: Runtime>(callback: Box<SingleInstanceCallback<R>>) -> 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();