fix: restore tray icon after Explorer restart
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user