Refactor (windows).

This commit is contained in:
Nuno Cruces 2022-06-19 00:48:38 +01:00
parent 971520115f
commit 4bfddad741
5 changed files with 54 additions and 26 deletions

View file

@ -1,6 +1,6 @@
//go:build generate //go:build generate
//go:generate -command mkwinsyscall go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go //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 package win

11
internal/win/kernel32.go Normal file
View file

@ -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

View file

@ -55,6 +55,10 @@ func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret i
return windows.MessageBox(hwnd, text, caption, boxtype) 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 GetDlgCtrlID(wnd HWND) (ret int) = user32.GetDlgCtrlID
//sys SendMessage(wnd HWND, msg uint32, wparam uintptr, lparam uintptr) (ret uintptr) = user32.SendMessageW //sys SendMessage(wnd HWND, msg uint32, wparam uintptr, lparam uintptr) (ret uintptr) = user32.SendMessageW
//sys SetWindowText(wnd HWND, text *uint16) (err error) = user32.SetWindowTextW //sys SetWindowText(wnd HWND, text *uint16) (err error) = user32.SetWindowTextW

View file

@ -41,6 +41,7 @@ var (
modcomctl32 = windows.NewLazySystemDLL("comctl32.dll") modcomctl32 = windows.NewLazySystemDLL("comctl32.dll")
modcomdlg32 = windows.NewLazySystemDLL("comdlg32.dll") modcomdlg32 = windows.NewLazySystemDLL("comdlg32.dll")
modgdi32 = windows.NewLazySystemDLL("gdi32.dll") modgdi32 = windows.NewLazySystemDLL("gdi32.dll")
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modntdll = windows.NewLazySystemDLL("ntdll.dll") modntdll = windows.NewLazySystemDLL("ntdll.dll")
modole32 = windows.NewLazySystemDLL("ole32.dll") modole32 = windows.NewLazySystemDLL("ole32.dll")
modshell32 = windows.NewLazySystemDLL("shell32.dll") modshell32 = windows.NewLazySystemDLL("shell32.dll")
@ -55,6 +56,8 @@ var (
procCreateFontIndirectW = modgdi32.NewProc("CreateFontIndirectW") procCreateFontIndirectW = modgdi32.NewProc("CreateFontIndirectW")
procDeleteObject = modgdi32.NewProc("DeleteObject") procDeleteObject = modgdi32.NewProc("DeleteObject")
procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps") procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps")
procGetConsoleWindow = modkernel32.NewProc("GetConsoleWindow")
procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW")
procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers") procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers")
procCoCreateInstance = modole32.NewProc("CoCreateInstance") procCoCreateInstance = modole32.NewProc("CoCreateInstance")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
@ -117,6 +120,21 @@ func GetDeviceCaps(dc Handle, index int) (cap int) {
return 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) { 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))) syscall.Syscall(procRtlGetNtVersionNumbers.Addr(), 3, uintptr(unsafe.Pointer(major)), uintptr(unsafe.Pointer(minor)), uintptr(unsafe.Pointer(build)))
return return

View file

@ -23,10 +23,7 @@ var (
activateActCtx = kernel32.NewProc("ActivateActCtx") activateActCtx = kernel32.NewProc("ActivateActCtx")
createActCtx = kernel32.NewProc("CreateActCtxW") createActCtx = kernel32.NewProc("CreateActCtxW")
deactivateActCtx = kernel32.NewProc("DeactivateActCtx") deactivateActCtx = kernel32.NewProc("DeactivateActCtx")
getConsoleWindow = kernel32.NewProc("GetConsoleWindow")
getCurrentThreadId = kernel32.NewProc("GetCurrentThreadId")
getModuleHandle = kernel32.NewProc("GetModuleHandleW") getModuleHandle = kernel32.NewProc("GetModuleHandleW")
getSystemDirectory = kernel32.NewProc("GetSystemDirectoryW")
callNextHookEx = user32.NewProc("CallNextHookEx") callNextHookEx = user32.NewProc("CallNextHookEx")
createIconFromResource = user32.NewProc("CreateIconFromResource") createIconFromResource = user32.NewProc("CreateIconFromResource")
@ -43,7 +40,6 @@ var (
getWindowRect = user32.NewProc("GetWindowRect") getWindowRect = user32.NewProc("GetWindowRect")
getWindowText = user32.NewProc("GetWindowTextW") getWindowText = user32.NewProc("GetWindowTextW")
getWindowTextLength = user32.NewProc("GetWindowTextLengthW") getWindowTextLength = user32.NewProc("GetWindowTextLengthW")
getWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId")
isDialogMessage = user32.NewProc("IsDialogMessageW") isDialogMessage = user32.NewProc("IsDialogMessageW")
loadIcon = user32.NewProc("LoadIconW") loadIcon = user32.NewProc("LoadIconW")
loadImage = user32.NewProc("LoadImageW") 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 hwnd(i uint64) win.HWND { return win.HWND(uintptr(i)) }
func setup() context.CancelFunc { func setup() context.CancelFunc {
var wnd uintptr var wnd win.HWND
win.EnumWindows(syscall.NewCallback(setupEnumCallback), uintptr(unsafe.Pointer(&wnd))) win.EnumWindows(syscall.NewCallback(setupEnumCallback), uintptr(unsafe.Pointer(&wnd)))
if wnd == 0 { if wnd == 0 {
wnd, _, _ = getConsoleWindow.Call() wnd = win.GetConsoleWindow()
} }
if wnd != 0 { if wnd != 0 {
setForegroundWindow.Call(wnd) setForegroundWindow.Call(uintptr(wnd))
} }
runtime.LockOSThread() runtime.LockOSThread()
@ -118,9 +114,9 @@ func setup() context.CancelFunc {
} }
} }
func setupEnumCallback(wnd uintptr, lparam *uintptr) uintptr { func setupEnumCallback(wnd win.HWND, lparam *win.HWND) uintptr {
var pid uintptr var pid uint32
getWindowThreadProcessId.Call(wnd, uintptr(unsafe.Pointer(&pid))) win.GetWindowThreadProcessId(wnd, &pid)
if int(pid) == os.Getpid() { if int(pid) == os.Getpid() {
*lparam = wnd *lparam = wnd
return 0 // stop enumeration return 0 // stop enumeration
@ -141,7 +137,7 @@ func hookDialog(ctx context.Context, icon any, title *string, init func(wnd win.
type dialogHook struct { type dialogHook struct {
ctx context.Context ctx context.Context
tid uintptr tid uint32
wnd uintptr wnd uintptr
hook uintptr hook uintptr
done chan struct{} 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) { 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 hk, _, err := setWindowsHookEx.Call(12, // WH_CALLWNDPROCRET
syscall.NewCallback(dialogHookProc), 0, tid) syscall.NewCallback(dialogHookProc), 0, uintptr(tid))
if hk == 0 { if hk == 0 {
return nil, err return nil, err
} }
@ -171,14 +167,14 @@ func newDialogHook(ctx context.Context, icon any, title *string, init func(wnd w
go hook.wait() go hook.wait()
} }
saveBackRef(tid, unsafe.Pointer(&hook)) saveBackRef(uintptr(tid), unsafe.Pointer(&hook))
return &hook, nil return &hook, nil
} }
func dialogHookProc(code int32, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr { func dialogHookProc(code int32, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr {
if lparam.Message == 0x0110 { // WM_INITDIALOG if lparam.Message == 0x0110 { // WM_INITDIALOG
tid, _, _ := getCurrentThreadId.Call() tid := win.GetCurrentThreadId()
hook := (*dialogHook)(loadBackRef(tid)) hook := (*dialogHook)(loadBackRef(uintptr(tid)))
atomic.StoreUintptr(&hook.wnd, uintptr(lparam.Wnd)) atomic.StoreUintptr(&hook.wnd, uintptr(lparam.Wnd))
if hook.ctx != nil && hook.ctx.Err() != nil { if hook.ctx != nil && hook.ctx.Err() != nil {
win.SendMessage(lparam.Wnd, win.WM_SYSCOMMAND, _SC_CLOSE, 0) 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() { func (h *dialogHook) unhook() {
deleteBackRef(h.tid) deleteBackRef(uintptr(h.tid))
if h.done != nil { if h.done != nil {
close(h.done) 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 // https://stackoverflow.com/questions/4308503/how-to-enable-visual-styles-without-a-manifest
func enableVisualStyles() (cookie uintptr) { func enableVisualStyles() (cookie uintptr) {
var dir [260]uint16 dir, err := win.GetSystemDirectory()
n, _, _ := getSystemDirectory.Call(uintptr(unsafe.Pointer(&dir[0])), uintptr(len(dir))) if err != nil {
if n == 0 || int(n) >= len(dir) {
return return
} }
@ -432,7 +427,7 @@ func enableVisualStyles() (cookie uintptr) {
ctx.Size = uint32(unsafe.Sizeof(ctx)) 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.Flags = 0x01c // ACTCTX_FLAG_RESOURCE_NAME_VALID|ACTCTX_FLAG_SET_PROCESS_DEFAULT|ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID
ctx.Source = syscall.StringToUTF16Ptr("shell32.dll") ctx.Source = syscall.StringToUTF16Ptr("shell32.dll")
ctx.AssemblyDirectory = &dir[0] ctx.AssemblyDirectory = syscall.StringToUTF16Ptr(dir)
ctx.ResourceName = 124 ctx.ResourceName = 124
if h, _, _ := createActCtx.Call(uintptr(unsafe.Pointer(&ctx))); h != 0 { if h, _, _ := createActCtx.Call(uintptr(unsafe.Pointer(&ctx))); h != 0 {