Refactor, docs.

This commit is contained in:
Nuno Cruces 2021-03-10 14:49:09 +00:00
parent ca9086e859
commit 45800f00aa
5 changed files with 75 additions and 93 deletions

View file

@ -72,6 +72,7 @@ func selectColor(opts options) (color.Color, error) {
return color.RGBA{R: r, G: g, B: b, A: 255}, nil return color.RGBA{R: r, G: g, B: b, A: 255}, nil
} }
// https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-choosecolorw-r1
type _CHOOSECOLORW struct { type _CHOOSECOLORW struct {
StructSize uint32 StructSize uint32
Owner uintptr Owner uintptr

View file

@ -32,13 +32,11 @@ var (
createWindowExW = user32.NewProc("CreateWindowExW") createWindowExW = user32.NewProc("CreateWindowExW")
defWindowProcW = user32.NewProc("DefWindowProcW") defWindowProcW = user32.NewProc("DefWindowProcW")
destroyWindowW = user32.NewProc("DestroyWindow") destroyWindowW = user32.NewProc("DestroyWindow")
dispatchMessageW = user32.NewProc("DispatchMessageW") dispatchMessage = user32.NewProc("DispatchMessageW")
getMessageW = user32.NewProc("GetMessageW")
sendMessageW = user32.NewProc("SendMessageW")
postQuitMessageW = user32.NewProc("PostQuitMessage") postQuitMessageW = user32.NewProc("PostQuitMessage")
registerClassExW = user32.NewProc("RegisterClassExW") registerClassExW = user32.NewProc("RegisterClassExW")
unregisterClassW = user32.NewProc("UnregisterClassW") unregisterClassW = user32.NewProc("UnregisterClassW")
translateMessageW = user32.NewProc("TranslateMessage") translateMessage = user32.NewProc("TranslateMessage")
getWindowTextLengthW = user32.NewProc("GetWindowTextLengthW") getWindowTextLengthW = user32.NewProc("GetWindowTextLengthW")
getWindowTextW = user32.NewProc("GetWindowTextW") getWindowTextW = user32.NewProc("GetWindowTextW")
getWindowLongW = user32.NewProc("GetWindowLongW") getWindowLongW = user32.NewProc("GetWindowLongW")
@ -47,7 +45,7 @@ var (
setWindowPosW = user32.NewProc("SetWindowPos") setWindowPosW = user32.NewProc("SetWindowPos")
showWindowW = user32.NewProc("ShowWindow") showWindowW = user32.NewProc("ShowWindow")
updateWindowW = user32.NewProc("UpdateWindow") updateWindowW = user32.NewProc("UpdateWindow")
isDialogMessageW = user32.NewProc("IsDialogMessageW") isDialogMessage = user32.NewProc("IsDialogMessageW")
getSystemMetricsW = user32.NewProc("GetSystemMetrics") getSystemMetricsW = user32.NewProc("GetSystemMetrics")
systemParametersInfoW = user32.NewProc("SystemParametersInfoW") systemParametersInfoW = user32.NewProc("SystemParametersInfoW")
@ -121,14 +119,14 @@ type wndClassExW struct {
iconSm syscall.Handle iconSm syscall.Handle
} }
// msgW https://msdn.microsoft.com/en-us/library/windows/desktop/ms644958.aspx // https://docs.microsoft.com/en-ie/windows/win32/api/winuser/ns-winuser-msg
type msgW struct { type _MSG struct {
hwnd syscall.Handle Owner syscall.Handle
message uint32 Message uint32
wParam uintptr WParam uintptr
lParam uintptr LParam uintptr
time uint32 Time uint32
pt pointW Pt _POINT
} }
// nonClientMetricsW https://msdn.microsoft.com/en-us/library/windows/desktop/ff729175.aspx // nonClientMetricsW https://msdn.microsoft.com/en-us/library/windows/desktop/ff729175.aspx
@ -168,11 +166,13 @@ type logfontW struct {
lfFaceName [32]uint16 lfFaceName [32]uint16
} }
type pointW struct { // https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-point
type _POINT struct {
x, y int32 x, y int32
} }
type rectW struct { // https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect
type _RECT struct {
left int32 left int32
top int32 top int32
right int32 right int32
@ -231,33 +231,10 @@ func unregisterClass(className string, instance syscall.Handle) bool {
return ret != 0 return ret != 0
} }
func getMessage(msg *msgW, hwnd syscall.Handle, msgFilterMin, msgFilterMax uint32) (bool, error) {
ret, _, err := getMessageW.Call(uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(msgFilterMin), uintptr(msgFilterMax))
if int32(ret) == -1 {
return false, err
}
return int32(ret) != 0, nil
}
func _sendMessage(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) uintptr {
ret, _, _ := sendMessageW.Call(uintptr(hwnd), uintptr(msg), wparam, lparam, 0, 0)
return ret
}
func dispatchMessage(msg *msgW) {
dispatchMessageW.Call(uintptr(unsafe.Pointer(msg)))
}
func postQuitMessage(exitCode int32) { func postQuitMessage(exitCode int32) {
postQuitMessageW.Call(uintptr(exitCode)) postQuitMessageW.Call(uintptr(exitCode))
} }
func translateMessage(msg *msgW) {
translateMessageW.Call(uintptr(unsafe.Pointer(msg)))
}
func getWindowTextLength(hwnd syscall.Handle) int { func getWindowTextLength(hwnd syscall.Handle) int {
ret, _, _ := getWindowTextLengthW.Call(uintptr(hwnd)) ret, _, _ := getWindowTextLengthW.Call(uintptr(hwnd))
return int(ret) return int(ret)
@ -292,7 +269,7 @@ func setWindowLong(hwnd syscall.Handle, index, value int32) int32 {
return int32(ret) return int32(ret)
} }
func getWindowRect(hwnd syscall.Handle, rect *rectW) bool { func getWindowRect(hwnd syscall.Handle, rect *_RECT) bool {
ret, _, _ := getWindowRectW.Call(uintptr(hwnd), uintptr(unsafe.Pointer(rect)), 0) ret, _, _ := getWindowRectW.Call(uintptr(hwnd), uintptr(unsafe.Pointer(rect)), 0)
return ret != 0 return ret != 0
} }
@ -313,18 +290,13 @@ func updateWindow(hwnd syscall.Handle) bool {
return ret != 0 return ret != 0
} }
func isDialogMessage(hwnd syscall.Handle, msg *msgW) bool {
ret, _, _ := isDialogMessageW.Call(uintptr(hwnd), uintptr(unsafe.Pointer(msg)), 0)
return ret != 0
}
func getSystemMetrics(nindex int32) int32 { func getSystemMetrics(nindex int32) int32 {
ret, _, _ := getSystemMetricsW.Call(uintptr(nindex), 0, 0) ret, _, _ := getSystemMetricsW.Call(uintptr(nindex), 0, 0)
return int32(ret) return int32(ret)
} }
func centerWindow(hwnd syscall.Handle) { func centerWindow(hwnd syscall.Handle) {
var rc rectW var rc _RECT
getWindowRect(hwnd, &rc) getWindowRect(hwnd, &rc)
xPos := (getSystemMetrics(smCxScreen) - (rc.right - rc.left)) / 2 xPos := (getSystemMetrics(smCxScreen) - (rc.right - rc.left)) / 2
yPos := (getSystemMetrics(smCyScreen) - (rc.bottom - rc.top)) / 2 yPos := (getSystemMetrics(smCyScreen) - (rc.bottom - rc.top)) / 2
@ -350,25 +322,24 @@ func registerClass(className string, instance syscall.Handle, fn interface{}) er
return err return err
} }
func messageLoop(hwnd syscall.Handle) error { // https://docs.microsoft.com/en-us/windows/win32/winmsg/using-messages-and-message-queues
func messageLoop(hwnd uintptr) error {
for { for {
msg := msgW{} var msg _MSG
gotMessage, err := getMessage(&msg, 0, 0, 0) ret, _, err := getMessage.Call(uintptr(unsafe.Pointer(&msg)), 0, 0, 0)
if err != nil { if int32(ret) == -1 {
return err return err
} }
if ret == 0 {
return nil
}
if gotMessage { ret, _, _ = isDialogMessage.Call(hwnd, uintptr(unsafe.Pointer(&msg)), 0)
if !isDialogMessage(hwnd, &msg) { if ret == 0 {
translateMessage(&msg) translateMessage.Call(uintptr(unsafe.Pointer(&msg)))
dispatchMessage(&msg) dispatchMessage.Call(uintptr(unsafe.Pointer(&msg)))
}
} else {
break
} }
} }
return nil
} }
// editBox displays textedit/inputbox dialog. // editBox displays textedit/inputbox dialog.
@ -433,17 +404,17 @@ func editBox(title, text, defaultText, className string, password bool) (string,
setWindowLong(hwnd, gwlStyle, getWindowLong(hwnd, gwlStyle)^wsMaximizeBox) setWindowLong(hwnd, gwlStyle, getWindowLong(hwnd, gwlStyle)^wsMaximizeBox)
font := getMessageFont() font := getMessageFont()
_sendMessage(hwndText, wmSetFont, font, 0) sendMessage.Call(uintptr(hwndText), wmSetFont, font, 0)
_sendMessage(hwndEdit, wmSetFont, font, 0) sendMessage.Call(uintptr(hwndEdit), wmSetFont, font, 0)
_sendMessage(hwndOK, wmSetFont, font, 0) sendMessage.Call(uintptr(hwndOK), wmSetFont, font, 0)
_sendMessage(hwndCancel, wmSetFont, font, 0) sendMessage.Call(uintptr(hwndCancel), wmSetFont, font, 0)
centerWindow(hwnd) centerWindow(hwnd)
showWindow(hwnd, swShowNormal) showWindow(hwnd, swShowNormal)
updateWindow(hwnd) updateWindow(hwnd)
err = messageLoop(hwnd) err = messageLoop(uintptr(hwnd))
if err != nil { if err != nil {
return out, false, err return out, false, err
} }

View file

@ -208,10 +208,10 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
if int32(hr) < 0 { if int32(hr) < 0 {
return browseForFolder(opts) return browseForFolder(opts)
} }
defer dialog.Call(dialog.vtbl.Release) defer dialog.Call(dialog.Release)
var flgs int var flgs int
hr, _, _ = dialog.Call(dialog.vtbl.GetOptions, uintptr(unsafe.Pointer(&flgs))) hr, _, _ = dialog.Call(dialog.GetOptions, uintptr(unsafe.Pointer(&flgs)))
if int32(hr) < 0 { if int32(hr) < 0 {
return "", nil, syscall.Errno(hr) return "", nil, syscall.Errno(hr)
} }
@ -221,14 +221,14 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
if opts.showHidden { if opts.showHidden {
flgs |= 0x10000000 // FOS_FORCESHOWHIDDEN flgs |= 0x10000000 // FOS_FORCESHOWHIDDEN
} }
hr, _, _ = dialog.Call(dialog.vtbl.SetOptions, uintptr(flgs|0x68)) // FOS_NOCHANGEDIR|FOS_PICKFOLDERS|FOS_FORCEFILESYSTEM hr, _, _ = dialog.Call(dialog.SetOptions, uintptr(flgs|0x68)) // FOS_NOCHANGEDIR|FOS_PICKFOLDERS|FOS_FORCEFILESYSTEM
if int32(hr) < 0 { if int32(hr) < 0 {
return "", nil, syscall.Errno(hr) return "", nil, syscall.Errno(hr)
} }
if opts.title != nil { if opts.title != nil {
ptr := syscall.StringToUTF16Ptr(*opts.title) ptr := syscall.StringToUTF16Ptr(*opts.title)
dialog.Call(dialog.vtbl.SetTitle, uintptr(unsafe.Pointer(ptr))) dialog.Call(dialog.SetTitle, uintptr(unsafe.Pointer(ptr)))
} }
if opts.filename != "" { if opts.filename != "" {
@ -240,8 +240,8 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
uintptr(unsafe.Pointer(&item))) uintptr(unsafe.Pointer(&item)))
if int32(hr) >= 0 && item != nil { if int32(hr) >= 0 && item != nil {
dialog.Call(dialog.vtbl.SetFolder, uintptr(unsafe.Pointer(item))) dialog.Call(dialog.SetFolder, uintptr(unsafe.Pointer(item)))
item.Call(item.vtbl.Release) item.Call(item.Release)
} }
} }
@ -254,7 +254,7 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
} }
activate() activate()
hr, _, _ = dialog.Call(dialog.vtbl.Show, 0) hr, _, _ = dialog.Call(dialog.Show, 0)
if opts.ctx != nil && opts.ctx.Err() != nil { if opts.ctx != nil && opts.ctx.Err() != nil {
return "", nil, opts.ctx.Err() return "", nil, opts.ctx.Err()
} }
@ -271,10 +271,10 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
if int32(hr) < 0 { if int32(hr) < 0 {
return syscall.Errno(hr) return syscall.Errno(hr)
} }
defer item.Call(item.vtbl.Release) defer item.Call(item.Release)
var ptr uintptr var ptr uintptr
hr, _, _ = item.Call(item.vtbl.GetDisplayName, hr, _, _ = item.Call(item.GetDisplayName,
0x80058000, // SIGDN_FILESYSPATH 0x80058000, // SIGDN_FILESYSPATH
uintptr(unsafe.Pointer(&ptr))) uintptr(unsafe.Pointer(&ptr)))
if int32(hr) < 0 { if int32(hr) < 0 {
@ -292,22 +292,22 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
if multi { if multi {
var items *_IShellItemArray var items *_IShellItemArray
hr, _, _ = dialog.Call(dialog.vtbl.GetResults, uintptr(unsafe.Pointer(&items))) hr, _, _ = dialog.Call(dialog.GetResults, uintptr(unsafe.Pointer(&items)))
if int32(hr) < 0 { if int32(hr) < 0 {
return "", nil, syscall.Errno(hr) return "", nil, syscall.Errno(hr)
} }
defer items.Call(items.vtbl.Release) defer items.Call(items.Release)
var count uint32 var count uint32
hr, _, _ = items.Call(items.vtbl.GetCount, uintptr(unsafe.Pointer(&count))) hr, _, _ = items.Call(items.GetCount, uintptr(unsafe.Pointer(&count)))
if int32(hr) < 0 { if int32(hr) < 0 {
return "", nil, syscall.Errno(hr) return "", nil, syscall.Errno(hr)
} }
for i := uintptr(0); i < uintptr(count) && err == nil; i++ { for i := uintptr(0); i < uintptr(count) && err == nil; i++ {
err = shellItemPath(&items._COMObject, items.vtbl.GetItemAt, i) err = shellItemPath(&items._COMObject, items.GetItemAt, i)
} }
} else { } else {
err = shellItemPath(&dialog._COMObject, dialog.vtbl.GetResult) err = shellItemPath(&dialog._COMObject, dialog.GetResult)
} }
return return
} }
@ -387,6 +387,7 @@ func initFilters(filters []FileFilter) []uint16 {
return res return res
} }
// https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamew
type _OPENFILENAME struct { type _OPENFILENAME struct {
StructSize uint32 StructSize uint32
Owner uintptr Owner uintptr
@ -413,6 +414,7 @@ type _OPENFILENAME struct {
FlagsEx uint32 FlagsEx uint32
} }
// https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfow
type _BROWSEINFO struct { type _BROWSEINFO struct {
Owner uintptr Owner uintptr
Root uintptr Root uintptr
@ -424,9 +426,7 @@ type _BROWSEINFO struct {
Image int32 Image int32
} }
func uuid(s string) uintptr { // https://github.com/wine-mirror/wine/blob/master/include/shobjidl.idl
return (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
}
var ( var (
_IID_IShellItem = uuid("\x1e\x6d\x82\x43\x18\xe7\xee\x42\xbc\x55\xa1\xe2\x61\xc3\x7b\xfe") _IID_IShellItem = uuid("\x1e\x6d\x82\x43\x18\xe7\xee\x42\xbc\x55\xa1\xe2\x61\xc3\x7b\xfe")
@ -436,17 +436,17 @@ var (
type _IFileOpenDialog struct { type _IFileOpenDialog struct {
_COMObject _COMObject
vtbl *_IFileOpenDialogVtbl *_IFileOpenDialogVtbl
} }
type _IShellItem struct { type _IShellItem struct {
_COMObject _COMObject
vtbl *_IShellItemVtbl *_IShellItemVtbl
} }
type _IShellItemArray struct { type _IShellItemArray struct {
_COMObject _COMObject
vtbl *_IShellItemArrayVtbl *_IShellItemArrayVtbl
} }
type _IFileOpenDialogVtbl struct { type _IFileOpenDialogVtbl struct {

View file

@ -97,20 +97,21 @@ func wtsMessage(text string, opts options) error {
return nil return nil
} }
// https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataw
type _NOTIFYICONDATA struct { type _NOTIFYICONDATA struct {
StructSize uint32 StructSize uint32
Owner uintptr Wnd uintptr
ID uint32 ID uint32
Flags uint32 Flags uint32
CallbackMessage uint32 CallbackMessage uint32
Icon uintptr Icon uintptr
Tip [128]uint16 Tip [128]uint16 // NOTIFYICONDATAA_V1_SIZE
State uint32 State uint32
StateMask uint32 StateMask uint32
Info [256]uint16 Info [256]uint16
Version uint32 Version uint32
InfoTitle [64]uint16 InfoTitle [64]uint16
InfoFlags uint32 InfoFlags uint32
// GuidItem [16]byte // GuidItem [16]byte // NOTIFYICONDATAA_V2_SIZE
// BalloonIcon uintptr // BalloonIcon syscall.Handle // NOTIFYICONDATAA_V3_SIZE
} }

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"os" "os"
"reflect"
"sync" "sync"
"syscall" "syscall"
"unsafe" "unsafe"
@ -27,6 +28,7 @@ var (
coCreateInstance = ole32.NewProc("CoCreateInstance") coCreateInstance = ole32.NewProc("CoCreateInstance")
coTaskMemFree = ole32.NewProc("CoTaskMemFree") coTaskMemFree = ole32.NewProc("CoTaskMemFree")
getMessage = user32.NewProc("GetMessageW")
sendMessage = user32.NewProc("SendMessageW") sendMessage = user32.NewProc("SendMessageW")
getClassName = user32.NewProc("GetClassNameW") getClassName = user32.NewProc("GetClassNameW")
setWindowsHookEx = user32.NewProc("SetWindowsHookExW") setWindowsHookEx = user32.NewProc("SetWindowsHookExW")
@ -68,6 +70,7 @@ func commDlgError() error {
} }
} }
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cwpretstruct
type _CWPRETSTRUCT struct { type _CWPRETSTRUCT struct {
Result uintptr Result uintptr
LParam uintptr LParam uintptr
@ -149,6 +152,18 @@ func hookDialogTitle(ctx context.Context, title *string) (unhook context.CancelF
return hookDialog(ctx, init) return hookDialog(ctx, init)
} }
// https://github.com/wine-mirror/wine/blob/master/include/unknwn.idl
type _IUnknownVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
}
func uuid(s string) uintptr {
return (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
}
type _COMObject struct{} type _COMObject struct{}
func (o *_COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr error) { func (o *_COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr error) {
@ -165,9 +180,3 @@ func (o *_COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr e
panic("COM call with too many arguments.") panic("COM call with too many arguments.")
} }
} }
type _IUnknownVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
}