Добавить иконку в Windows с помощью встроенного API Golang

Я занимаюсь разработкой демона без пользовательского интерфейса, кроме простого значка в системном окне Windows.

Я не хотел бы иметь никаких зависимостей от каких-либо других пакетов, поэтому я пытаюсь использовать пакет 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, но без него исполняемый файл вылетает.
  • UFlags, DwState и DwStateMask имеют значения, которые я нашел в разных проектах.

Я знаю, что это возможно; Golang WIKI дает реализацию для вызова окна сообщения.

Ответ 2

Поля NOTIFYICONDATA

HWND

Поле hWnd в NOTIFYICONDATA содержит дескриптор окна, связанный с самим уведомлением, как указано в MSDN:

HWND

Дескриптор окна, которое получает уведомления, связанные со значком в области уведомлений.

Я обнаружил, что необходимо связать дескриптор окна, даже если окно не видно.

uFlags сообщает, какие поля NOTIFYICONDATA действительны в одной команде. Как вы видите, в NOTIFYICONDATA много полей, и если вы собираетесь изменить только значок уведомления, вы можете оставить другие поля без изменений и установить только поле hIcon, а затем передать весь NOTIFYICONDATA в Shell_NotifyIcon. ]. Если вы хотите изменить значок и сообщение, просто установите для него значение NIF_MESSAGE|NIF_ICON.

dwState

dwState можно использовать для управления видимостью значков. Если вы укажете NIF_STATE для uFlags и NIS_HIDDEN для dwState и dwStateMask, уведомление будет скрыто.

dwStateMask

И в большинстве случаев просто установите dwStateMask так же, как dwState. Он просто сообщает, какой бит dwState действителен для команды:

Возможные значения такие же, как для dwState.

Пример

Вы можете найти полный пример, который я написал здесь: https://github.com/hallazzang/go-windows-programming/tree/master/example/gui/notifyicon