2020-01-07 19:44:26 -05:00
|
|
|
package zenity
|
|
|
|
|
2020-01-12 13:55:10 -05:00
|
|
|
import (
|
2020-01-30 09:14:42 -05:00
|
|
|
"context"
|
2020-01-12 13:55:10 -05:00
|
|
|
"fmt"
|
2021-01-05 10:20:42 -05:00
|
|
|
"os"
|
2020-01-30 09:14:42 -05:00
|
|
|
"sync"
|
2020-01-12 13:55:10 -05:00
|
|
|
"syscall"
|
|
|
|
"unsafe"
|
|
|
|
)
|
2020-01-07 19:44:26 -05:00
|
|
|
|
|
|
|
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")
|
2020-01-30 21:18:43 -05:00
|
|
|
wtsapi32 = syscall.NewLazyDLL("wtsapi32.dll")
|
2020-01-07 19:44:26 -05:00
|
|
|
|
2020-01-12 13:55:10 -05:00
|
|
|
commDlgExtendedError = comdlg32.NewProc("CommDlgExtendedError")
|
|
|
|
|
2020-01-07 19:44:26 -05:00
|
|
|
getCurrentThreadId = kernel32.NewProc("GetCurrentThreadId")
|
2021-01-05 10:20:42 -05:00
|
|
|
getConsoleWindow = kernel32.NewProc("GetConsoleWindow")
|
2020-01-07 19:44:26 -05:00
|
|
|
|
|
|
|
coInitializeEx = ole32.NewProc("CoInitializeEx")
|
|
|
|
coUninitialize = ole32.NewProc("CoUninitialize")
|
|
|
|
coCreateInstance = ole32.NewProc("CoCreateInstance")
|
|
|
|
coTaskMemFree = ole32.NewProc("CoTaskMemFree")
|
|
|
|
|
2021-01-05 10:20:42 -05:00
|
|
|
sendMessage = user32.NewProc("SendMessageW")
|
|
|
|
getClassName = user32.NewProc("GetClassNameW")
|
|
|
|
setWindowsHookEx = user32.NewProc("SetWindowsHookExW")
|
|
|
|
unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx")
|
|
|
|
callNextHookEx = user32.NewProc("CallNextHookEx")
|
|
|
|
enumWindows = user32.NewProc("EnumWindows")
|
|
|
|
enumChildWindows = user32.NewProc("EnumChildWindows")
|
|
|
|
getDlgCtrlID = user32.NewProc("GetDlgCtrlID")
|
|
|
|
setWindowText = user32.NewProc("SetWindowTextW")
|
|
|
|
setForegroundWindow = user32.NewProc("SetForegroundWindow")
|
|
|
|
getWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId")
|
2020-01-07 19:44:26 -05:00
|
|
|
)
|
|
|
|
|
2021-01-05 10:20:42 -05:00
|
|
|
func activate() {
|
|
|
|
var hwnd uintptr
|
|
|
|
enumWindows.Call(syscall.NewCallback(func(wnd, lparam uintptr) uintptr {
|
|
|
|
var pid uintptr
|
|
|
|
getWindowThreadProcessId.Call(wnd, uintptr(unsafe.Pointer(&pid)))
|
|
|
|
if int(pid) == os.Getpid() {
|
|
|
|
hwnd = wnd
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return 1
|
|
|
|
}), 0)
|
|
|
|
if hwnd == 0 {
|
|
|
|
hwnd, _, _ = getConsoleWindow.Call()
|
|
|
|
}
|
|
|
|
if hwnd != 0 {
|
|
|
|
setForegroundWindow.Call(hwnd)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-12 13:55:10 -05:00
|
|
|
func commDlgError() error {
|
2020-01-29 09:15:21 -05:00
|
|
|
s, _, _ := commDlgExtendedError.Call()
|
|
|
|
if s == 0 {
|
2020-01-12 13:55:10 -05:00
|
|
|
return nil
|
|
|
|
} else {
|
2020-01-29 09:15:21 -05:00
|
|
|
return fmt.Errorf("Common Dialog error: %x", s)
|
2020-01-12 13:55:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-07 19:44:26 -05:00
|
|
|
type _CWPRETSTRUCT struct {
|
|
|
|
Result uintptr
|
|
|
|
LParam uintptr
|
|
|
|
WParam uintptr
|
|
|
|
Message uint32
|
2020-01-17 07:28:44 -05:00
|
|
|
Wnd uintptr
|
2020-01-07 19:44:26 -05:00
|
|
|
}
|
2020-01-12 13:55:10 -05:00
|
|
|
|
2020-01-30 09:14:42 -05:00
|
|
|
func hookDialog(ctx context.Context, initDialog func(wnd uintptr)) (unhook context.CancelFunc, err error) {
|
|
|
|
if ctx != nil && ctx.Err() != nil {
|
|
|
|
return nil, ctx.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
var mtx sync.Mutex
|
|
|
|
var hook, wnd uintptr
|
2020-01-24 08:59:03 -05:00
|
|
|
tid, _, _ := getCurrentThreadId.Call()
|
|
|
|
hook, _, err = setWindowsHookEx.Call(12, // WH_CALLWNDPROCRET
|
|
|
|
syscall.NewCallback(func(code int, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr {
|
|
|
|
if lparam.Message == 0x0110 { // WM_INITDIALOG
|
2020-01-30 09:14:42 -05:00
|
|
|
name := [8]uint16{}
|
2020-01-24 08:59:03 -05:00
|
|
|
getClassName.Call(lparam.Wnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name)))
|
|
|
|
if syscall.UTF16ToString(name[:]) == "#32770" { // The class for a dialog box
|
2020-01-30 09:14:42 -05:00
|
|
|
var close bool
|
|
|
|
|
|
|
|
mtx.Lock()
|
|
|
|
if ctx != nil && ctx.Err() != nil {
|
|
|
|
close = true
|
|
|
|
} else {
|
|
|
|
wnd = lparam.Wnd
|
|
|
|
}
|
|
|
|
mtx.Unlock()
|
|
|
|
|
|
|
|
if close {
|
|
|
|
sendMessage.Call(lparam.Wnd, 0x0112 /* WM_SYSCOMMAND */, 0xf060 /* SC_CLOSE */, 0)
|
|
|
|
} else if initDialog != nil {
|
|
|
|
initDialog(lparam.Wnd)
|
|
|
|
}
|
2020-01-24 08:59:03 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
next, _, _ := callNextHookEx.Call(hook, uintptr(code), wparam, uintptr(unsafe.Pointer(lparam)))
|
|
|
|
return next
|
|
|
|
}), 0, tid)
|
2020-01-30 09:14:42 -05:00
|
|
|
|
|
|
|
if hook == 0 {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if ctx == nil {
|
|
|
|
return func() { unhookWindowsHookEx.Call(hook) }, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
wait := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
mtx.Lock()
|
|
|
|
w := wnd
|
|
|
|
mtx.Unlock()
|
|
|
|
|
|
|
|
if w != 0 {
|
|
|
|
sendMessage.Call(w, 0x0112 /* WM_SYSCOMMAND */, 0xf060 /* SC_CLOSE */, 0)
|
|
|
|
}
|
|
|
|
case <-wait:
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return func() {
|
|
|
|
unhookWindowsHookEx.Call(hook)
|
|
|
|
close(wait)
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2021-03-03 22:25:45 -05:00
|
|
|
func hookDialogTitle(ctx context.Context, title *string) (unhook context.CancelFunc, err error) {
|
|
|
|
var init func(wnd uintptr)
|
|
|
|
if title != nil {
|
|
|
|
init = func(wnd uintptr) {
|
|
|
|
ptr := syscall.StringToUTF16Ptr(*title)
|
|
|
|
setWindowText.Call(wnd, uintptr(unsafe.Pointer(ptr)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return hookDialog(ctx, init)
|
2020-01-24 08:59:03 -05:00
|
|
|
}
|
|
|
|
|
2020-01-12 13:55:10 -05:00
|
|
|
type _COMObject struct{}
|
|
|
|
|
|
|
|
func (o *_COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
|
|
|
self := uintptr(unsafe.Pointer(o))
|
|
|
|
nargs := uintptr(len(a))
|
|
|
|
switch nargs {
|
|
|
|
case 0:
|
|
|
|
return syscall.Syscall(trap, nargs+1, self, 0, 0)
|
|
|
|
case 1:
|
|
|
|
return syscall.Syscall(trap, nargs+1, self, a[0], 0)
|
|
|
|
case 2:
|
|
|
|
return syscall.Syscall(trap, nargs+1, self, a[0], a[1])
|
|
|
|
default:
|
|
|
|
panic("COM call with too many arguments.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type _IUnknownVtbl struct {
|
|
|
|
QueryInterface uintptr
|
|
|
|
AddRef uintptr
|
|
|
|
Release uintptr
|
|
|
|
}
|