I'm developing a daemon with no UI apart from a simple icon in the Windows systray.
I would like to have no dependencies on any other package(s), so I'm trying to use the syscall
package and implement the necessary call(s) by myself.
Shell_NotifyIcon
function in shell32.dll
.Shell_NotifyIconW
(Unicode declination), but the implementation is partial.Built with xilp/systray documentation.
type HANDLE uintptr
type HICON HANDLE
type HWND HANDLE
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}
type NOTIFYICONDATA struct {
CbSize uint32
HWnd HWND
UID uint32
UFlags uint32
UCallbackMessage uint32
HIcon HICON
SzTip [128]uint16
DwState uint32
DwStateMask uint32
SzInfo [256]uint16
UVersion uint32
SzInfoTitle [64]uint16
DwInfoFlags uint32
GuidItem GUID
}
const (
NIM_ADD = 0x00000000
NIM_MODIFY = 0x00000001
NIM_DELETE = 0x00000002
NIM_SETVERSION = 0x00000004
NIF_MESSAGE = 0x00000001
NIF_ICON = 0x00000002
NIF_TIP = 0x00000004
NIF_STATE = 0x00000008
NIF_HIDDEN = 0x00000001
)
package main
import (
"log"
"syscall"
"unsafe"
)
func main() {
shell32 := syscall.MustLoadDLL("shell32.dll")
Shell_NotifyIcon := shell32.MustFindProc("Shell_NotifyIconW")
iconData := NOTIFYICONDATA{
HWnd: 0,
UFlags: NIF_MESSAGE | NIF_STATE,
DwState: NIF_HIDDEN,
DwStateMask: NIS_HIDDEN,
}
iconData.CbSize = uint32(unsafe.Sizeof(iconData))
ret, _, _ := Shell_NotifyIcon.Call(
NIM_ADD,
uintptr(unsafe.Pointer(&iconData)),
)
if ret == 0 {
log.Println("Failed")
return
}
// Do anything, like open a HTTP server to keep the program running
http.ListenAndServe(":8080", nil)
}
HWnd
, but without it, the executable crashes.UFlags
, DwState
and DwStateMask
have values that I have found in different projects.I know that it is possible; the Golang WIKI gives an implementation to call a message box.
In Windows 10 On Windows 10, you can access more detailed setting by right-clicking the taskbar and selecting “Settings”. This takes you straight to the Settings > Personalization > Taskbar screen. Scroll down to the “Notification Area” section and click the “Select which icons appear on the taskbar” link.
NOTIFYICONDATA
hWnd
field of NOTIFYICONDATA
holds a window handle that is associated with notifyicon itself, as mentioned in MSDN:
hWnd
A handle to the window that receives notifications associated with an icon in the notification area.
I found that it's necessary to associate a window handle, even if the window is not visible.
uFlags
tells which fields of NOTIFYICONDATA
are valid in single command.
As you see there are lots of fields in NOTIFYICONDATA
, and if you are going to change just the icon of the notifyicon, you can leave other fields unchanged and set only hIcon
field then pass the whole NOTIFYICONDATA
to Shell_NotifyIcon
.
If you want to change both icon and message, just set it to NIF_MESSAGE|NIF_ICON
.
dwState
can be used to control icon's visibility. If you specify NIF_STATE
for uFlags
, and NIS_HIDDEN
for dwState
and dwStateMask
, it'll make notifyicon hidden.
And in most case, just set dwStateMask
as same as dwState
. It just tells which bit of dwState
is valid for the command:
The possible values are the same as those for dwState.
You can find full example I've wrote at here: https://github.com/hallazzang/go-windows-programming/tree/master/example/gui/notifyicon
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With