From 4bfddad741285b0a918de7e752158f474bc89058 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Sun, 19 Jun 2022 00:48:38 +0100 Subject: [PATCH] Refactor (windows). --- internal/win/generate.go | 2 +- internal/win/kernel32.go | 11 ++++++++ internal/win/user32.go | 4 +++ internal/win/zsyscall_windows.go | 18 +++++++++++++ util_windows.go | 45 ++++++++++++++------------------ 5 files changed, 54 insertions(+), 26 deletions(-) create mode 100644 internal/win/kernel32.go diff --git a/internal/win/generate.go b/internal/win/generate.go index 5a681c8..9c90c05 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 win32.go wtsapi32.go +//go:generate mkwinsyscall comctl32.go comdlg32.go gdi32.go kernel32.go ole32.go shell32.go user32.go win32.go wtsapi32.go package win diff --git a/internal/win/kernel32.go b/internal/win/kernel32.go new file mode 100644 index 0000000..8e3fd7b --- /dev/null +++ b/internal/win/kernel32.go @@ -0,0 +1,11 @@ +//go:build windows + +package win + +import "golang.org/x/sys/windows" + +func GetCurrentThreadId() (id uint32) { return windows.GetCurrentThreadId() } +func GetSystemDirectory() (string, error) { return windows.GetSystemDirectory() } + +//sys GetConsoleWindow() (ret HWND) = kernel32.GetConsoleWindow +//sys GetModuleHandle(moduleName *uint16) (ret Handle, err error) = kernel32.GetModuleHandleW diff --git a/internal/win/user32.go b/internal/win/user32.go index a7b0534..748bb05 100644 --- a/internal/win/user32.go +++ b/internal/win/user32.go @@ -55,6 +55,10 @@ func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret i return windows.MessageBox(hwnd, text, caption, boxtype) } +func GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) { + return windows.GetWindowThreadProcessId(hwnd, pid) +} + //sys GetDlgCtrlID(wnd HWND) (ret int) = user32.GetDlgCtrlID //sys SendMessage(wnd HWND, msg uint32, wparam uintptr, lparam uintptr) (ret uintptr) = user32.SendMessageW //sys SetWindowText(wnd HWND, text *uint16) (err error) = user32.SetWindowTextW diff --git a/internal/win/zsyscall_windows.go b/internal/win/zsyscall_windows.go index 130d932..c18b38d 100644 --- a/internal/win/zsyscall_windows.go +++ b/internal/win/zsyscall_windows.go @@ -41,6 +41,7 @@ var ( modcomctl32 = windows.NewLazySystemDLL("comctl32.dll") modcomdlg32 = windows.NewLazySystemDLL("comdlg32.dll") modgdi32 = windows.NewLazySystemDLL("gdi32.dll") + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") modntdll = windows.NewLazySystemDLL("ntdll.dll") modole32 = windows.NewLazySystemDLL("ole32.dll") modshell32 = windows.NewLazySystemDLL("shell32.dll") @@ -55,6 +56,8 @@ var ( procCreateFontIndirectW = modgdi32.NewProc("CreateFontIndirectW") procDeleteObject = modgdi32.NewProc("DeleteObject") procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps") + procGetConsoleWindow = modkernel32.NewProc("GetConsoleWindow") + procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW") procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers") procCoCreateInstance = modole32.NewProc("CoCreateInstance") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") @@ -117,6 +120,21 @@ func GetDeviceCaps(dc Handle, index int) (cap int) { return } +func GetConsoleWindow() (ret HWND) { + r0, _, _ := syscall.Syscall(procGetConsoleWindow.Addr(), 0, 0, 0, 0) + ret = HWND(r0) + return +} + +func GetModuleHandle(moduleName *uint16) (ret Handle, err error) { + r0, _, e1 := syscall.Syscall(procGetModuleHandleW.Addr(), 1, uintptr(unsafe.Pointer(moduleName)), 0, 0) + ret = Handle(r0) + if ret == 0 { + err = errnoErr(e1) + } + return +} + 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 diff --git a/util_windows.go b/util_windows.go index a33709f..1a66f3a 100644 --- a/util_windows.go +++ b/util_windows.go @@ -20,13 +20,10 @@ var ( kernel32 = windows.NewLazySystemDLL("kernel32.dll") user32 = windows.NewLazySystemDLL("user32.dll") - activateActCtx = kernel32.NewProc("ActivateActCtx") - createActCtx = kernel32.NewProc("CreateActCtxW") - deactivateActCtx = kernel32.NewProc("DeactivateActCtx") - getConsoleWindow = kernel32.NewProc("GetConsoleWindow") - getCurrentThreadId = kernel32.NewProc("GetCurrentThreadId") - getModuleHandle = kernel32.NewProc("GetModuleHandleW") - getSystemDirectory = kernel32.NewProc("GetSystemDirectoryW") + activateActCtx = kernel32.NewProc("ActivateActCtx") + createActCtx = kernel32.NewProc("CreateActCtxW") + deactivateActCtx = kernel32.NewProc("DeactivateActCtx") + getModuleHandle = kernel32.NewProc("GetModuleHandleW") callNextHookEx = user32.NewProc("CallNextHookEx") createIconFromResource = user32.NewProc("CreateIconFromResource") @@ -43,7 +40,6 @@ var ( getWindowRect = user32.NewProc("GetWindowRect") getWindowText = user32.NewProc("GetWindowTextW") getWindowTextLength = user32.NewProc("GetWindowTextLengthW") - getWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId") isDialogMessage = user32.NewProc("IsDialogMessageW") loadIcon = user32.NewProc("LoadIconW") loadImage = user32.NewProc("LoadImageW") @@ -76,13 +72,13 @@ func strptr(s string) uintptr { func hwnd(i uint64) win.HWND { return win.HWND(uintptr(i)) } func setup() context.CancelFunc { - var wnd uintptr + var wnd win.HWND win.EnumWindows(syscall.NewCallback(setupEnumCallback), uintptr(unsafe.Pointer(&wnd))) if wnd == 0 { - wnd, _, _ = getConsoleWindow.Call() + wnd = win.GetConsoleWindow() } if wnd != 0 { - setForegroundWindow.Call(wnd) + setForegroundWindow.Call(uintptr(wnd)) } runtime.LockOSThread() @@ -118,9 +114,9 @@ func setup() context.CancelFunc { } } -func setupEnumCallback(wnd uintptr, lparam *uintptr) uintptr { - var pid uintptr - getWindowThreadProcessId.Call(wnd, uintptr(unsafe.Pointer(&pid))) +func setupEnumCallback(wnd win.HWND, lparam *win.HWND) uintptr { + var pid uint32 + win.GetWindowThreadProcessId(wnd, &pid) if int(pid) == os.Getpid() { *lparam = wnd return 0 // stop enumeration @@ -141,7 +137,7 @@ func hookDialog(ctx context.Context, icon any, title *string, init func(wnd win. type dialogHook struct { ctx context.Context - tid uintptr + tid uint32 wnd uintptr hook uintptr done chan struct{} @@ -151,9 +147,9 @@ type dialogHook struct { } func newDialogHook(ctx context.Context, icon any, title *string, init func(wnd win.HWND)) (*dialogHook, error) { - tid, _, _ := getCurrentThreadId.Call() + tid := win.GetCurrentThreadId() hk, _, err := setWindowsHookEx.Call(12, // WH_CALLWNDPROCRET - syscall.NewCallback(dialogHookProc), 0, tid) + syscall.NewCallback(dialogHookProc), 0, uintptr(tid)) if hk == 0 { return nil, err } @@ -171,14 +167,14 @@ func newDialogHook(ctx context.Context, icon any, title *string, init func(wnd w go hook.wait() } - saveBackRef(tid, unsafe.Pointer(&hook)) + saveBackRef(uintptr(tid), unsafe.Pointer(&hook)) return &hook, nil } func dialogHookProc(code int32, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr { if lparam.Message == 0x0110 { // WM_INITDIALOG - tid, _, _ := getCurrentThreadId.Call() - hook := (*dialogHook)(loadBackRef(tid)) + tid := win.GetCurrentThreadId() + hook := (*dialogHook)(loadBackRef(uintptr(tid))) atomic.StoreUintptr(&hook.wnd, uintptr(lparam.Wnd)) if hook.ctx != nil && hook.ctx.Err() != nil { win.SendMessage(lparam.Wnd, win.WM_SYSCOMMAND, _SC_CLOSE, 0) @@ -204,7 +200,7 @@ func dialogHookProc(code int32, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr { } func (h *dialogHook) unhook() { - deleteBackRef(h.tid) + deleteBackRef(uintptr(h.tid)) if h.done != nil { close(h.done) } @@ -422,9 +418,8 @@ func messageLoop(wnd uintptr) error { // https://stackoverflow.com/questions/4308503/how-to-enable-visual-styles-without-a-manifest func enableVisualStyles() (cookie uintptr) { - var dir [260]uint16 - n, _, _ := getSystemDirectory.Call(uintptr(unsafe.Pointer(&dir[0])), uintptr(len(dir))) - if n == 0 || int(n) >= len(dir) { + dir, err := win.GetSystemDirectory() + if err != nil { return } @@ -432,7 +427,7 @@ func enableVisualStyles() (cookie uintptr) { ctx.Size = uint32(unsafe.Sizeof(ctx)) ctx.Flags = 0x01c // ACTCTX_FLAG_RESOURCE_NAME_VALID|ACTCTX_FLAG_SET_PROCESS_DEFAULT|ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID ctx.Source = syscall.StringToUTF16Ptr("shell32.dll") - ctx.AssemblyDirectory = &dir[0] + ctx.AssemblyDirectory = syscall.StringToUTF16Ptr(dir) ctx.ResourceName = 124 if h, _, _ := createActCtx.Call(uintptr(unsafe.Pointer(&ctx))); h != 0 {