Message dialogs improvements (windows).

This commit is contained in:
Nuno Cruces 2020-01-08 00:44:26 +00:00
parent ec8eb571eb
commit fd22f9bf8e
3 changed files with 106 additions and 11 deletions

View file

@ -11,17 +11,9 @@ import (
) )
var ( var (
comdlg32 = syscall.NewLazyDLL("comdlg32.dll")
ole32 = syscall.NewLazyDLL("ole32.dll")
shell32 = syscall.NewLazyDLL("shell32.dll")
getOpenFileName = comdlg32.NewProc("GetOpenFileNameW") getOpenFileName = comdlg32.NewProc("GetOpenFileNameW")
getSaveFileName = comdlg32.NewProc("GetSaveFileNameW") getSaveFileName = comdlg32.NewProc("GetSaveFileNameW")
commDlgExtendedError = comdlg32.NewProc("CommDlgExtendedError") commDlgExtendedError = comdlg32.NewProc("CommDlgExtendedError")
coInitializeEx = ole32.NewProc("CoInitializeEx")
coUninitialize = ole32.NewProc("CoUninitialize")
coCreateInstance = ole32.NewProc("CoCreateInstance")
coTaskMemFree = ole32.NewProc("CoTaskMemFree")
shBrowseForFolder = shell32.NewProc("SHBrowseForFolderW") shBrowseForFolder = shell32.NewProc("SHBrowseForFolderW")
shGetPathFromIDListEx = shell32.NewProc("SHGetPathFromIDListEx") shGetPathFromIDListEx = shell32.NewProc("SHGetPathFromIDListEx")
shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName") shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName")

34
init_windows.go Normal file
View file

@ -0,0 +1,34 @@
package zenity
import "syscall"
var (
comdlg32 = syscall.NewLazyDLL("comdlg32.dll")
kernel32 = syscall.NewLazyDLL("kernel32.dll")
ole32 = syscall.NewLazyDLL("ole32.dll")
shell32 = syscall.NewLazyDLL("shell32.dll")
user32 = syscall.NewLazyDLL("user32.dll")
getCurrentThreadId = kernel32.NewProc("GetCurrentThreadId")
coInitializeEx = ole32.NewProc("CoInitializeEx")
coUninitialize = ole32.NewProc("CoUninitialize")
coCreateInstance = ole32.NewProc("CoCreateInstance")
coTaskMemFree = ole32.NewProc("CoTaskMemFree")
getClassName = user32.NewProc("GetClassNameA")
setWindowsHookEx = user32.NewProc("SetWindowsHookExW")
unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx")
callNextHookEx = user32.NewProc("CallNextHookEx")
enumChildWindows = user32.NewProc("EnumChildWindows")
getDlgCtrlID = user32.NewProc("GetDlgCtrlID")
setWindowText = user32.NewProc("SetWindowTextW")
)
type _CWPRETSTRUCT struct {
Result uintptr
LParam uintptr
WParam uintptr
Message uint32
HWnd uintptr
}

View file

@ -1,12 +1,12 @@
package zenity package zenity
import ( import (
"runtime"
"syscall" "syscall"
"unsafe" "unsafe"
) )
var ( var (
user32 = syscall.NewLazyDLL("user32.dll")
messageBox = user32.NewProc("MessageBoxW") messageBox = user32.NewProc("MessageBoxW")
) )
@ -49,17 +49,86 @@ func message(typ int, text string, options []Option) (bool, error) {
flags |= 0x40 // MB_ICONINFORMATION flags |= 0x40 // MB_ICONINFORMATION
} }
if typ == 2 && opts.defcancel {
if opts.extra == "" {
flags |= 0x100 // MB_DEFBUTTON2
} else {
flags |= 0x200 // MB_DEFBUTTON3
}
}
if opts.title != "" { if opts.title != "" {
caption = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(opts.title))) caption = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(opts.title)))
} }
if opts.ok != "" || opts.cancel != "" || opts.extra != "" {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
hook, err := hookMessageLabels(typ, opts)
if hook == 0 {
return false, err
}
defer unhookWindowsHookEx.Call(hook)
}
n, _, err := messageBox.Call(0, n, _, err := messageBox.Call(0,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
caption, flags) caption, flags)
if n == 0 { if n == 0 {
return false, err return false, err
}
if n == 7 || n == 2 && typ != 2 { // IDNO
return false, ErrExtraButton
}
if n == 1 || n == 6 { // IDOK, IDYES
return true, nil
}
return false, nil
}
func hookMessageLabels(typ int, opts options) (hook uintptr, err error) {
tid, _, _ := getCurrentThreadId.Call()
hook, _, err = setWindowsHookEx.Call(12, // WH_CALLWNDPROCRET
syscall.NewCallback(func(code int, wparam, lparam uintptr) uintptr {
msg := *(*_CWPRETSTRUCT)(unsafe.Pointer(lparam))
if msg.Message == 0x0110 { // WM_INITDIALOG
name := [7]byte{}
n, _, _ := getClassName.Call(msg.HWnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name)))
if string(name[:n]) == "#32770" {
enumChildWindows.Call(msg.HWnd,
syscall.NewCallback(func(hwnd, lparam uintptr) uintptr {
name := [7]byte{}
n, _, _ := getClassName.Call(hwnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name)))
if string(name[:n]) == "Button" {
ctl, _, _ := getDlgCtrlID.Call(hwnd)
var text string
switch ctl {
case 1, 6: // IDOK, IDYES
text = opts.ok
case 2: // IDCANCEL
if typ == 2 {
text = opts.cancel
} else if opts.extra != "" {
text = opts.extra
} else { } else {
return n == 1 /* IDOK */ || n == 6 /* IDYES */, nil text = opts.ok
}
case 7: // IDNO
text = opts.extra
}
if text != "" {
ptr := syscall.StringToUTF16Ptr(text)
setWindowText.Call(hwnd, uintptr(unsafe.Pointer(ptr)))
} }
} }
return 1
}), 0)
}
}
next, _, _ := callNextHookEx.Call(hook, uintptr(code), wparam, lparam)
return next
}), 0, tid)
return
}