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
}
// https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-choosecolorw-r1
type _CHOOSECOLORW struct {
StructSize uint32
Owner uintptr

View file

@ -32,13 +32,11 @@ var (
createWindowExW = user32.NewProc("CreateWindowExW")
defWindowProcW = user32.NewProc("DefWindowProcW")
destroyWindowW = user32.NewProc("DestroyWindow")
dispatchMessageW = user32.NewProc("DispatchMessageW")
getMessageW = user32.NewProc("GetMessageW")
sendMessageW = user32.NewProc("SendMessageW")
dispatchMessage = user32.NewProc("DispatchMessageW")
postQuitMessageW = user32.NewProc("PostQuitMessage")
registerClassExW = user32.NewProc("RegisterClassExW")
unregisterClassW = user32.NewProc("UnregisterClassW")
translateMessageW = user32.NewProc("TranslateMessage")
translateMessage = user32.NewProc("TranslateMessage")
getWindowTextLengthW = user32.NewProc("GetWindowTextLengthW")
getWindowTextW = user32.NewProc("GetWindowTextW")
getWindowLongW = user32.NewProc("GetWindowLongW")
@ -47,7 +45,7 @@ var (
setWindowPosW = user32.NewProc("SetWindowPos")
showWindowW = user32.NewProc("ShowWindow")
updateWindowW = user32.NewProc("UpdateWindow")
isDialogMessageW = user32.NewProc("IsDialogMessageW")
isDialogMessage = user32.NewProc("IsDialogMessageW")
getSystemMetricsW = user32.NewProc("GetSystemMetrics")
systemParametersInfoW = user32.NewProc("SystemParametersInfoW")
@ -121,14 +119,14 @@ type wndClassExW struct {
iconSm syscall.Handle
}
// msgW https://msdn.microsoft.com/en-us/library/windows/desktop/ms644958.aspx
type msgW struct {
hwnd syscall.Handle
message uint32
wParam uintptr
lParam uintptr
time uint32
pt pointW
// https://docs.microsoft.com/en-ie/windows/win32/api/winuser/ns-winuser-msg
type _MSG struct {
Owner syscall.Handle
Message uint32
WParam uintptr
LParam uintptr
Time uint32
Pt _POINT
}
// nonClientMetricsW https://msdn.microsoft.com/en-us/library/windows/desktop/ff729175.aspx
@ -168,11 +166,13 @@ type logfontW struct {
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
}
type rectW struct {
// https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect
type _RECT struct {
left int32
top int32
right int32
@ -231,33 +231,10 @@ func unregisterClass(className string, instance syscall.Handle) bool {
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) {
postQuitMessageW.Call(uintptr(exitCode))
}
func translateMessage(msg *msgW) {
translateMessageW.Call(uintptr(unsafe.Pointer(msg)))
}
func getWindowTextLength(hwnd syscall.Handle) int {
ret, _, _ := getWindowTextLengthW.Call(uintptr(hwnd))
return int(ret)
@ -292,7 +269,7 @@ func setWindowLong(hwnd syscall.Handle, index, value int32) int32 {
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)
return ret != 0
}
@ -313,18 +290,13 @@ func updateWindow(hwnd syscall.Handle) bool {
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 {
ret, _, _ := getSystemMetricsW.Call(uintptr(nindex), 0, 0)
return int32(ret)
}
func centerWindow(hwnd syscall.Handle) {
var rc rectW
var rc _RECT
getWindowRect(hwnd, &rc)
xPos := (getSystemMetrics(smCxScreen) - (rc.right - rc.left)) / 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
}
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 {
msg := msgW{}
gotMessage, err := getMessage(&msg, 0, 0, 0)
if err != nil {
var msg _MSG
ret, _, err := getMessage.Call(uintptr(unsafe.Pointer(&msg)), 0, 0, 0)
if int32(ret) == -1 {
return err
}
if gotMessage {
if !isDialogMessage(hwnd, &msg) {
translateMessage(&msg)
dispatchMessage(&msg)
}
} else {
break
}
}
if ret == 0 {
return nil
}
ret, _, _ = isDialogMessage.Call(hwnd, uintptr(unsafe.Pointer(&msg)), 0)
if ret == 0 {
translateMessage.Call(uintptr(unsafe.Pointer(&msg)))
dispatchMessage.Call(uintptr(unsafe.Pointer(&msg)))
}
}
}
// 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)
font := getMessageFont()
_sendMessage(hwndText, wmSetFont, font, 0)
_sendMessage(hwndEdit, wmSetFont, font, 0)
_sendMessage(hwndOK, wmSetFont, font, 0)
_sendMessage(hwndCancel, wmSetFont, font, 0)
sendMessage.Call(uintptr(hwndText), wmSetFont, font, 0)
sendMessage.Call(uintptr(hwndEdit), wmSetFont, font, 0)
sendMessage.Call(uintptr(hwndOK), wmSetFont, font, 0)
sendMessage.Call(uintptr(hwndCancel), wmSetFont, font, 0)
centerWindow(hwnd)
showWindow(hwnd, swShowNormal)
updateWindow(hwnd)
err = messageLoop(hwnd)
err = messageLoop(uintptr(hwnd))
if err != nil {
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 {
return browseForFolder(opts)
}
defer dialog.Call(dialog.vtbl.Release)
defer dialog.Call(dialog.Release)
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 {
return "", nil, syscall.Errno(hr)
}
@ -221,14 +221,14 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
if opts.showHidden {
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 {
return "", nil, syscall.Errno(hr)
}
if opts.title != nil {
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 != "" {
@ -240,8 +240,8 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
uintptr(unsafe.Pointer(&item)))
if int32(hr) >= 0 && item != nil {
dialog.Call(dialog.vtbl.SetFolder, uintptr(unsafe.Pointer(item)))
item.Call(item.vtbl.Release)
dialog.Call(dialog.SetFolder, uintptr(unsafe.Pointer(item)))
item.Call(item.Release)
}
}
@ -254,7 +254,7 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
}
activate()
hr, _, _ = dialog.Call(dialog.vtbl.Show, 0)
hr, _, _ = dialog.Call(dialog.Show, 0)
if opts.ctx != nil && opts.ctx.Err() != nil {
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 {
return syscall.Errno(hr)
}
defer item.Call(item.vtbl.Release)
defer item.Call(item.Release)
var ptr uintptr
hr, _, _ = item.Call(item.vtbl.GetDisplayName,
hr, _, _ = item.Call(item.GetDisplayName,
0x80058000, // SIGDN_FILESYSPATH
uintptr(unsafe.Pointer(&ptr)))
if int32(hr) < 0 {
@ -292,22 +292,22 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
if multi {
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 {
return "", nil, syscall.Errno(hr)
}
defer items.Call(items.vtbl.Release)
defer items.Call(items.Release)
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 {
return "", nil, syscall.Errno(hr)
}
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 {
err = shellItemPath(&dialog._COMObject, dialog.vtbl.GetResult)
err = shellItemPath(&dialog._COMObject, dialog.GetResult)
}
return
}
@ -387,6 +387,7 @@ func initFilters(filters []FileFilter) []uint16 {
return res
}
// https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamew
type _OPENFILENAME struct {
StructSize uint32
Owner uintptr
@ -413,6 +414,7 @@ type _OPENFILENAME struct {
FlagsEx uint32
}
// https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfow
type _BROWSEINFO struct {
Owner uintptr
Root uintptr
@ -424,9 +426,7 @@ type _BROWSEINFO struct {
Image int32
}
func uuid(s string) uintptr {
return (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
}
// https://github.com/wine-mirror/wine/blob/master/include/shobjidl.idl
var (
_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 {
_COMObject
vtbl *_IFileOpenDialogVtbl
*_IFileOpenDialogVtbl
}
type _IShellItem struct {
_COMObject
vtbl *_IShellItemVtbl
*_IShellItemVtbl
}
type _IShellItemArray struct {
_COMObject
vtbl *_IShellItemArrayVtbl
*_IShellItemArrayVtbl
}
type _IFileOpenDialogVtbl struct {

View file

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

View file

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"reflect"
"sync"
"syscall"
"unsafe"
@ -27,6 +28,7 @@ var (
coCreateInstance = ole32.NewProc("CoCreateInstance")
coTaskMemFree = ole32.NewProc("CoTaskMemFree")
getMessage = user32.NewProc("GetMessageW")
sendMessage = user32.NewProc("SendMessageW")
getClassName = user32.NewProc("GetClassNameW")
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 {
Result uintptr
LParam uintptr
@ -149,6 +152,18 @@ func hookDialogTitle(ctx context.Context, title *string) (unhook context.CancelF
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{}
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.")
}
}
type _IUnknownVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
}