Skip to content

Commit 800810f

Browse files
committed
extract taskbar
1 parent dabc18f commit 800810f

File tree

3 files changed

+124
-96
lines changed

3 files changed

+124
-96
lines changed

v3/pkg/services/badge/badge_windows.go

+6-95
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import (
99
"image/color"
1010
"image/png"
1111
"os"
12-
"syscall"
13-
"unsafe"
1412

1513
"github.com/wailsapp/wails/v3/pkg/application"
1614
"github.com/wailsapp/wails/v3/pkg/w32"
@@ -19,95 +17,8 @@ import (
1917
"golang.org/x/image/math/fixed"
2018
)
2119

22-
var (
23-
ole32 = syscall.NewLazyDLL("ole32.dll")
24-
coCreateInstance = ole32.NewProc("CoCreateInstance")
25-
)
26-
27-
const (
28-
CLSCTX_INPROC_SERVER = 0x1
29-
)
30-
31-
var (
32-
CLSID_TaskbarList = syscall.GUID{0x56FDF344, 0xFD6D, 0x11D0, [8]byte{0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
33-
IID_ITaskbarList3 = syscall.GUID{0xEA1AFB91, 0x9E28, 0x4B86, [8]byte{0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF}}
34-
)
35-
36-
type ITaskbarList3 struct {
37-
lpVtbl *taskbarList3Vtbl
38-
}
39-
40-
type taskbarList3Vtbl struct {
41-
QueryInterface uintptr
42-
AddRef uintptr
43-
Release uintptr
44-
HrInit uintptr
45-
AddTab uintptr
46-
DeleteTab uintptr
47-
ActivateTab uintptr
48-
SetActiveAlt uintptr
49-
MarkFullscreenWindow uintptr
50-
SetProgressValue uintptr
51-
SetProgressState uintptr
52-
RegisterTab uintptr
53-
UnregisterTab uintptr
54-
SetTabOrder uintptr
55-
SetTabActive uintptr
56-
ThumbBarAddButtons uintptr
57-
ThumbBarUpdateButtons uintptr
58-
ThumbBarSetImageList uintptr
59-
SetOverlayIcon uintptr
60-
SetThumbnailTooltip uintptr
61-
SetThumbnailClip uintptr
62-
}
63-
64-
func newTaskbarList3() (*ITaskbarList3, error) {
65-
const COINIT_APARTMENTTHREADED = 0x2
66-
67-
coInit := ole32.NewProc("CoInitializeEx")
68-
if hr, _, _ := coInit.Call(0, COINIT_APARTMENTTHREADED); hr != 0 && hr != 0x1 {
69-
return nil, syscall.Errno(hr)
70-
}
71-
72-
var taskbar *ITaskbarList3
73-
hr, _, _ := coCreateInstance.Call(
74-
uintptr(unsafe.Pointer(&CLSID_TaskbarList)),
75-
0,
76-
uintptr(CLSCTX_INPROC_SERVER),
77-
uintptr(unsafe.Pointer(&IID_ITaskbarList3)),
78-
uintptr(unsafe.Pointer(&taskbar)),
79-
)
80-
81-
if hr != 0 {
82-
ole32.NewProc("CoUninitialize").Call()
83-
return nil, syscall.Errno(hr)
84-
}
85-
86-
if r, _, _ := syscall.SyscallN(taskbar.lpVtbl.HrInit, uintptr(unsafe.Pointer(taskbar))); r != 0 {
87-
syscall.SyscallN(taskbar.lpVtbl.Release, uintptr(unsafe.Pointer(taskbar)))
88-
ole32.NewProc("CoUninitialize").Call()
89-
return nil, syscall.Errno(r)
90-
}
91-
92-
return taskbar, nil
93-
}
94-
95-
func (t *ITaskbarList3) SetOverlayIcon(hwnd syscall.Handle, hIcon syscall.Handle, description *uint16) error {
96-
ret, _, _ := syscall.SyscallN(
97-
t.lpVtbl.SetOverlayIcon,
98-
uintptr(unsafe.Pointer(t)),
99-
uintptr(hwnd),
100-
uintptr(hIcon),
101-
uintptr(unsafe.Pointer(description)),
102-
)
103-
if ret != 0 {
104-
return syscall.Errno(ret)
105-
}
106-
return nil
107-
}
108-
10920
type windowsBadge struct {
110-
taskbar *ITaskbarList3
21+
taskbar *w32.ITaskbarList3
11122
badgeImg *image.RGBA
11223
badgeSize int
11324
fontManager *FontManager
@@ -147,7 +58,7 @@ func NewWithOptions(options Options) *Service {
14758
}
14859

14960
func (w *windowsBadge) Startup(ctx context.Context, options application.ServiceOptions) error {
150-
taskbar, err := newTaskbarList3()
61+
taskbar, err := w32.NewTaskbarList3()
15162
if err != nil {
15263
return err
15364
}
@@ -159,8 +70,8 @@ func (w *windowsBadge) Startup(ctx context.Context, options application.ServiceO
15970

16071
func (w *windowsBadge) Shutdown() error {
16172
if w.taskbar != nil {
162-
syscall.SyscallN(w.taskbar.lpVtbl.Release, uintptr(unsafe.Pointer(w.taskbar)))
163-
ole32.NewProc("CoUninitialize").Call()
73+
w.taskbar.Release()
74+
w32.CoUninitialize()
16475
}
16576

16677
return nil
@@ -202,7 +113,7 @@ func (w *windowsBadge) SetBadge(label string) error {
202113
}
203114
defer w32.DestroyIcon(hicon)
204115

205-
return w.taskbar.SetOverlayIcon(syscall.Handle(hwnd), syscall.Handle(hicon), nil)
116+
return w.taskbar.SetOverlayIcon(hwnd, hicon, nil)
206117
}
207118

208119
func (w *windowsBadge) RemoveBadge() error {
@@ -225,7 +136,7 @@ func (w *windowsBadge) RemoveBadge() error {
225136
return err
226137
}
227138

228-
return w.taskbar.SetOverlayIcon(syscall.Handle(hwnd), 0, nil)
139+
return w.taskbar.SetOverlayIcon(hwnd, 0, nil)
229140
}
230141

231142
func (w *windowsBadge) createBadgeIcon() (w32.HICON, error) {

v3/pkg/w32/ole32.go

+23-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
package w32
88

99
import (
10-
"github.com/wailsapp/go-webview2/pkg/combridge"
1110
"syscall"
1211
"unsafe"
12+
13+
"github.com/wailsapp/go-webview2/pkg/combridge"
1314
)
1415

1516
var (
@@ -19,6 +20,7 @@ var (
1920
procCoInitialize = modole32.NewProc("CoInitialize")
2021
procOleInitialize = modole32.NewProc("OleInitialize")
2122
procCoUninitialize = modole32.NewProc("CoUninitialize")
23+
procCoCreateInstance = modole32.NewProc("CoCreateInstance")
2224
procCreateStreamOnHGlobal = modole32.NewProc("CreateStreamOnHGlobal")
2325
procRegisterDragDrop = modole32.NewProc("RegisterDragDrop")
2426
procRevokeDragDrop = modole32.NewProc("RevokeDragDrop")
@@ -49,6 +51,26 @@ func CoUninitialize() {
4951
procCoUninitialize.Call()
5052
}
5153

54+
func CoCreateInstance(clsid *syscall.GUID, dwClsContext uintptr, riid *syscall.GUID, ppv uintptr) HRESULT {
55+
ret, _, _ := procCoCreateInstance.Call(
56+
uintptr(unsafe.Pointer(clsid)),
57+
0,
58+
uintptr(dwClsContext),
59+
uintptr(unsafe.Pointer(riid)),
60+
uintptr(ppv))
61+
62+
switch uint32(ret) {
63+
case E_INVALIDARG:
64+
panic("CoCreateInstance failed with E_INVALIDARG")
65+
case E_OUTOFMEMORY:
66+
panic("CoCreateInstance failed with E_OUTOFMEMORY")
67+
case E_UNEXPECTED:
68+
panic("CoCreateInstance failed with E_UNEXPECTED")
69+
}
70+
71+
return HRESULT(ret)
72+
}
73+
5274
func CreateStreamOnHGlobal(hGlobal HGLOBAL, fDeleteOnRelease bool) *IStream {
5375
stream := new(IStream)
5476
ret, _, _ := procCreateStreamOnHGlobal.Call(

v3/pkg/w32/taskbar.go

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//go:build windows
2+
3+
package w32
4+
5+
import (
6+
"syscall"
7+
"unsafe"
8+
)
9+
10+
var (
11+
CLSID_TaskbarList = syscall.GUID{Data1: 0x56FDF344, Data2: 0xFD6D, Data3: 0x11D0, Data4: [8]byte{0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
12+
IID_ITaskbarList3 = syscall.GUID{Data1: 0xEA1AFB91, Data2: 0x9E28, Data3: 0x4B86, Data4: [8]byte{0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF}}
13+
)
14+
15+
// ITaskbarList3 interface for Windows taskbar functionality
16+
type ITaskbarList3 struct {
17+
lpVtbl *taskbarList3Vtbl
18+
}
19+
20+
type taskbarList3Vtbl struct {
21+
QueryInterface uintptr
22+
AddRef uintptr
23+
Release uintptr
24+
HrInit uintptr
25+
AddTab uintptr
26+
DeleteTab uintptr
27+
ActivateTab uintptr
28+
SetActiveAlt uintptr
29+
MarkFullscreenWindow uintptr
30+
SetProgressValue uintptr
31+
SetProgressState uintptr
32+
RegisterTab uintptr
33+
UnregisterTab uintptr
34+
SetTabOrder uintptr
35+
SetTabActive uintptr
36+
ThumbBarAddButtons uintptr
37+
ThumbBarUpdateButtons uintptr
38+
ThumbBarSetImageList uintptr
39+
SetOverlayIcon uintptr
40+
SetThumbnailTooltip uintptr
41+
SetThumbnailClip uintptr
42+
}
43+
44+
// NewTaskbarList3 creates a new instance of ITaskbarList3
45+
func NewTaskbarList3() (*ITaskbarList3, error) {
46+
const COINIT_APARTMENTTHREADED = 0x2
47+
48+
if hrInit := CoInitializeEx(COINIT_APARTMENTTHREADED); hrInit != 0 && hrInit != 0x1 {
49+
return nil, syscall.Errno(hrInit)
50+
}
51+
52+
var taskbar *ITaskbarList3
53+
hr := CoCreateInstance(
54+
&CLSID_TaskbarList,
55+
CLSCTX_INPROC_SERVER,
56+
&IID_ITaskbarList3,
57+
uintptr(unsafe.Pointer(&taskbar)),
58+
)
59+
60+
if hr != 0 {
61+
CoUninitialize()
62+
return nil, syscall.Errno(hr)
63+
}
64+
65+
if r, _, _ := syscall.SyscallN(taskbar.lpVtbl.HrInit, uintptr(unsafe.Pointer(taskbar))); r != 0 {
66+
syscall.SyscallN(taskbar.lpVtbl.Release, uintptr(unsafe.Pointer(taskbar)))
67+
CoUninitialize()
68+
return nil, syscall.Errno(r)
69+
}
70+
71+
return taskbar, nil
72+
}
73+
74+
// SetOverlayIcon sets an overlay icon on the taskbar
75+
func (t *ITaskbarList3) SetOverlayIcon(hwnd HWND, hIcon HICON, description *uint16) error {
76+
ret, _, _ := syscall.SyscallN(
77+
t.lpVtbl.SetOverlayIcon,
78+
uintptr(unsafe.Pointer(t)),
79+
uintptr(hwnd),
80+
uintptr(hIcon),
81+
uintptr(unsafe.Pointer(description)),
82+
)
83+
if ret != 0 {
84+
return syscall.Errno(ret)
85+
}
86+
return nil
87+
}
88+
89+
// Release releases the ITaskbarList3 interface
90+
func (t *ITaskbarList3) Release() {
91+
if t != nil {
92+
syscall.SyscallN(t.lpVtbl.Release, uintptr(unsafe.Pointer(t)))
93+
CoUninitialize()
94+
}
95+
}

0 commit comments

Comments
 (0)