fleet/orbit/cmd/desktop/desktop_windows.go
Lucas Manuel Rodriguez ea25ce4e9e
Fix Fleet Desktop bugs on Windows (#16402)
#15821

This PR is adding two improvements and fixing two Windows bugs in Fleet
Desktop:

## Improvement
- We are now capturing the stderr of Fleet Desktop. This helped me find
bug (1) below (otherwise the panic output below was hidden from us).
- To reduce complexity I'm removing the "Theme detection" routine
because we made the decision to use the colored icon for both themes...,
see here:
415d1f493b/orbit/cmd/desktop/desktop_windows.go (L21-L27)

## Bug fixes
1. Fleet Desktop icon not showing in the task bar. This was fixed by
updating to use the latest version of `fyne.io/systray`. (See
https://github.com/fyne-io/systray/issues/22#issuecomment-1173157898.)
2. Orbit now properly detects if Fleet Desktop isn't running on Windows.

Bug (1)'s panic output 
```
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x72b14b]

goroutine 23 [running]:
fyne.io/systray.(*winTray).setTooltip(0x1eb5d40, {0x126923f?, 0x0?})
	/Users/luk/gopath/pkg/mod/fyne.io/systray@v1.10.0/systray_windows.go:260 +0xcb
fyne.io/systray.SetTooltip({0x126923f?, 0x125fc16?})
	/Users/luk/gopath/pkg/mod/fyne.io/systray@v1.10.0/systray_windows.go:961 +0x29
main.main.func1()
	/Users/luk/fleetdm/git/fleet/orbit/cmd/desktop/desktop.go:103 +0xba
fyne.io/systray.Register.func2()
	/Users/luk/gopath/pkg/mod/fyne.io/systray@v1.10.0/systray.go:98 +0x2f
created by fyne.io/systray.Register in goroutine 1
	/Users/luk/gopath/pkg/mod/fyne.io/systray@v1.10.0/systray.go:96 +0xb1
```

- [X] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [X] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [X] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- [x] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2024-01-29 18:52:55 -03:00

77 lines
2.5 KiB
Go

//go:build windows
// +build windows
package main
import (
_ "embed"
"errors"
"fmt"
"time"
"github.com/rs/zerolog/log"
"golang.org/x/sys/windows"
)
// For Windows we must use ico format for the icon,
// see https://github.com/getlantern/systray/blob/6065fda28be8c8d91aeb5e20de25e1600b8664a3/systray_windows.go#L850-L856.
// In the past we implemented some logic to detect the Windows theme but it was buggy,
// so as a temporary fix we are using the same colored icon for both themes.
// Such theme detection logic was removed in this PR: https://github.com/fleetdm/fleet/pull/16402.
//go:embed windows_app.ico
var iconLight []byte
//go:embed windows_app.ico
var iconDark []byte
// blockWaitForStopEvent waits for the named event kernel object to be signalled
func blockWaitForStopEvent(channelId string) error {
if channelId == "" {
return errors.New("communication channel name should not be empty")
}
// converting go string to UTF16 windows compatible string
targetChannel := "Global\\comm-" + channelId
ev, err := windows.UTF16PtrFromString(targetChannel)
if err != nil {
return fmt.Errorf("there was a problem generating UTF16 string: %w", err)
}
// The right to use the object for synchronization
// https://learn.microsoft.com/en-us/windows/win32/sync/synchronization-object-security-and-access-rights
const EVENT_SYNCHRONIZE = 0x00100000
// block wait until channel is available
var handle windows.Handle = windows.InvalidHandle
for {
// OpenEvent API opens a named event object from the kernel object manager
// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-openeventw
handle, err = windows.OpenEvent(EVENT_SYNCHRONIZE, false, ev)
if (err == nil) && (handle != windows.InvalidHandle) {
break
}
// wait before next handle check
time.Sleep(500 * time.Millisecond)
}
defer windows.CloseHandle(handle)
// OpenEvent() call was successful and our process got a handle to the named event kernel object
log.Info().Msg("Comm channel was acquired")
// now block wait for the handle to be signaled by Orbit
// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject
s, err := windows.WaitForSingleObject(handle, windows.INFINITE)
if (err != nil) && (err != windows.ERROR_SUCCESS) {
return fmt.Errorf("there was a problem calling WaitForSingleObject: %w", err)
}
if s != windows.WAIT_OBJECT_0 {
return fmt.Errorf("event wait was interrupted for unknown reasons: %d", s)
}
return nil
}