diff --git a/internal/win/gdi32.go b/internal/win/gdi32.go index 9dfb75b..933f6f1 100644 --- a/internal/win/gdi32.go +++ b/internal/win/gdi32.go @@ -27,4 +27,4 @@ type LOGFONT struct { //sys CreateFontIndirect(lf *LOGFONT) (font Handle) = gdi32.CreateFontIndirectW //sys DeleteObject(o Handle) (ok bool) = gdi32.DeleteObject -//sys GetDeviceCaps(dc Handle, index int) (cap uintptr) = gdi32.GetDeviceCaps +//sys GetDeviceCaps(dc Handle, index int) (cap int) = gdi32.GetDeviceCaps diff --git a/internal/win/generate.go b/internal/win/generate.go index cd3060a..5a681c8 100644 --- a/internal/win/generate.go +++ b/internal/win/generate.go @@ -1,6 +1,6 @@ //go:build generate //go:generate -command mkwinsyscall go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go -//go:generate mkwinsyscall comctl32.go comdlg32.go gdi32.go ole32.go shell32.go user32.go +//go:generate mkwinsyscall comctl32.go comdlg32.go gdi32.go ole32.go shell32.go user32.go win32.go wtsapi32.go package win diff --git a/internal/win/ole32.go b/internal/win/ole32.go index ea617eb..7be6ded 100644 --- a/internal/win/ole32.go +++ b/internal/win/ole32.go @@ -44,4 +44,4 @@ func (o *COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr er } //sys CoTaskMemFree(address uintptr) = ole32.CoTaskMemFree -//sys CoCreateInstance(clsid uintptr, unkOuter unsafe.Pointer, clsContext int32, iid uintptr, address unsafe.Pointer) (ret error) = ole32.CoCreateInstance +//sys CoCreateInstance(clsid uintptr, unkOuter unsafe.Pointer, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) = ole32.CoCreateInstance diff --git a/internal/win/shell32.go b/internal/win/shell32.go index 97bd834..fb00314 100644 --- a/internal/win/shell32.go +++ b/internal/win/shell32.go @@ -53,6 +53,6 @@ type _IShellItemVtbl struct { } //sys SHBrowseForFolder(bi *BROWSEINFO) (ptr uintptr) = shell32.SHBrowseForFolder -//sys SHCreateItemFromParsingName(path *uint16, bc unsafe.Pointer, iid uintptr, item **IShellItem) (err error) = shell32.SHCreateItemFromParsingName -//sys SHGetPathFromIDListEx(ptr uintptr, path *uint16, pathLen int, opts int) (err error) = shell32.SHGetPathFromIDListEx +//sys SHCreateItemFromParsingName(path *uint16, bc unsafe.Pointer, iid uintptr, item **IShellItem) (res error) = shell32.SHCreateItemFromParsingName +//sys SHGetPathFromIDListEx(ptr uintptr, path *uint16, pathLen int, opts int) (ok bool) = shell32.SHGetPathFromIDListEx //sys ShellNotifyIcon(message uint32, data *NOTIFYICONDATA) (ret int, err error) = shell32.Shell_NotifyIconW diff --git a/internal/win/user32.go b/internal/win/user32.go index 26c94ca..6d1e16b 100644 --- a/internal/win/user32.go +++ b/internal/win/user32.go @@ -32,3 +32,5 @@ const ( func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) { return windows.MessageBox(hwnd, text, caption, boxtype) } + +//sys GetDlgCtrlID(wnd HWND) (ret int) = user32.GetDlgCtrlID diff --git a/internal/win/win32.go b/internal/win/win32.go index ebf0d87..d989756 100644 --- a/internal/win/win32.go +++ b/internal/win/win32.go @@ -7,3 +7,5 @@ import "golang.org/x/sys/windows" type Handle = windows.Handle type HWND = windows.HWND + +//sys RtlGetNtVersionNumbers(major *uint32, minor *uint32, build *uint32) = ntdll.RtlGetNtVersionNumbers diff --git a/internal/win/wtsapi32.go b/internal/win/wtsapi32.go new file mode 100644 index 0000000..5df6f8c --- /dev/null +++ b/internal/win/wtsapi32.go @@ -0,0 +1,10 @@ +//go:build windows + +package win + +const ( + WTS_CURRENT_SERVER_HANDLE = 0 + WTS_CURRENT_SESSION = 0xffffffff +) + +//sys WTSSendMessage(server Handle, sessionID uint32, title *uint16, titleLength int, message *uint16, messageLength int, style uint32, timeout int, response *uint32, wait bool) (err error) = wtsapi32.WTSSendMessageW diff --git a/internal/win/zsyscall_windows.go b/internal/win/zsyscall_windows.go index 66b5cf5..10a1c85 100644 --- a/internal/win/zsyscall_windows.go +++ b/internal/win/zsyscall_windows.go @@ -41,8 +41,11 @@ var ( modcomctl32 = windows.NewLazySystemDLL("comctl32.dll") modcomdlg32 = windows.NewLazySystemDLL("comdlg32.dll") modgdi32 = windows.NewLazySystemDLL("gdi32.dll") + modntdll = windows.NewLazySystemDLL("ntdll.dll") modole32 = windows.NewLazySystemDLL("ole32.dll") modshell32 = windows.NewLazySystemDLL("shell32.dll") + moduser32 = windows.NewLazySystemDLL("user32.dll") + modwtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll") procInitCommonControlsEx = modcomctl32.NewProc("InitCommonControlsEx") procChooseColorW = modcomdlg32.NewProc("ChooseColorW") @@ -52,12 +55,15 @@ var ( procCreateFontIndirectW = modgdi32.NewProc("CreateFontIndirectW") procDeleteObject = modgdi32.NewProc("DeleteObject") procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps") + procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers") procCoCreateInstance = modole32.NewProc("CoCreateInstance") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolder") procSHCreateItemFromParsingName = modshell32.NewProc("SHCreateItemFromParsingName") procSHGetPathFromIDListEx = modshell32.NewProc("SHGetPathFromIDListEx") procShell_NotifyIconW = modshell32.NewProc("Shell_NotifyIconW") + procGetDlgCtrlID = moduser32.NewProc("GetDlgCtrlID") + procWTSSendMessageW = modwtsapi32.NewProc("WTSSendMessageW") ) func InitCommonControlsEx(icc *INITCOMMONCONTROLSEX) (ok bool) { @@ -102,16 +108,21 @@ func DeleteObject(o Handle) (ok bool) { return } -func GetDeviceCaps(dc Handle, index int) (cap uintptr) { +func GetDeviceCaps(dc Handle, index int) (cap int) { r0, _, _ := syscall.Syscall(procGetDeviceCaps.Addr(), 2, uintptr(dc), uintptr(index), 0) - cap = uintptr(r0) + cap = int(r0) return } -func CoCreateInstance(clsid uintptr, unkOuter unsafe.Pointer, clsContext int32, iid uintptr, address unsafe.Pointer) (ret error) { +func RtlGetNtVersionNumbers(major *uint32, minor *uint32, build *uint32) { + syscall.Syscall(procRtlGetNtVersionNumbers.Addr(), 3, uintptr(unsafe.Pointer(major)), uintptr(unsafe.Pointer(minor)), uintptr(unsafe.Pointer(build))) + return +} + +func CoCreateInstance(clsid uintptr, unkOuter unsafe.Pointer, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) { r0, _, _ := syscall.Syscall6(procCoCreateInstance.Addr(), 5, uintptr(clsid), uintptr(unkOuter), uintptr(clsContext), uintptr(iid), uintptr(address), 0) if r0 != 0 { - ret = syscall.Errno(r0) + res = syscall.Errno(r0) } return } @@ -127,19 +138,17 @@ func SHBrowseForFolder(bi *BROWSEINFO) (ptr uintptr) { return } -func SHCreateItemFromParsingName(path *uint16, bc unsafe.Pointer, iid uintptr, item **IShellItem) (err error) { - r1, _, e1 := syscall.Syscall6(procSHCreateItemFromParsingName.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(bc), uintptr(iid), uintptr(unsafe.Pointer(item)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) +func SHCreateItemFromParsingName(path *uint16, bc unsafe.Pointer, iid uintptr, item **IShellItem) (res error) { + r0, _, _ := syscall.Syscall6(procSHCreateItemFromParsingName.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(bc), uintptr(iid), uintptr(unsafe.Pointer(item)), 0, 0) + if r0 != 0 { + res = syscall.Errno(r0) } return } -func SHGetPathFromIDListEx(ptr uintptr, path *uint16, pathLen int, opts int) (err error) { - r1, _, e1 := syscall.Syscall6(procSHGetPathFromIDListEx.Addr(), 4, uintptr(ptr), uintptr(unsafe.Pointer(path)), uintptr(pathLen), uintptr(opts), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } +func SHGetPathFromIDListEx(ptr uintptr, path *uint16, pathLen int, opts int) (ok bool) { + r0, _, _ := syscall.Syscall6(procSHGetPathFromIDListEx.Addr(), 4, uintptr(ptr), uintptr(unsafe.Pointer(path)), uintptr(pathLen), uintptr(opts), 0, 0) + ok = r0 != 0 return } @@ -151,3 +160,21 @@ func ShellNotifyIcon(message uint32, data *NOTIFYICONDATA) (ret int, err error) } return } + +func GetDlgCtrlID(wnd HWND) (ret int) { + r0, _, _ := syscall.Syscall(procGetDlgCtrlID.Addr(), 1, uintptr(wnd), 0, 0) + ret = int(r0) + return +} + +func WTSSendMessage(server Handle, sessionID uint32, title *uint16, titleLength int, message *uint16, messageLength int, style uint32, timeout int, response *uint32, wait bool) (err error) { + var _p0 uint32 + if wait { + _p0 = 1 + } + r1, _, e1 := syscall.Syscall12(procWTSSendMessageW.Addr(), 10, uintptr(server), uintptr(sessionID), uintptr(unsafe.Pointer(title)), uintptr(titleLength), uintptr(unsafe.Pointer(message)), uintptr(messageLength), uintptr(style), uintptr(timeout), uintptr(unsafe.Pointer(response)), uintptr(_p0), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} diff --git a/msg_windows.go b/msg_windows.go index 9ec5fec..8923ca9 100644 --- a/msg_windows.go +++ b/msg_windows.go @@ -8,10 +8,6 @@ import ( "github.com/ncruces/zenity/internal/win" ) -var ( - getDlgCtrlID = user32.NewProc("GetDlgCtrlID") -) - func message(kind messageKind, text string, opts options) error { var flags uint32 @@ -22,6 +18,8 @@ func message(kind messageKind, text string, opts options) error { flags |= win.MB_OKCANCEL case opts.extraButton != nil: flags |= win.MB_YESNO + default: + opts.cancelLabel = opts.okLabel } switch opts.icon { @@ -59,7 +57,7 @@ func message(kind messageKind, text string, opts options) error { defer setup()() if opts.ctx != nil || opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil || opts.icon != nil { - unhook, err := hookMessageDialog(kind, opts) + unhook, err := hookMessageDialog(opts) if err != nil { return err } @@ -89,7 +87,7 @@ func message(kind messageKind, text string, opts options) error { } } -func hookMessageDialog(kind messageKind, opts options) (unhook context.CancelFunc, err error) { +func hookMessageDialog(opts options) (unhook context.CancelFunc, err error) { return hookDialog(opts.ctx, opts.windowIcon, nil, func(wnd uintptr) { enumChildWindows.Call(wnd, syscall.NewCallback(hookMessageDialogCallback), @@ -97,8 +95,8 @@ func hookMessageDialog(kind messageKind, opts options) (unhook context.CancelFun }) } -func hookMessageDialogCallback(wnd uintptr, lparam *options) uintptr { - ctl, _, _ := getDlgCtrlID.Call(wnd) +func hookMessageDialogCallback(wnd win.HWND, lparam *options) uintptr { + ctl := win.GetDlgCtrlID(wnd) var text *string switch ctl { @@ -110,14 +108,14 @@ func hookMessageDialogCallback(wnd uintptr, lparam *options) uintptr { text = lparam.extraButton } if text != nil { - setWindowText.Call(wnd, strptr(*text)) + setWindowText.Call(uintptr(wnd), strptr(*text)) } if ctl == 20 /*IDC_STATIC_OK*/ { icon := getIcon(lparam.icon) if icon.handle != 0 { defer icon.delete() - sendMessage.Call(wnd, _STM_SETICON, icon.handle, 0) + sendMessage.Call(uintptr(wnd), _STM_SETICON, icon.handle, 0) } } return 1 diff --git a/notify_windows.go b/notify_windows.go index 9143cc4..12df65f 100644 --- a/notify_windows.go +++ b/notify_windows.go @@ -11,11 +11,6 @@ import ( "github.com/ncruces/zenity/internal/zenutil" ) -var ( - rtlGetNtVersionNumbers = ntdll.NewProc("RtlGetNtVersionNumbers") - wtsSendMessage = wtsapi32.NewProc("WTSSendMessageW") -) - func notify(text string, opts options) error { if opts.ctx != nil && opts.ctx.Err() != nil { return opts.ctx.Err() @@ -64,10 +59,7 @@ func notify(text string, opts options) error { } var major, minor, build uint32 - rtlGetNtVersionNumbers.Call( - uintptr(unsafe.Pointer(&major)), - uintptr(unsafe.Pointer(&minor)), - uintptr(unsafe.Pointer(&build))) + win.RtlGetNtVersionNumbers(&major, &minor, &build) // On Windows 7 (6.1) and lower, wait up to 10 seconds to clean up. if major < 6 || major == 6 && minor < 2 { @@ -86,7 +78,7 @@ func notify(text string, opts options) error { } func wtsMessage(text string, opts options) error { - var flags uintptr + var flags uint32 switch opts.icon { case ErrorIcon: @@ -113,15 +105,8 @@ func wtsMessage(text string, opts options) error { ptitle := syscall.StringToUTF16(*title) var res uint32 - s, _, err := wtsSendMessage.Call( - 0, // WTS_CURRENT_SERVER_HANDLE - 0xffffffff, // WTS_CURRENT_SESSION - uintptr(unsafe.Pointer(&ptitle[0])), uintptr(2*len(ptitle)), - uintptr(unsafe.Pointer(&ptext[0])), uintptr(2*len(ptext)), - flags, uintptr(timeout), uintptr(unsafe.Pointer(&res)), 0) - - if s == 0 { - return err - } - return nil + return win.WTSSendMessage( + win.WTS_CURRENT_SERVER_HANDLE, win.WTS_CURRENT_SESSION, + &ptitle[0], 2*len(ptitle), &ptext[0], 2*len(ptext), + flags, timeout, &res, false) } diff --git a/util_windows.go b/util_windows.go index 549a5fd..335f662 100644 --- a/util_windows.go +++ b/util_windows.go @@ -18,9 +18,7 @@ import ( var ( kernel32 = windows.NewLazySystemDLL("kernel32.dll") - ntdll = windows.NewLazySystemDLL("ntdll.dll") user32 = windows.NewLazySystemDLL("user32.dll") - wtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll") activateActCtx = kernel32.NewProc("ActivateActCtx") createActCtx = kernel32.NewProc("CreateActCtxW") @@ -261,7 +259,7 @@ func getDPI(wnd uintptr) dpi { if wnd != 0 && getDpiForWindow.Find() == nil { res, _, _ = getDpiForWindow.Call(wnd) } else if dc, _, _ := getWindowDC.Call(wnd); dc != 0 { - res = win.GetDeviceCaps(win.Handle(dc), win.LOGPIXELSY) + res = uintptr(win.GetDeviceCaps(win.Handle(dc), win.LOGPIXELSY)) releaseDC.Call(0, dc) }