fix: restore tray icon after Explorer restart

This commit is contained in:
2026-09-06 13:53:09 +00:00
parent 3f15377ed5
commit 98070d21df
+27 -4
View File
@@ -70,9 +70,11 @@ var (
procGetCursorPos = user32Tray.NewProc("GetCursorPos")
procSetForeground = user32Tray.NewProc("SetForegroundWindow")
procGetModuleHandle = user32Tray.NewProc("GetModuleHandleW")
procRegisterMessage = user32Tray.NewProc("RegisterWindowMessageW")
procShellNotify = shell32Tray.NewProc("Shell_NotifyIconW")
trayCallback = syscall.NewCallback(trayWindowProc)
trayWindows sync.Map // hwnd -> *trayWindow
taskbarCreatedMessage uint32
)
type trayPoint struct{ X, Y int32 }
@@ -212,7 +214,10 @@ func runTrayMessageLoop(output io.Writer, tooltip string, ready chan<- *trayWind
window.icon = trayIconData{CbSize: uint32(unsafe.Sizeof(trayIconData{})), HWnd: hwnd, UID: trayIconID, UFlags: trayNIFMessage | trayNIFIcon | trayNIFTip, UCallbackMessage: trayMessage, HIcon: icon}
copy(window.icon.Tip[:], winapi.StringToUTF16(tooltip))
trayWindows.Store(hwnd, window)
if result, _, err := procShellNotify.Call(uintptr(trayNIMAdd), uintptr(unsafe.Pointer(&window.icon))); result == 0 {
messageName, _ := winapi.UTF16PtrFromString("TaskbarCreated")
registeredMessage, _, _ := procRegisterMessage.Call(uintptr(unsafe.Pointer(messageName)))
taskbarCreatedMessage = uint32(registeredMessage)
if err := window.addIcon(); err != nil {
trayWindows.Delete(hwnd)
_, _, _ = procDestroyWindow.Call(hwnd)
done <- err
@@ -263,10 +268,28 @@ func trayWindowProc(hwnd uintptr, message uint32, wParam, lParam uintptr) uintpt
}
return 0
}
if window != nil && taskbarCreatedMessage != 0 && message == taskbarCreatedMessage {
// Explorer may restart without destroying the tray window. Re-add the
// icon with the current bounded tooltip so the frontend recovers without
// restarting the service or tray process.
_ = window.addIcon()
return 0
}
result, _, _ := procDefWindowProc.Call(hwnd, uintptr(message), wParam, lParam)
return result
}
func (window *trayWindow) addIcon() error {
window.icon.UFlags = trayNIFMessage | trayNIFIcon | trayNIFTip
if result, _, err := procShellNotify.Call(uintptr(trayNIMAdd), uintptr(unsafe.Pointer(&window.icon))); result == 0 {
if err == syscall.Errno(0) {
err = syscall.GetLastError()
}
return err
}
return nil
}
func (window *trayWindow) removeIcon() {
window.closeOnce.Do(func() {
window.icon.UFlags = 0
@@ -400,10 +423,10 @@ func (window *trayWindow) setTooltip(value string) {
}
func openExactPath(path string) error {
if path == "" || strings.TrimSpace(path) != path || !utf8.ValidString(path) {
if path == "" || strings.TrimSpace(path) != path || !utf8.ValidString(path) || !filepath.IsAbs(path) {
return errors.New("invalid path returned by service")
}
info, err := os.Stat(path)
info, err := os.Lstat(path)
if err != nil || !info.Mode().IsRegular() {
return errors.New("service path is not a regular file")
}
@@ -412,7 +435,7 @@ func openExactPath(path string) error {
return err
}
explorer := filepath.Join(windowsDir, "explorer.exe")
if info, err := os.Stat(explorer); err != nil || !info.Mode().IsRegular() {
if info, err := os.Lstat(explorer); err != nil || !info.Mode().IsRegular() {
return errors.New("Windows Explorer is unavailable")
}
return exec.Command(explorer, path).Start()