mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-14 14:45:49 +01:00
extract taskbar
This commit is contained in:
parent
dabc18f663
commit
800810f092
3 changed files with 124 additions and 96 deletions
|
|
@ -9,8 +9,6 @@ import (
|
|||
"image/color"
|
||||
"image/png"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"github.com/wailsapp/wails/v3/pkg/w32"
|
||||
|
|
@ -19,95 +17,8 @@ import (
|
|||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
var (
|
||||
ole32 = syscall.NewLazyDLL("ole32.dll")
|
||||
coCreateInstance = ole32.NewProc("CoCreateInstance")
|
||||
)
|
||||
|
||||
const (
|
||||
CLSCTX_INPROC_SERVER = 0x1
|
||||
)
|
||||
|
||||
var (
|
||||
CLSID_TaskbarList = syscall.GUID{0x56FDF344, 0xFD6D, 0x11D0, [8]byte{0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
|
||||
IID_ITaskbarList3 = syscall.GUID{0xEA1AFB91, 0x9E28, 0x4B86, [8]byte{0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF}}
|
||||
)
|
||||
|
||||
type ITaskbarList3 struct {
|
||||
lpVtbl *taskbarList3Vtbl
|
||||
}
|
||||
|
||||
type taskbarList3Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
HrInit uintptr
|
||||
AddTab uintptr
|
||||
DeleteTab uintptr
|
||||
ActivateTab uintptr
|
||||
SetActiveAlt uintptr
|
||||
MarkFullscreenWindow uintptr
|
||||
SetProgressValue uintptr
|
||||
SetProgressState uintptr
|
||||
RegisterTab uintptr
|
||||
UnregisterTab uintptr
|
||||
SetTabOrder uintptr
|
||||
SetTabActive uintptr
|
||||
ThumbBarAddButtons uintptr
|
||||
ThumbBarUpdateButtons uintptr
|
||||
ThumbBarSetImageList uintptr
|
||||
SetOverlayIcon uintptr
|
||||
SetThumbnailTooltip uintptr
|
||||
SetThumbnailClip uintptr
|
||||
}
|
||||
|
||||
func newTaskbarList3() (*ITaskbarList3, error) {
|
||||
const COINIT_APARTMENTTHREADED = 0x2
|
||||
|
||||
coInit := ole32.NewProc("CoInitializeEx")
|
||||
if hr, _, _ := coInit.Call(0, COINIT_APARTMENTTHREADED); hr != 0 && hr != 0x1 {
|
||||
return nil, syscall.Errno(hr)
|
||||
}
|
||||
|
||||
var taskbar *ITaskbarList3
|
||||
hr, _, _ := coCreateInstance.Call(
|
||||
uintptr(unsafe.Pointer(&CLSID_TaskbarList)),
|
||||
0,
|
||||
uintptr(CLSCTX_INPROC_SERVER),
|
||||
uintptr(unsafe.Pointer(&IID_ITaskbarList3)),
|
||||
uintptr(unsafe.Pointer(&taskbar)),
|
||||
)
|
||||
|
||||
if hr != 0 {
|
||||
ole32.NewProc("CoUninitialize").Call()
|
||||
return nil, syscall.Errno(hr)
|
||||
}
|
||||
|
||||
if r, _, _ := syscall.SyscallN(taskbar.lpVtbl.HrInit, uintptr(unsafe.Pointer(taskbar))); r != 0 {
|
||||
syscall.SyscallN(taskbar.lpVtbl.Release, uintptr(unsafe.Pointer(taskbar)))
|
||||
ole32.NewProc("CoUninitialize").Call()
|
||||
return nil, syscall.Errno(r)
|
||||
}
|
||||
|
||||
return taskbar, nil
|
||||
}
|
||||
|
||||
func (t *ITaskbarList3) SetOverlayIcon(hwnd syscall.Handle, hIcon syscall.Handle, description *uint16) error {
|
||||
ret, _, _ := syscall.SyscallN(
|
||||
t.lpVtbl.SetOverlayIcon,
|
||||
uintptr(unsafe.Pointer(t)),
|
||||
uintptr(hwnd),
|
||||
uintptr(hIcon),
|
||||
uintptr(unsafe.Pointer(description)),
|
||||
)
|
||||
if ret != 0 {
|
||||
return syscall.Errno(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type windowsBadge struct {
|
||||
taskbar *ITaskbarList3
|
||||
taskbar *w32.ITaskbarList3
|
||||
badgeImg *image.RGBA
|
||||
badgeSize int
|
||||
fontManager *FontManager
|
||||
|
|
@ -147,7 +58,7 @@ func NewWithOptions(options Options) *Service {
|
|||
}
|
||||
|
||||
func (w *windowsBadge) Startup(ctx context.Context, options application.ServiceOptions) error {
|
||||
taskbar, err := newTaskbarList3()
|
||||
taskbar, err := w32.NewTaskbarList3()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -159,8 +70,8 @@ func (w *windowsBadge) Startup(ctx context.Context, options application.ServiceO
|
|||
|
||||
func (w *windowsBadge) Shutdown() error {
|
||||
if w.taskbar != nil {
|
||||
syscall.SyscallN(w.taskbar.lpVtbl.Release, uintptr(unsafe.Pointer(w.taskbar)))
|
||||
ole32.NewProc("CoUninitialize").Call()
|
||||
w.taskbar.Release()
|
||||
w32.CoUninitialize()
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -202,7 +113,7 @@ func (w *windowsBadge) SetBadge(label string) error {
|
|||
}
|
||||
defer w32.DestroyIcon(hicon)
|
||||
|
||||
return w.taskbar.SetOverlayIcon(syscall.Handle(hwnd), syscall.Handle(hicon), nil)
|
||||
return w.taskbar.SetOverlayIcon(hwnd, hicon, nil)
|
||||
}
|
||||
|
||||
func (w *windowsBadge) RemoveBadge() error {
|
||||
|
|
@ -225,7 +136,7 @@ func (w *windowsBadge) RemoveBadge() error {
|
|||
return err
|
||||
}
|
||||
|
||||
return w.taskbar.SetOverlayIcon(syscall.Handle(hwnd), 0, nil)
|
||||
return w.taskbar.SetOverlayIcon(hwnd, 0, nil)
|
||||
}
|
||||
|
||||
func (w *windowsBadge) createBadgeIcon() (w32.HICON, error) {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,10 @@
|
|||
package w32
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/go-webview2/pkg/combridge"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/wailsapp/go-webview2/pkg/combridge"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -19,6 +20,7 @@ var (
|
|||
procCoInitialize = modole32.NewProc("CoInitialize")
|
||||
procOleInitialize = modole32.NewProc("OleInitialize")
|
||||
procCoUninitialize = modole32.NewProc("CoUninitialize")
|
||||
procCoCreateInstance = modole32.NewProc("CoCreateInstance")
|
||||
procCreateStreamOnHGlobal = modole32.NewProc("CreateStreamOnHGlobal")
|
||||
procRegisterDragDrop = modole32.NewProc("RegisterDragDrop")
|
||||
procRevokeDragDrop = modole32.NewProc("RevokeDragDrop")
|
||||
|
|
@ -49,6 +51,26 @@ func CoUninitialize() {
|
|||
procCoUninitialize.Call()
|
||||
}
|
||||
|
||||
func CoCreateInstance(clsid *syscall.GUID, dwClsContext uintptr, riid *syscall.GUID, ppv uintptr) HRESULT {
|
||||
ret, _, _ := procCoCreateInstance.Call(
|
||||
uintptr(unsafe.Pointer(clsid)),
|
||||
0,
|
||||
uintptr(dwClsContext),
|
||||
uintptr(unsafe.Pointer(riid)),
|
||||
uintptr(ppv))
|
||||
|
||||
switch uint32(ret) {
|
||||
case E_INVALIDARG:
|
||||
panic("CoCreateInstance failed with E_INVALIDARG")
|
||||
case E_OUTOFMEMORY:
|
||||
panic("CoCreateInstance failed with E_OUTOFMEMORY")
|
||||
case E_UNEXPECTED:
|
||||
panic("CoCreateInstance failed with E_UNEXPECTED")
|
||||
}
|
||||
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func CreateStreamOnHGlobal(hGlobal HGLOBAL, fDeleteOnRelease bool) *IStream {
|
||||
stream := new(IStream)
|
||||
ret, _, _ := procCreateStreamOnHGlobal.Call(
|
||||
|
|
|
|||
95
v3/pkg/w32/taskbar.go
Normal file
95
v3/pkg/w32/taskbar.go
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
//go:build windows
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
CLSID_TaskbarList = syscall.GUID{Data1: 0x56FDF344, Data2: 0xFD6D, Data3: 0x11D0, Data4: [8]byte{0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
|
||||
IID_ITaskbarList3 = syscall.GUID{Data1: 0xEA1AFB91, Data2: 0x9E28, Data3: 0x4B86, Data4: [8]byte{0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF}}
|
||||
)
|
||||
|
||||
// ITaskbarList3 interface for Windows taskbar functionality
|
||||
type ITaskbarList3 struct {
|
||||
lpVtbl *taskbarList3Vtbl
|
||||
}
|
||||
|
||||
type taskbarList3Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
HrInit uintptr
|
||||
AddTab uintptr
|
||||
DeleteTab uintptr
|
||||
ActivateTab uintptr
|
||||
SetActiveAlt uintptr
|
||||
MarkFullscreenWindow uintptr
|
||||
SetProgressValue uintptr
|
||||
SetProgressState uintptr
|
||||
RegisterTab uintptr
|
||||
UnregisterTab uintptr
|
||||
SetTabOrder uintptr
|
||||
SetTabActive uintptr
|
||||
ThumbBarAddButtons uintptr
|
||||
ThumbBarUpdateButtons uintptr
|
||||
ThumbBarSetImageList uintptr
|
||||
SetOverlayIcon uintptr
|
||||
SetThumbnailTooltip uintptr
|
||||
SetThumbnailClip uintptr
|
||||
}
|
||||
|
||||
// NewTaskbarList3 creates a new instance of ITaskbarList3
|
||||
func NewTaskbarList3() (*ITaskbarList3, error) {
|
||||
const COINIT_APARTMENTTHREADED = 0x2
|
||||
|
||||
if hrInit := CoInitializeEx(COINIT_APARTMENTTHREADED); hrInit != 0 && hrInit != 0x1 {
|
||||
return nil, syscall.Errno(hrInit)
|
||||
}
|
||||
|
||||
var taskbar *ITaskbarList3
|
||||
hr := CoCreateInstance(
|
||||
&CLSID_TaskbarList,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
&IID_ITaskbarList3,
|
||||
uintptr(unsafe.Pointer(&taskbar)),
|
||||
)
|
||||
|
||||
if hr != 0 {
|
||||
CoUninitialize()
|
||||
return nil, syscall.Errno(hr)
|
||||
}
|
||||
|
||||
if r, _, _ := syscall.SyscallN(taskbar.lpVtbl.HrInit, uintptr(unsafe.Pointer(taskbar))); r != 0 {
|
||||
syscall.SyscallN(taskbar.lpVtbl.Release, uintptr(unsafe.Pointer(taskbar)))
|
||||
CoUninitialize()
|
||||
return nil, syscall.Errno(r)
|
||||
}
|
||||
|
||||
return taskbar, nil
|
||||
}
|
||||
|
||||
// SetOverlayIcon sets an overlay icon on the taskbar
|
||||
func (t *ITaskbarList3) SetOverlayIcon(hwnd HWND, hIcon HICON, description *uint16) error {
|
||||
ret, _, _ := syscall.SyscallN(
|
||||
t.lpVtbl.SetOverlayIcon,
|
||||
uintptr(unsafe.Pointer(t)),
|
||||
uintptr(hwnd),
|
||||
uintptr(hIcon),
|
||||
uintptr(unsafe.Pointer(description)),
|
||||
)
|
||||
if ret != 0 {
|
||||
return syscall.Errno(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Release releases the ITaskbarList3 interface
|
||||
func (t *ITaskbarList3) Release() {
|
||||
if t != nil {
|
||||
syscall.SyscallN(t.lpVtbl.Release, uintptr(unsafe.Pointer(t)))
|
||||
CoUninitialize()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue