我正在开发一个没有UI的守护进程,除了Windows系统托盘中的一个简单图标外没有其他UI。
我希望不依赖任何其他包,因此我尝试使用syscall
包并自己实现必要的调用。
文档
- 经过一些研究,我认为我必须使用
shell32.dll
中的Shell_NotifyIcon
函数。 - Golang WIKI提供了三种调用Windows DLL的方法。第三种解决方案应该被排除。出于许多原因,我只想使用Golang编译器构建源代码。
- 我找到了一篇有趣的关于"使用Go开发多平台应用程序"的文章,其中解释了如何使用
Shell_NotifyIconW
(Unicode变体),但实现是部分的。 - 我发现了一些实现Windows系统托盘的Golang库。它们有助于理解涉及处理它的结构和调用。
库
- getlantern/systray:Lantern图标托盘
- cratonica/trayhost:TrayHost
- xilp/systray:systray库
- lxn/walk:Walk
实现
结构
使用xilp/systray文档构建。
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
中提供什么信息,但没有它,可执行文件会崩溃。 UFlags
、DwState
和DwStateMask
的值来自于我在不同项目中发现的。
我知道这是可能的;Golang WIKI提供了调用消息框的实现。
CreateWindow
并传递相同的 hwnd,如此处所示。或者你可以尝试看看是否传递桌面的 hwnd 有效。为了实现这一点,你可以使用 GetDesktopWindow。 - Tarun LalwaniPrintln
中存储并打印Call
中的lastErr
,并告诉我们您得到了什么。输出可能非常简洁,但这将是一些额外信息,当调试WinAPI使用时,您需要尽可能多的帮助。 - akavel