使用原生 Golang API 在 Windows 上添加系统托盘图标

15

我正在开发一个没有UI的守护进程,除了Windows系统托盘中的一个简单图标外没有其他UI。

我希望不依赖任何其他包,因此我尝试使用syscall包并自己实现必要的调用。

文档

实现

结构

使用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中提供什么信息,但没有它,可执行文件会崩溃。
  • UFlagsDwStateDwStateMask的值来自于我在不同项目中发现的。

我知道这是可能的;Golang WIKI提供了调用消息框的实现。


2
所以你有两个选择,要么自己创建窗口 CreateWindow 并传递相同的 hwnd,如此处所示。或者你可以尝试看看是否传递桌面的 hwnd 有效。为了实现这一点,你可以使用 GetDesktopWindow - Tarun Lalwani
不错!我已经测试了GetDesktopWindow方法,但是出现了错误。在第二个选项中,不幸的是我无法实现它。你有一个在专用Gist或其他地方实现的例子吗?感谢你的帮助。 - Baptiste Donaux
我没有一个方便的要点,但我会建议在Github上搜索,你应该能找到一些可以尝试的东西。 - Tarun Lalwani
请在您的Println中存储并打印Call中的lastErr,并告诉我们您得到了什么。输出可能非常简洁,但这将是一些额外信息,当调试WinAPI使用时,您需要尽可能多的帮助。 - akavel
2
你可以在github.com/lxn/walk上查看它是如何完成的,就像这个例子所示。 - Adriano P
感谢Adriano提供的示例,非常完美! - Baptiste Donaux
1个回答

2

NOTIFYICONDATA的字段

hWnd

NOTIFYICONDATAhWnd字段保存与通知区域图标关联的窗口句柄,如MSDN所述:

hWnd

接收与通知区域中图标相关的通知的窗口的句柄。

我发现即使窗口不可见,也有必要关联一个窗口句柄。

uFlags 指定单个命令中 NOTIFYICONDATA 的哪些字段是有效的。正如您所看到的,NOTIFYICONDATA 中有很多字段,如果您只想更改通知区域图标,可以将其他字段保持不变并仅设置 hIcon 字段,然后将整个 NOTIFYICONDATA 传递给 Shell_NotifyIcon。如果您想同时更改图标和消息,则将其设置为 NIF_MESSAGE|NIF_ICON

dwState

dwState 可用于控制图标的可见性。如果在 uFlags 中指定了 NIF_STATE,并且在 dwStatedwStateMask 中指定了 NIS_HIDDEN,则会使通知区域图标隐藏。

dwStateMask

在大多数情况下,只需将 dwStateMask 设置为与 dwState 相同。它只是告诉命令 dwState 的哪些位是有效的:

可能的值与 dwState 的值相同。

示例

您可以在此处找到我编写的完整示例:https://github.com/hallazzang/go-windows-programming/tree/master/example/gui/notifyicon


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接