├── part1 ├── icon.ico ├── README.md ├── main.go └── winapi.go ├── part2 ├── icon.ico ├── README.md ├── main.go └── winapi.go ├── README.md └── LICENSE /part1/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hallazzang/go-tray-icons-tutorial/HEAD/part1/icon.ico -------------------------------------------------------------------------------- /part2/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hallazzang/go-tray-icons-tutorial/HEAD/part2/icon.ico -------------------------------------------------------------------------------- /part1/README.md: -------------------------------------------------------------------------------- 1 | # Creating Tray Icons using Go in Windows - Part 1 2 | 3 | Run this example by: 4 | 5 | ``` 6 | go run . 7 | ``` 8 | -------------------------------------------------------------------------------- /part2/README.md: -------------------------------------------------------------------------------- 1 | # Creating Tray Icons using Go in Windows - Part 2 2 | 3 | Run this example by: 4 | 5 | ``` 6 | go run . 7 | ``` 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Creating Tray Icons using Go 2 | 3 | This repository contains full example code which is used in my tutorial. 4 | 5 | Original article can be found at: https://hallazzang.github.io/post/go-tray-icons/ 6 | 7 | ## Parts 8 | 9 | - [Part 1](part1) 10 | - [Part 2](part2) 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Hanjun Kim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /part1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "unsafe" 5 | 6 | "golang.org/x/sys/windows" 7 | ) 8 | 9 | func wndProc(hWnd uintptr, msg uint32, wParam, lParam uintptr) uintptr { 10 | switch msg { 11 | case WM_DESTROY: 12 | PostQuitMessage(0) 13 | default: 14 | r, _ := DefWindowProc(hWnd, msg, wParam, lParam) 15 | return r 16 | } 17 | return 0 18 | } 19 | 20 | func createMainWindow() (uintptr, error) { 21 | hInstance, err := GetModuleHandle(nil) 22 | if err != nil { 23 | return 0, err 24 | } 25 | 26 | wndClass := windows.StringToUTF16Ptr("MyWindow") 27 | 28 | var wcex WNDCLASSEX 29 | 30 | wcex.CbSize = uint32(unsafe.Sizeof(wcex)) 31 | wcex.LpfnWndProc = windows.NewCallback(wndProc) 32 | wcex.HInstance = hInstance 33 | wcex.LpszClassName = wndClass 34 | if _, err := RegisterClassEx(&wcex); err != nil { 35 | return 0, err 36 | } 37 | 38 | hwnd, err := CreateWindowEx( 39 | 0, 40 | wndClass, 41 | windows.StringToUTF16Ptr("Tray Icons Example"), 42 | WS_OVERLAPPEDWINDOW, 43 | CW_USEDEFAULT, 44 | CW_USEDEFAULT, 45 | 400, 46 | 300, 47 | 0, 48 | 0, 49 | hInstance, 50 | nil) 51 | if err != nil { 52 | return 0, err 53 | } 54 | 55 | return hwnd, nil 56 | } 57 | 58 | func main() { 59 | hwnd, err := createMainWindow() 60 | if err != nil { 61 | panic(err) 62 | } 63 | 64 | var data NOTIFYICONDATA 65 | 66 | data.CbSize = uint32(unsafe.Sizeof(data)) 67 | data.UFlags = NIF_ICON 68 | data.HWnd = hwnd 69 | 70 | icon, err := LoadImage( 71 | 0, 72 | windows.StringToUTF16Ptr("icon.ico"), 73 | IMAGE_ICON, 74 | 0, 75 | 0, 76 | LR_DEFAULTSIZE|LR_LOADFROMFILE) 77 | if err != nil { 78 | panic(err) 79 | } 80 | data.HIcon = icon 81 | 82 | if _, err := Shell_NotifyIcon(NIM_ADD, &data); err != nil { 83 | panic(err) 84 | } 85 | 86 | defer func() { 87 | if _, err := Shell_NotifyIcon(NIM_DELETE, &data); err != nil { 88 | panic(err) 89 | } 90 | }() 91 | 92 | ShowWindow(hwnd, SW_SHOW) 93 | 94 | var msg MSG 95 | 96 | for { 97 | r, err := GetMessage(&msg, 0, 0, 0) 98 | if err != nil { 99 | panic(err) 100 | } 101 | if r == 0 { 102 | break 103 | } 104 | 105 | TranslateMessage(&msg) 106 | DispatchMessage(&msg) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /part2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | "unsafe" 8 | 9 | "golang.org/x/sys/windows" 10 | ) 11 | 12 | const TrayIconMsg = WM_APP + 1 13 | 14 | func wndProc(hWnd uintptr, msg uint32, wParam, lParam uintptr) uintptr { 15 | switch msg { 16 | case TrayIconMsg: 17 | switch nmsg := LOWORD(uint32(lParam)); nmsg { 18 | case NIN_BALLOONUSERCLICK: 19 | fmt.Println("user clicked the balloon notification") 20 | case WM_LBUTTONDOWN: 21 | fmt.Println("user clicked the tray icon") 22 | } 23 | case WM_DESTROY: 24 | PostQuitMessage(0) 25 | default: 26 | r, _ := DefWindowProc(hWnd, msg, wParam, lParam) 27 | return r 28 | } 29 | return 0 30 | } 31 | 32 | func createMainWindow() (uintptr, error) { 33 | hInstance, err := GetModuleHandle(nil) 34 | if err != nil { 35 | return 0, err 36 | } 37 | 38 | wndClass := windows.StringToUTF16Ptr("MyWindow") 39 | 40 | var wcex WNDCLASSEX 41 | 42 | wcex.CbSize = uint32(unsafe.Sizeof(wcex)) 43 | wcex.LpfnWndProc = windows.NewCallback(wndProc) 44 | wcex.HInstance = hInstance 45 | wcex.LpszClassName = wndClass 46 | if _, err := RegisterClassEx(&wcex); err != nil { 47 | return 0, err 48 | } 49 | 50 | hwnd, err := CreateWindowEx( 51 | 0, 52 | wndClass, 53 | windows.StringToUTF16Ptr("Tray Icons Example"), 54 | WS_OVERLAPPEDWINDOW, 55 | CW_USEDEFAULT, 56 | CW_USEDEFAULT, 57 | 400, 58 | 300, 59 | 0, 60 | 0, 61 | hInstance, 62 | nil) 63 | if err != nil { 64 | return 0, err 65 | } 66 | 67 | return hwnd, nil 68 | } 69 | 70 | func newGUID() GUID { 71 | var buf [16]byte 72 | rand.Read(buf[:]) 73 | return *(*GUID)(unsafe.Pointer(&buf[0])) 74 | } 75 | 76 | type TrayIcon struct { 77 | hwnd uintptr 78 | guid GUID 79 | } 80 | 81 | func NewTrayIcon(hwnd uintptr) (*TrayIcon, error) { 82 | ti := &TrayIcon{hwnd: hwnd, guid: newGUID()} 83 | data := ti.initData() 84 | data.UFlags |= NIF_MESSAGE 85 | data.UCallbackMessage = TrayIconMsg 86 | if _, err := Shell_NotifyIcon(NIM_ADD, data); err != nil { 87 | return nil, err 88 | } 89 | return ti, nil 90 | } 91 | 92 | func (ti *TrayIcon) initData() *NOTIFYICONDATA { 93 | var data NOTIFYICONDATA 94 | data.CbSize = uint32(unsafe.Sizeof(data)) 95 | data.UFlags = NIF_GUID 96 | data.HWnd = ti.hwnd 97 | data.GUIDItem = ti.guid 98 | return &data 99 | } 100 | 101 | func (ti *TrayIcon) Dispose() error { 102 | _, err := Shell_NotifyIcon(NIM_DELETE, ti.initData()) 103 | return err 104 | } 105 | 106 | func (ti *TrayIcon) SetIcon(icon uintptr) error { 107 | data := ti.initData() 108 | data.UFlags |= NIF_ICON 109 | data.HIcon = icon 110 | _, err := Shell_NotifyIcon(NIM_MODIFY, data) 111 | return err 112 | } 113 | 114 | func (ti *TrayIcon) SetTooltip(tooltip string) error { 115 | data := ti.initData() 116 | data.UFlags |= NIF_TIP 117 | copy(data.SzTip[:], windows.StringToUTF16(tooltip)) 118 | _, err := Shell_NotifyIcon(NIM_MODIFY, data) 119 | return err 120 | } 121 | 122 | func (ti *TrayIcon) ShowBalloonNotification(title, text string) error { 123 | data := ti.initData() 124 | data.UFlags |= NIF_INFO 125 | if title != "" { 126 | copy(data.SzInfoTitle[:], windows.StringToUTF16(title)) 127 | } 128 | copy(data.SzInfo[:], windows.StringToUTF16(text)) 129 | _, err := Shell_NotifyIcon(NIM_MODIFY, data) 130 | return err 131 | } 132 | 133 | func init() { 134 | rand.Seed(time.Now().UnixNano()) 135 | } 136 | 137 | func main() { 138 | hwnd, err := createMainWindow() 139 | if err != nil { 140 | panic(err) 141 | } 142 | 143 | icon, err := LoadImage( 144 | 0, 145 | windows.StringToUTF16Ptr("icon.ico"), 146 | IMAGE_ICON, 147 | 0, 148 | 0, 149 | LR_DEFAULTSIZE|LR_LOADFROMFILE) 150 | if err != nil { 151 | panic(err) 152 | } 153 | 154 | ti, err := NewTrayIcon(hwnd) 155 | if err != nil { 156 | panic(err) 157 | } 158 | defer ti.Dispose() 159 | 160 | ti.SetIcon(icon) 161 | ti.SetTooltip("Tray Icon!") 162 | 163 | go func() { 164 | for i := 1; i <= 3; i++ { 165 | time.Sleep(3 * time.Second) 166 | ti.ShowBalloonNotification( 167 | fmt.Sprintf("Message %d", i), 168 | "This is a balloon message", 169 | ) 170 | } 171 | }() 172 | 173 | ShowWindow(hwnd, SW_SHOW) 174 | 175 | var msg MSG 176 | for { 177 | if r, err := GetMessage(&msg, 0, 0, 0); err != nil { 178 | panic(err) 179 | } else if r == 0 { 180 | break 181 | } 182 | TranslateMessage(&msg) 183 | DispatchMessage(&msg) 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /part1/winapi.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "unsafe" 5 | 6 | "golang.org/x/sys/windows" 7 | ) 8 | 9 | const ( 10 | IMAGE_ICON = 1 11 | 12 | LR_DEFAULTSIZE = 0x00000040 13 | LR_LOADFROMFILE = 0x00000010 14 | 15 | SW_SHOW = 5 16 | 17 | CW_USEDEFAULT = ^0x7fffffff 18 | 19 | WS_CAPTION = 0x00c00000 20 | WS_MAXIMIZEBOX = 0x00010000 21 | WS_MINIMIZEBOX = 0x00020000 22 | WS_OVERLAPPED = 0x00000000 23 | WS_SYSMENU = 0x00080000 24 | WS_THICKFRAME = 0x00040000 25 | WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX 26 | 27 | WM_DESTROY = 0x0002 28 | WM_SETICON = 0x0080 29 | WM_MOUSEMOVE = 0x0200 30 | WM_LBUTTONDOWN = 0x0201 31 | WM_LBUTTONUP = 0x0202 32 | WM_LBUTTONDBLCLK = 0x0203 33 | WM_RBUTTONDOWN = 0x0204 34 | WM_RBUTTONUP = 0x0205 35 | WM_RBUTTONDBLCLK = 0x0206 36 | WM_APP = 0x8000 37 | ) 38 | 39 | const ( 40 | NIM_ADD = 0x00000000 41 | NIM_MODIFY = 0x00000001 42 | NIM_DELETE = 0x00000002 43 | NIM_SETFOCUS = 0x00000003 44 | NIM_SETVERSION = 0x00000004 45 | 46 | NIF_MESSAGE = 0x00000001 47 | NIF_ICON = 0x00000002 48 | NIF_TIP = 0x00000004 49 | NIF_STATE = 0x00000008 50 | NIF_INFO = 0x00000010 51 | NIF_GUID = 0x00000020 52 | NIF_REALTIME = 0x00000040 53 | NIF_SHOWTIP = 0x00000080 54 | 55 | NIS_HIDDEN = 0x00000001 56 | NIS_SHAREDICON = 0x00000002 57 | 58 | NIIF_NONE = 0x00000000 59 | NIIF_INFO = 0x00000001 60 | NIIF_WARNING = 0x00000002 61 | NIIF_ERROR = 0x00000003 62 | NIIF_USER = 0x00000004 63 | NIIF_NOSOUND = 0x00000010 64 | NIIF_LARGE_ICON = 0x00000020 65 | NIIF_RESPECT_QUIET_TIME = 0x00000080 66 | NIIF_ICON_MASK = 0x0000000F 67 | 68 | NIN_BALLOONSHOW = 0x0402 69 | NIN_BALLOONTIMEOUT = 0x0404 70 | NIN_BALLOONUSERCLICK = 0x0405 71 | ) 72 | 73 | var ( 74 | libshell32 = windows.NewLazySystemDLL("shell32.dll") 75 | libuser32 = windows.NewLazySystemDLL("user32.dll") 76 | libkernel32 = windows.NewLazySystemDLL("kernel32.dll") 77 | 78 | procShell_NotifyIconW = libshell32.NewProc("Shell_NotifyIconW") 79 | procLoadImageW = libuser32.NewProc("LoadImageW") 80 | procRegisterClassExW = libuser32.NewProc("RegisterClassExW") 81 | procGetModuleHandleW = libkernel32.NewProc("GetModuleHandleW") 82 | procCreateWindowExW = libuser32.NewProc("CreateWindowExW") 83 | procDefWindowProcW = libuser32.NewProc("DefWindowProcW") 84 | procGetMessageW = libuser32.NewProc("GetMessageW") 85 | procTranslateMessage = libuser32.NewProc("TranslateMessage") 86 | procDispatchMessageW = libuser32.NewProc("DispatchMessageW") 87 | procPostQuitMessage = libuser32.NewProc("PostQuitMessage") 88 | procShowWindow = libuser32.NewProc("ShowWindow") 89 | ) 90 | 91 | type MSG struct { 92 | Hwnd uintptr 93 | Message uint32 94 | WParam uintptr 95 | LParam uintptr 96 | Time uint32 97 | Pt POINT 98 | LPrivate uint32 99 | } 100 | 101 | type POINT struct { 102 | X int32 103 | Y int32 104 | } 105 | 106 | type WNDCLASSEX struct { 107 | CbSize uint32 108 | Style uint32 109 | LpfnWndProc uintptr 110 | CbClsExtra int32 111 | CbWndExtra int32 112 | HInstance uintptr 113 | HIcon uintptr 114 | HCursor uintptr 115 | HbrBackground uintptr 116 | LpszMenuName *uint16 117 | LpszClassName *uint16 118 | HIconSm uintptr 119 | } 120 | 121 | type NOTIFYICONDATA struct { 122 | CbSize uint32 123 | HWnd uintptr 124 | UID uint32 125 | UFlags uint32 126 | UCallbackMessage uint32 127 | HIcon uintptr 128 | SzTip [128]uint16 129 | DwState uint32 130 | DwStateMask uint32 131 | SzInfo [256]uint16 132 | UVersion uint32 133 | SzInfoTitle [64]uint16 134 | DwInfoFlags uint32 135 | GUIDItem GUID 136 | HBalloonIcon uintptr 137 | } 138 | 139 | type GUID struct { 140 | Data1 uint32 141 | Data2 uint16 142 | Data3 uint16 143 | Data4 [8]byte 144 | } 145 | 146 | func Shell_NotifyIcon( 147 | dwMessage uint32, 148 | lpData *NOTIFYICONDATA) (int32, error) { 149 | r, _, err := procShell_NotifyIconW.Call( 150 | uintptr(dwMessage), 151 | uintptr(unsafe.Pointer(lpData))) 152 | if r == 0 { 153 | return 0, err 154 | } 155 | return int32(r), nil 156 | } 157 | 158 | func LoadImage( 159 | hInst uintptr, 160 | name *uint16, 161 | type_ uint32, 162 | cx, cy int32, 163 | fuLoad uint32) (uintptr, error) { 164 | r, _, err := procLoadImageW.Call( 165 | hInst, 166 | uintptr(unsafe.Pointer(name)), 167 | uintptr(type_), 168 | uintptr(cx), 169 | uintptr(cy), 170 | uintptr(fuLoad)) 171 | if r == 0 { 172 | return 0, err 173 | } 174 | return r, nil 175 | } 176 | 177 | func GetModuleHandle(lpModuleName *uint16) (uintptr, error) { 178 | r, _, err := procGetModuleHandleW.Call(uintptr(unsafe.Pointer(lpModuleName))) 179 | if r == 0 { 180 | return 0, err 181 | } 182 | return r, nil 183 | } 184 | 185 | func RegisterClassEx(Arg1 *WNDCLASSEX) (uint16, error) { 186 | r, _, err := procRegisterClassExW.Call(uintptr(unsafe.Pointer(Arg1))) 187 | if r == 0 { 188 | return 0, err 189 | } 190 | return uint16(r), nil 191 | } 192 | 193 | func CreateWindowEx( 194 | dwExStyle uint32, 195 | lpClassName, lpWindowName *uint16, 196 | dwStyle uint32, 197 | X, Y, nWidth, nHeight int32, 198 | hWndParent, hMenu, hInstance uintptr, 199 | lpParam unsafe.Pointer) (uintptr, error) { 200 | r, _, err := procCreateWindowExW.Call( 201 | uintptr(dwExStyle), 202 | uintptr(unsafe.Pointer(lpClassName)), 203 | uintptr(unsafe.Pointer(lpWindowName)), 204 | uintptr(dwStyle), 205 | uintptr(X), 206 | uintptr(Y), 207 | uintptr(nWidth), 208 | uintptr(nHeight), 209 | hWndParent, 210 | hMenu, 211 | hInstance, 212 | uintptr(lpParam)) 213 | if r == 0 { 214 | return 0, err 215 | } 216 | return r, nil 217 | } 218 | 219 | func DefWindowProc( 220 | hWnd uintptr, 221 | Msg uint32, 222 | wParam, lParam uintptr) (uintptr, error) { 223 | r, _, _ := procDefWindowProcW.Call( 224 | hWnd, 225 | uintptr(Msg), 226 | wParam, 227 | lParam) 228 | return r, nil 229 | } 230 | 231 | func GetMessage( 232 | lpMsg *MSG, 233 | hWnd uintptr, 234 | uMsgFilterMin, 235 | uMsgFilterMax uint32) (int32, error) { 236 | r, _, err := procGetMessageW.Call( 237 | uintptr(unsafe.Pointer(lpMsg)), 238 | hWnd, 239 | uintptr(uMsgFilterMin), 240 | uintptr(uMsgFilterMax)) 241 | if int32(r) == -1 { 242 | return 0, err 243 | } 244 | return int32(r), nil 245 | } 246 | 247 | func TranslateMessage(lpMsg *MSG) (int32, error) { 248 | r, _, _ := procTranslateMessage.Call(uintptr(unsafe.Pointer(lpMsg))) 249 | return int32(r), nil 250 | } 251 | 252 | func DispatchMessage(lpMsg *MSG) (uintptr, error) { 253 | r, _, _ := procDispatchMessageW.Call(uintptr(unsafe.Pointer(lpMsg))) 254 | return r, nil 255 | } 256 | 257 | func PostQuitMessage(nExitCode int32) { 258 | procPostQuitMessage.Call(uintptr(nExitCode)) 259 | } 260 | 261 | func ShowWindow(hWnd uintptr, nCmdShow int32) (int32, error) { 262 | r, _, err := procShowWindow.Call(hWnd, uintptr(nCmdShow)) 263 | if r == 0 { 264 | return 0, err 265 | } 266 | return int32(r), nil 267 | } 268 | 269 | func LOWORD(dwValue uint32) uint16 { 270 | return uint16(dwValue) 271 | } 272 | -------------------------------------------------------------------------------- /part2/winapi.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "unsafe" 5 | 6 | "golang.org/x/sys/windows" 7 | ) 8 | 9 | const ( 10 | IMAGE_ICON = 1 11 | 12 | LR_DEFAULTSIZE = 0x00000040 13 | LR_LOADFROMFILE = 0x00000010 14 | 15 | SW_SHOW = 5 16 | 17 | CW_USEDEFAULT = ^0x7fffffff 18 | 19 | WS_CAPTION = 0x00c00000 20 | WS_MAXIMIZEBOX = 0x00010000 21 | WS_MINIMIZEBOX = 0x00020000 22 | WS_OVERLAPPED = 0x00000000 23 | WS_SYSMENU = 0x00080000 24 | WS_THICKFRAME = 0x00040000 25 | WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX 26 | 27 | WM_DESTROY = 0x0002 28 | WM_SETICON = 0x0080 29 | WM_MOUSEMOVE = 0x0200 30 | WM_LBUTTONDOWN = 0x0201 31 | WM_LBUTTONUP = 0x0202 32 | WM_LBUTTONDBLCLK = 0x0203 33 | WM_RBUTTONDOWN = 0x0204 34 | WM_RBUTTONUP = 0x0205 35 | WM_RBUTTONDBLCLK = 0x0206 36 | WM_APP = 0x8000 37 | ) 38 | 39 | const ( 40 | NIM_ADD = 0x00000000 41 | NIM_MODIFY = 0x00000001 42 | NIM_DELETE = 0x00000002 43 | NIM_SETFOCUS = 0x00000003 44 | NIM_SETVERSION = 0x00000004 45 | 46 | NIF_MESSAGE = 0x00000001 47 | NIF_ICON = 0x00000002 48 | NIF_TIP = 0x00000004 49 | NIF_STATE = 0x00000008 50 | NIF_INFO = 0x00000010 51 | NIF_GUID = 0x00000020 52 | NIF_REALTIME = 0x00000040 53 | NIF_SHOWTIP = 0x00000080 54 | 55 | NIS_HIDDEN = 0x00000001 56 | NIS_SHAREDICON = 0x00000002 57 | 58 | NIIF_NONE = 0x00000000 59 | NIIF_INFO = 0x00000001 60 | NIIF_WARNING = 0x00000002 61 | NIIF_ERROR = 0x00000003 62 | NIIF_USER = 0x00000004 63 | NIIF_NOSOUND = 0x00000010 64 | NIIF_LARGE_ICON = 0x00000020 65 | NIIF_RESPECT_QUIET_TIME = 0x00000080 66 | NIIF_ICON_MASK = 0x0000000F 67 | 68 | NIN_BALLOONSHOW = 0x0402 69 | NIN_BALLOONTIMEOUT = 0x0404 70 | NIN_BALLOONUSERCLICK = 0x0405 71 | ) 72 | 73 | var ( 74 | libshell32 = windows.NewLazySystemDLL("shell32.dll") 75 | libuser32 = windows.NewLazySystemDLL("user32.dll") 76 | libkernel32 = windows.NewLazySystemDLL("kernel32.dll") 77 | 78 | procShell_NotifyIconW = libshell32.NewProc("Shell_NotifyIconW") 79 | procLoadImageW = libuser32.NewProc("LoadImageW") 80 | procRegisterClassExW = libuser32.NewProc("RegisterClassExW") 81 | procGetModuleHandleW = libkernel32.NewProc("GetModuleHandleW") 82 | procCreateWindowExW = libuser32.NewProc("CreateWindowExW") 83 | procDefWindowProcW = libuser32.NewProc("DefWindowProcW") 84 | procGetMessageW = libuser32.NewProc("GetMessageW") 85 | procTranslateMessage = libuser32.NewProc("TranslateMessage") 86 | procDispatchMessageW = libuser32.NewProc("DispatchMessageW") 87 | procPostQuitMessage = libuser32.NewProc("PostQuitMessage") 88 | procShowWindow = libuser32.NewProc("ShowWindow") 89 | ) 90 | 91 | type MSG struct { 92 | Hwnd uintptr 93 | Message uint32 94 | WParam uintptr 95 | LParam uintptr 96 | Time uint32 97 | Pt POINT 98 | LPrivate uint32 99 | } 100 | 101 | type POINT struct { 102 | X int32 103 | Y int32 104 | } 105 | 106 | type WNDCLASSEX struct { 107 | CbSize uint32 108 | Style uint32 109 | LpfnWndProc uintptr 110 | CbClsExtra int32 111 | CbWndExtra int32 112 | HInstance uintptr 113 | HIcon uintptr 114 | HCursor uintptr 115 | HbrBackground uintptr 116 | LpszMenuName *uint16 117 | LpszClassName *uint16 118 | HIconSm uintptr 119 | } 120 | 121 | type NOTIFYICONDATA struct { 122 | CbSize uint32 123 | HWnd uintptr 124 | UID uint32 125 | UFlags uint32 126 | UCallbackMessage uint32 127 | HIcon uintptr 128 | SzTip [128]uint16 129 | DwState uint32 130 | DwStateMask uint32 131 | SzInfo [256]uint16 132 | UVersion uint32 133 | SzInfoTitle [64]uint16 134 | DwInfoFlags uint32 135 | GUIDItem GUID 136 | HBalloonIcon uintptr 137 | } 138 | 139 | type GUID struct { 140 | Data1 uint32 141 | Data2 uint16 142 | Data3 uint16 143 | Data4 [8]byte 144 | } 145 | 146 | func Shell_NotifyIcon( 147 | dwMessage uint32, 148 | lpData *NOTIFYICONDATA) (int32, error) { 149 | r, _, err := procShell_NotifyIconW.Call( 150 | uintptr(dwMessage), 151 | uintptr(unsafe.Pointer(lpData))) 152 | if r == 0 { 153 | return 0, err 154 | } 155 | return int32(r), nil 156 | } 157 | 158 | func LoadImage( 159 | hInst uintptr, 160 | name *uint16, 161 | type_ uint32, 162 | cx, cy int32, 163 | fuLoad uint32) (uintptr, error) { 164 | r, _, err := procLoadImageW.Call( 165 | hInst, 166 | uintptr(unsafe.Pointer(name)), 167 | uintptr(type_), 168 | uintptr(cx), 169 | uintptr(cy), 170 | uintptr(fuLoad)) 171 | if r == 0 { 172 | return 0, err 173 | } 174 | return r, nil 175 | } 176 | 177 | func GetModuleHandle(lpModuleName *uint16) (uintptr, error) { 178 | r, _, err := procGetModuleHandleW.Call(uintptr(unsafe.Pointer(lpModuleName))) 179 | if r == 0 { 180 | return 0, err 181 | } 182 | return r, nil 183 | } 184 | 185 | func RegisterClassEx(Arg1 *WNDCLASSEX) (uint16, error) { 186 | r, _, err := procRegisterClassExW.Call(uintptr(unsafe.Pointer(Arg1))) 187 | if r == 0 { 188 | return 0, err 189 | } 190 | return uint16(r), nil 191 | } 192 | 193 | func CreateWindowEx( 194 | dwExStyle uint32, 195 | lpClassName, lpWindowName *uint16, 196 | dwStyle uint32, 197 | X, Y, nWidth, nHeight int32, 198 | hWndParent, hMenu, hInstance uintptr, 199 | lpParam unsafe.Pointer) (uintptr, error) { 200 | r, _, err := procCreateWindowExW.Call( 201 | uintptr(dwExStyle), 202 | uintptr(unsafe.Pointer(lpClassName)), 203 | uintptr(unsafe.Pointer(lpWindowName)), 204 | uintptr(dwStyle), 205 | uintptr(X), 206 | uintptr(Y), 207 | uintptr(nWidth), 208 | uintptr(nHeight), 209 | hWndParent, 210 | hMenu, 211 | hInstance, 212 | uintptr(lpParam)) 213 | if r == 0 { 214 | return 0, err 215 | } 216 | return r, nil 217 | } 218 | 219 | func DefWindowProc( 220 | hWnd uintptr, 221 | Msg uint32, 222 | wParam, lParam uintptr) (uintptr, error) { 223 | r, _, _ := procDefWindowProcW.Call( 224 | hWnd, 225 | uintptr(Msg), 226 | wParam, 227 | lParam) 228 | return r, nil 229 | } 230 | 231 | func GetMessage( 232 | lpMsg *MSG, 233 | hWnd uintptr, 234 | uMsgFilterMin, 235 | uMsgFilterMax uint32) (int32, error) { 236 | r, _, err := procGetMessageW.Call( 237 | uintptr(unsafe.Pointer(lpMsg)), 238 | hWnd, 239 | uintptr(uMsgFilterMin), 240 | uintptr(uMsgFilterMax)) 241 | if int32(r) == -1 { 242 | return 0, err 243 | } 244 | return int32(r), nil 245 | } 246 | 247 | func TranslateMessage(lpMsg *MSG) (int32, error) { 248 | r, _, _ := procTranslateMessage.Call(uintptr(unsafe.Pointer(lpMsg))) 249 | return int32(r), nil 250 | } 251 | 252 | func DispatchMessage(lpMsg *MSG) (uintptr, error) { 253 | r, _, _ := procDispatchMessageW.Call(uintptr(unsafe.Pointer(lpMsg))) 254 | return r, nil 255 | } 256 | 257 | func PostQuitMessage(nExitCode int32) { 258 | procPostQuitMessage.Call(uintptr(nExitCode)) 259 | } 260 | 261 | func ShowWindow(hWnd uintptr, nCmdShow int32) (int32, error) { 262 | r, _, err := procShowWindow.Call(hWnd, uintptr(nCmdShow)) 263 | if r == 0 { 264 | return 0, err 265 | } 266 | return int32(r), nil 267 | } 268 | 269 | func LOWORD(dwValue uint32) uint16 { 270 | return uint16(dwValue) 271 | } 272 | --------------------------------------------------------------------------------