//go:build windows package main import ( "bytes" _ "embed" "encoding/binary" "os" "path/filepath" "syscall" "unsafe" ) //go:embed panel_icon.png var panelIconPNG []byte func setWindowIcon(windowPtr unsafe.Pointer) { hwnd := uintptr(windowPtr) if hwnd == 0 { return } // Write a temp ICO file (Windows LoadImage needs a file path) icoData := wrapPNG(panelIconPNG, 64, 64) icoPath := filepath.Join(os.TempDir(), "syncwarden-panel.ico") if err := os.WriteFile(icoPath, icoData, 0644); err != nil { return } user32 := syscall.NewLazyDLL("user32.dll") loadImage := user32.NewProc("LoadImageW") sendMessage := user32.NewProc("SendMessageW") pathW, _ := syscall.UTF16PtrFromString(icoPath) const ( imageIcon = 1 lrLoadFromFile = 0x0010 wmSetIcon = 0x0080 iconBig = 1 iconSmall = 0 ) hBig, _, _ := loadImage.Call(0, uintptr(unsafe.Pointer(pathW)), imageIcon, 32, 32, lrLoadFromFile) if hBig != 0 { sendMessage.Call(hwnd, wmSetIcon, iconBig, hBig) } hSmall, _, _ := loadImage.Call(0, uintptr(unsafe.Pointer(pathW)), imageIcon, 16, 16, lrLoadFromFile) if hSmall != 0 { sendMessage.Call(hwnd, wmSetIcon, iconSmall, hSmall) } } func wrapPNG(pngData []byte, width, height int) []byte { const headerSize = 6 const entrySize = 16 imageOffset := headerSize + entrySize buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, uint16(0)) binary.Write(buf, binary.LittleEndian, uint16(1)) binary.Write(buf, binary.LittleEndian, uint16(1)) w := byte(width) if width >= 256 { w = 0 } h := byte(height) if height >= 256 { h = 0 } buf.WriteByte(w) buf.WriteByte(h) buf.WriteByte(0) buf.WriteByte(0) binary.Write(buf, binary.LittleEndian, uint16(1)) binary.Write(buf, binary.LittleEndian, uint16(32)) binary.Write(buf, binary.LittleEndian, uint32(len(pngData))) binary.Write(buf, binary.LittleEndian, uint32(imageOffset)) buf.Write(pngData) return buf.Bytes() }