Refactor, docs.
This commit is contained in:
parent
ca9086e859
commit
45800f00aa
5 changed files with 75 additions and 93 deletions
|
@ -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
|
||||
|
|
101
entry_windows.go
101
entry_windows.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue