Skip to content

Commit 36688f6

Browse files
committed
add gui/notifyicon example
also update win package
1 parent 3c3d7cf commit 36688f6

File tree

7 files changed

+335
-11
lines changed

7 files changed

+335
-11
lines changed

example/gui/notifyicon/icon.ico

162 KB
Binary file not shown.

example/gui/notifyicon/main.go

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"unsafe"
6+
7+
"github.com/hallazzang/go-windows-programming/pkg/win"
8+
"golang.org/x/sys/windows"
9+
)
10+
11+
func wndProc(hWnd uintptr, msg uint32, wParam, lParam uintptr) uintptr {
12+
switch msg {
13+
case notifyIconMsg:
14+
switch nmsg := win.LOWORD(uint32(lParam)); nmsg {
15+
case win.NIN_BALLOONUSERCLICK:
16+
log.Print("User has clicked the balloon message")
17+
case win.WM_LBUTTONDOWN:
18+
clickHandler()
19+
}
20+
case win.WM_DESTROY:
21+
win.PostQuitMessage(0)
22+
default:
23+
return win.DefWindowProc(hWnd, msg, wParam, lParam)
24+
}
25+
return 0
26+
}
27+
28+
func createMainWindow() (uintptr, error) {
29+
hInstance := win.GetModuleHandle(nil)
30+
31+
wndClass := windows.StringToUTF16Ptr("MyWindow")
32+
33+
var wcex win.WNDCLASSEX
34+
wcex.CbSize = uint32(unsafe.Sizeof(wcex))
35+
wcex.Style = win.CS_HREDRAW | win.CS_VREDRAW
36+
wcex.LpfnWndProc = windows.NewCallback(wndProc)
37+
wcex.HInstance = hInstance
38+
wcex.HbrBackground = win.COLOR_WINDOW + 1
39+
wcex.LpszClassName = wndClass
40+
if win.RegisterClassEx(&wcex) == 0 {
41+
return 0, win.GetLastError()
42+
}
43+
44+
hwnd := win.CreateWindowEx(0, wndClass, windows.StringToUTF16Ptr("NotifyIcon Example"), win.WS_OVERLAPPEDWINDOW, win.CW_USEDEFAULT, win.CW_USEDEFAULT, 400, 300, 0, 0, hInstance, nil)
45+
if hwnd == win.NULL {
46+
return 0, win.GetLastError()
47+
}
48+
win.ShowWindow(hwnd, win.SW_SHOW)
49+
50+
return hwnd, nil
51+
}
52+
53+
func loadIcon(name string) (uintptr, error) {
54+
pname, err := windows.UTF16PtrFromString(name)
55+
if err != nil {
56+
return 0, err
57+
}
58+
59+
hIcon := win.LoadImage(win.NULL, pname, win.IMAGE_ICON, 0, 0, win.LR_DEFAULTSIZE|win.LR_LOADFROMFILE)
60+
if hIcon == win.NULL {
61+
return 0, win.GetLastError()
62+
}
63+
64+
return hIcon, nil
65+
}
66+
67+
func clickHandler() {
68+
log.Print("User has clicked the notify icon")
69+
}
70+
71+
func main() {
72+
hwnd, err := createMainWindow()
73+
if err != nil {
74+
panic(err)
75+
}
76+
77+
hIcon, err := loadIcon("icon.ico")
78+
defer win.DestroyIcon(hIcon)
79+
80+
win.SendMessage(hwnd, win.WM_SETICON, win.ICON_BIG, hIcon)
81+
win.SendMessage(hwnd, win.WM_SETICON, win.ICON_SMALL, hIcon)
82+
83+
ni, err := newNotifyIcon(hwnd)
84+
if err != nil {
85+
panic(err)
86+
}
87+
defer ni.Dispose()
88+
89+
ni.SetIcon(hIcon)
90+
ni.SetTooltip("NotifyIcon Example")
91+
ni.ShowNotification("Hello", "NotifyIcon!")
92+
93+
var msg win.MSG
94+
for win.GetMessage(&msg, 0, 0, 0) != 0 {
95+
win.TranslateMessage(&msg)
96+
win.DispatchMessage(&msg)
97+
}
98+
}

example/gui/notifyicon/notifyicon.go

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"math/rand"
6+
"time"
7+
"unsafe"
8+
9+
"github.com/hallazzang/go-windows-programming/pkg/win"
10+
"golang.org/x/sys/windows"
11+
)
12+
13+
const notifyIconMsg = win.WM_APP + 1
14+
15+
var errShellNotifyIcon = errors.New("Shell_NotifyIcon error")
16+
17+
func init() {
18+
rand.Seed(time.Now().UnixNano())
19+
}
20+
21+
type notifyIcon struct {
22+
hwnd uintptr
23+
guid win.GUID
24+
}
25+
26+
func newNotifyIcon(hwnd uintptr) (*notifyIcon, error) {
27+
ni := &notifyIcon{
28+
hwnd: hwnd,
29+
guid: newGUID(),
30+
}
31+
data := ni.newData()
32+
data.UFlags |= win.NIF_MESSAGE
33+
data.UCallbackMessage = notifyIconMsg
34+
if win.Shell_NotifyIcon(win.NIM_ADD, data) == win.FALSE {
35+
return nil, errShellNotifyIcon
36+
}
37+
return ni, nil
38+
}
39+
40+
func (ni *notifyIcon) Dispose() {
41+
win.Shell_NotifyIcon(win.NIM_DELETE, ni.newData())
42+
}
43+
44+
func (ni *notifyIcon) SetTooltip(tooltip string) error {
45+
data := ni.newData()
46+
data.UFlags |= win.NIF_TIP
47+
copy(data.SzTip[:], windows.StringToUTF16(tooltip))
48+
if win.Shell_NotifyIcon(win.NIM_MODIFY, data) == win.FALSE {
49+
return errShellNotifyIcon
50+
}
51+
return nil
52+
}
53+
54+
func (ni *notifyIcon) SetIcon(hIcon uintptr) error {
55+
data := ni.newData()
56+
data.UFlags |= win.NIF_ICON
57+
data.HIcon = hIcon
58+
if win.Shell_NotifyIcon(win.NIM_MODIFY, data) == win.FALSE {
59+
return errShellNotifyIcon
60+
}
61+
return nil
62+
}
63+
64+
func (ni *notifyIcon) ShowNotification(title, text string) error {
65+
data := ni.newData()
66+
data.UFlags |= win.NIF_INFO
67+
copy(data.SzInfoTitle[:], windows.StringToUTF16(title))
68+
copy(data.SzInfo[:], windows.StringToUTF16(text))
69+
if win.Shell_NotifyIcon(win.NIM_MODIFY, data) == win.FALSE {
70+
return errShellNotifyIcon
71+
}
72+
return nil
73+
}
74+
75+
func (ni *notifyIcon) newData() *win.NOTIFYICONDATA {
76+
var nid win.NOTIFYICONDATA
77+
nid.CbSize = uint32(unsafe.Sizeof(nid))
78+
nid.UFlags = win.NIF_GUID
79+
nid.HWnd = ni.hwnd
80+
nid.GuidItem = ni.guid
81+
return &nid
82+
}
83+
84+
func newGUID() win.GUID {
85+
var buf [16]byte
86+
rand.Read(buf[:])
87+
return *(*win.GUID)(unsafe.Pointer(&buf[0]))
88+
}

pkg/win/constant.go

+75-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
package win
22

3+
const (
4+
NULL = 0
5+
6+
TRUE = BOOL(1)
7+
FALSE = BOOL(0)
8+
)
9+
310
// GetSysColor constants
411
const (
512
COLOR_WINDOW = 5
@@ -15,6 +22,12 @@ const (
1522
CW_USEDEFAULT = ^0x7fffffff
1623
)
1724

25+
// WM_SETICON constants
26+
const (
27+
ICON_BIG = 1
28+
ICON_SMALL = 0
29+
)
30+
1831
// LoadCursor constants
1932
const (
2033
IDC_ARROW = 32512
@@ -25,6 +38,58 @@ const (
2538
IDI_APPLICATION = 32512
2639
)
2740

41+
// LoadImage constants
42+
const (
43+
IMAGE_BITMAP = 0
44+
IMAGE_CURSOR = 2
45+
IMAGE_ICON = 1
46+
47+
LR_CREATEDIBSECTION = 0x00002000
48+
LR_DEFAULTCOLOR = 0x00000000
49+
LR_DEFAULTSIZE = 0x00000040
50+
LR_LOADFROMFILE = 0x00000010
51+
LR_LOADMAP3DCOLORS = 0x00001000
52+
LR_LOADTRANSPARENT = 0x00000020
53+
LR_MONOCHROME = 0x00000001
54+
LR_SHARED = 0x00008000
55+
LR_VGACOLOR = 0x00000080
56+
)
57+
58+
// NotifyIcon constants
59+
const (
60+
NIM_ADD = 0x00000000
61+
NIM_MODIFY = 0x00000001
62+
NIM_DELETE = 0x00000002
63+
NIM_SETFOCUS = 0x00000003
64+
NIM_SETVERSION = 0x00000004
65+
66+
NIF_MESSAGE = 0x00000001
67+
NIF_ICON = 0x00000002
68+
NIF_TIP = 0x00000004
69+
NIF_STATE = 0x00000008
70+
NIF_INFO = 0x00000010
71+
NIF_GUID = 0x00000020
72+
NIF_REALTIME = 0x00000040
73+
NIF_SHOWTIP = 0x00000080
74+
75+
NIS_HIDDEN = 0x00000001
76+
NIS_SHAREDICON = 0x00000002
77+
78+
NIIF_NONE = 0x00000000
79+
NIIF_INFO = 0x00000001
80+
NIIF_WARNING = 0x00000002
81+
NIIF_ERROR = 0x00000003
82+
NIIF_USER = 0x00000004
83+
NIIF_NOSOUND = 0x00000010
84+
NIIF_LARGE_ICON = 0x00000020
85+
NIIF_RESPECT_QUIET_TIME = 0x00000080
86+
NIIF_ICON_MASK = 0x0000000F
87+
88+
NIN_BALLOONSHOW = 0x0402
89+
NIN_BALLOONTIMEOUT = 0x0404
90+
NIN_BALLOONUSERCLICK = 0x0405
91+
)
92+
2893
// ShowWindow constants
2994
const (
3095
SW_HIDE = 0
@@ -35,7 +100,16 @@ const (
35100

36101
// Window messages
37102
const (
38-
WM_DESTROY = 0x0002
103+
WM_DESTROY = 0x0002
104+
WM_SETICON = 0x0080
105+
WM_MOUSEMOVE = 0x0200
106+
WM_LBUTTONDOWN = 0x0201
107+
WM_LBUTTONUP = 0x0202
108+
WM_LBUTTONDBLCLK = 0x0203
109+
WM_RBUTTONDOWN = 0x0204
110+
WM_RBUTTONUP = 0x0205
111+
WM_RBUTTONDBLCLK = 0x0206
112+
WM_APP = 0x8000
39113
)
40114

41115
// Window styles

pkg/win/macro.go

+8
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,11 @@ import "unsafe"
55
func MAKEINTRESOURCE(i uintptr) *uint16 {
66
return (*uint16)(unsafe.Pointer(i))
77
}
8+
9+
func LOWORD(dwValue uint32) uint16 {
10+
return uint16(dwValue)
11+
}
12+
13+
func HIWORD(dwValue uint32) uint16 {
14+
return uint16((dwValue >> 16) & 0xffff)
15+
}

pkg/win/type.go

+27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
package win
22

3+
type BOOL int32
4+
5+
type GUID struct {
6+
Data1 uint32
7+
Data2 uint16
8+
Data3 uint16
9+
Data4 [8]byte
10+
}
11+
312
type MSG struct {
413
Hwnd uintptr
514
Message uint32
@@ -10,6 +19,24 @@ type MSG struct {
1019
LPrivate uint32
1120
}
1221

22+
type NOTIFYICONDATA struct {
23+
CbSize uint32
24+
HWnd uintptr
25+
UID uint32
26+
UFlags uint32
27+
UCallbackMessage uint32
28+
HIcon uintptr
29+
SzTip [128]uint16
30+
DwState uint32
31+
DwStateMask uint32
32+
SzInfo [256]uint16
33+
UVersion uint32
34+
SzInfoTitle [64]uint16
35+
DwInfoFlags uint32
36+
GuidItem GUID
37+
HBalloonIcon uintptr
38+
}
39+
1340
type POINT struct {
1441
X int32
1542
Y int32

0 commit comments

Comments
 (0)