Refactor (windows).

This commit is contained in:
Nuno Cruces 2022-06-20 02:14:08 +01:00
parent 4bfddad741
commit b273c0992b
14 changed files with 214 additions and 145 deletions

View file

@ -117,7 +117,7 @@ func (dlg *calendarDialog) setup(text string, opts options) (time.Time, error) {
}()
}
if err := messageLoop(dlg.wnd); err != nil {
if err := win.MessageLoop(win.HWND(dlg.wnd)); err != nil {
return time.Time{}, err
}
if opts.ctx != nil && opts.ctx.Err() != nil {

View file

@ -111,7 +111,7 @@ func (dlg *entryDialog) setup(text string, opts options) (string, error) {
}()
}
if err := messageLoop(dlg.wnd); err != nil {
if err := win.MessageLoop(win.HWND(dlg.wnd)); err != nil {
return "", err
}
if opts.ctx != nil && opts.ctx.Err() != nil {

View file

@ -17,6 +17,8 @@ const (
_FOS_FORCEFILESYSTEM = 0x00000040
_FOS_ALLOWMULTISELECT = 0x00000200
_FOS_FORCESHOWHIDDEN = 0x10000000
_SIGDN_FILESYSPATH = 0x80058000
)
func selectFile(opts options) (string, error) {
@ -191,7 +193,7 @@ func selectFileSave(opts options) (string, error) {
func pickFolders(opts options, multi bool) (str string, lst []string, err error) {
defer setup()()
err = win.CoInitializeEx(0, 0x6) // COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE
err = win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE)
if err != win.RPC_E_CHANGED_MODE {
if err != nil {
return "", nil, err
@ -201,7 +203,7 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
var dialog *_IFileOpenDialog
err = win.CoCreateInstance(
_CLSID_FileOpenDialog, nil, 0x17, // CLSCTX_ALL
_CLSID_FileOpenDialog, nil, win.CLSCTX_ALL,
_IID_IFileOpenDialog, unsafe.Pointer(&dialog))
if err != nil {
if multi {
@ -257,7 +259,7 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
if opts.ctx != nil && opts.ctx.Err() != nil {
return "", nil, opts.ctx.Err()
}
if hr == 0x800704c7 { // ERROR_CANCELLED
if hr == uintptr(win.E_CANCELED) {
return "", nil, ErrCanceled
}
if int32(hr) < 0 {
@ -272,10 +274,9 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
}
defer item.Call(item.Release)
var ptr uintptr
var ptr unsafe.Pointer
hr, _, _ = item.Call(item.GetDisplayName,
0x80058000, // SIGDN_FILESYSPATH
uintptr(unsafe.Pointer(&ptr)))
_SIGDN_FILESYSPATH, uintptr(unsafe.Pointer(&ptr)))
if int32(hr) < 0 {
return syscall.Errno(hr)
}
@ -314,7 +315,7 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
func browseForFolder(opts options) (string, []string, error) {
var args win.BROWSEINFO
args.Owner, _ = opts.attach.(win.HWND)
args.Flags = 0x1 // BIF_RETURNONLYFSDIRS
args.Flags = win.BIF_RETURNONLYFSDIRS
if opts.title != nil {
args.Title = syscall.StringToUTF16Ptr(*opts.title)
@ -336,7 +337,7 @@ func browseForFolder(opts options) (string, []string, error) {
if opts.ctx != nil && opts.ctx.Err() != nil {
return "", nil, opts.ctx.Err()
}
if ptr == 0 {
if ptr == nil {
return "", nil, ErrCanceled
}
defer win.CoTaskMemFree(ptr)
@ -349,8 +350,8 @@ func browseForFolder(opts options) (string, []string, error) {
}
func browseForFolderCallback(wnd win.HWND, msg uint32, lparam, data uintptr) uintptr {
if msg == 1 { // BFFM_INITIALIZED
win.SendMessage(wnd, 1024+103 /* BFFM_SETSELECTIONW */, 1 /* TRUE */, data)
if msg == win.BFFM_INITIALIZED {
win.SendMessage(wnd, win.BFFM_SETSELECTION, 1, data)
}
return 0
}

View file

@ -22,7 +22,7 @@ type CHOOSECOLOR struct {
RgbResult uint32
CustColors *[16]uint32
Flags uint32
CustData uintptr
CustData Pointer
FnHook uintptr
TemplateName *uint16
}
@ -58,7 +58,7 @@ type OPENFILENAME struct {
FileOffset uint16
FileExtension uint16
DefExt *uint16
CustData uintptr
CustData Pointer
FnHook uintptr
TemplateName *uint16
PvReserved uintptr

View file

@ -10,7 +10,19 @@ import (
)
const (
RPC_E_CHANGED_MODE syscall.Errno = 0x80010106
COINIT_MULTITHREADED = windows.COINIT_MULTITHREADED
COINIT_APARTMENTTHREADED = windows.COINIT_APARTMENTTHREADED
COINIT_DISABLE_OLE1DDE = windows.COINIT_DISABLE_OLE1DDE
COINIT_SPEED_OVER_MEMORY = windows.COINIT_SPEED_OVER_MEMORY
CLSCTX_INPROC_SERVER = windows.CLSCTX_INPROC_SERVER
CLSCTX_INPROC_HANDLER = windows.CLSCTX_INPROC_HANDLER
CLSCTX_LOCAL_SERVER = windows.CLSCTX_LOCAL_SERVER
CLSCTX_REMOTE_SERVER = windows.CLSCTX_REMOTE_SERVER
CLSCTX_ALL = windows.CLSCTX_INPROC_SERVER | windows.CLSCTX_INPROC_HANDLER | windows.CLSCTX_LOCAL_SERVER | windows.CLSCTX_REMOTE_SERVER
E_CANCELED = windows.ERROR_CANCELLED | windows.FACILITY_WIN32<<16 | 0x80000000
RPC_E_CHANGED_MODE = syscall.Errno(windows.RPC_E_CHANGED_MODE)
)
func CoInitializeEx(reserved uintptr, coInit uint32) error {
@ -19,6 +31,8 @@ func CoInitializeEx(reserved uintptr, coInit uint32) error {
func CoUninitialize() { windows.CoUninitialize() }
func CoTaskMemFree(address unsafe.Pointer) { windows.CoTaskMemFree(address) }
// https://github.com/wine-mirror/wine/blob/master/include/unknwn.idl
type IUnknownVtbl struct {
@ -43,5 +57,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) (res error) = ole32.CoCreateInstance

View file

@ -3,6 +3,11 @@
package win
const (
BIF_RETURNONLYFSDIRS = 0x00000001
BFFM_INITIALIZED = 1
BFFM_SETSELECTION = WM_USER + 103
NIM_ADD = 0
NIM_DELETE = 2
)
@ -10,7 +15,7 @@ const (
// https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfow
type BROWSEINFO struct {
Owner HWND
Root uintptr
Root Pointer
DisplayName *uint16
Title *uint16
Flags uint32
@ -52,7 +57,7 @@ type _IShellItemVtbl struct {
Compare uintptr
}
//sys SHBrowseForFolder(bi *BROWSEINFO) (ptr uintptr) = shell32.SHBrowseForFolder
//sys SHBrowseForFolder(bi *BROWSEINFO) (ptr unsafe.Pointer) = shell32.SHBrowseForFolder
//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 SHGetPathFromIDListEx(ptr unsafe.Pointer, path *uint16, pathLen int, opts int) (ok bool) = shell32.SHGetPathFromIDListEx
//sys ShellNotifyIcon(message uint32, data *NOTIFYICONDATA) (ret int, err error) = shell32.Shell_NotifyIconW

View file

@ -2,7 +2,12 @@
package win
import "golang.org/x/sys/windows"
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
const (
IDOK = 1
@ -49,6 +54,12 @@ const (
PBM_SETRANGE32 = WM_USER + 6
PBM_SETMARQUEE = WM_USER + 10
STM_SETICON = 0x0170
DPI_AWARENESS_CONTEXT_UNAWARE = ^uintptr(1) + 1
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = ^uintptr(2) + 1
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = ^uintptr(3) + 1
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = ^uintptr(4) + 1
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED = ^uintptr(5) + 1
)
func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) {
@ -59,8 +70,61 @@ func GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) {
return windows.GetWindowThreadProcessId(hwnd, pid)
}
func SetThreadDpiAwarenessContext(dpiContext uintptr) (ret uintptr, err error) {
if err := procSetThreadDpiAwarenessContext.Find(); err != nil {
return 0, err
}
return setThreadDpiAwarenessContext(dpiContext), nil
}
// https://docs.microsoft.com/en-us/windows/win32/winmsg/using-messages-and-message-queues
func MessageLoop(wnd HWND) error {
getMessage := procGetMessageW.Addr()
translateMessage := procTranslateMessage.Addr()
dispatchMessage := procDispatchMessageW.Addr()
isDialogMessage := procIsDialogMessageW.Addr()
for {
var msg MSG
s, _, err := syscall.Syscall6(getMessage, 4, uintptr(unsafe.Pointer(&msg)), 0, 0, 0, 0, 0)
if int32(s) == -1 {
return err
}
if s == 0 {
return nil
}
s, _, _ = syscall.Syscall(isDialogMessage, 2, uintptr(wnd), uintptr(unsafe.Pointer(&msg)), 0)
if s == 0 {
syscall.Syscall(translateMessage, 1, uintptr(unsafe.Pointer(&msg)), 0, 0)
syscall.Syscall(dispatchMessage, 1, uintptr(unsafe.Pointer(&msg)), 0, 0)
}
}
}
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-msg
type MSG struct {
Owner syscall.Handle
Message uint32
WParam uintptr
LParam uintptr
Time uint32
Pt POINT
}
// https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-point
type POINT struct {
x, y int32
}
//sys DispatchMessage(msg *MSG) (ret uintptr) = user32.DispatchMessageW
//sys EnumChildWindows(parent HWND, enumFunc uintptr, lparam unsafe.Pointer) = user32.EnumChildWindows
//sys EnumWindows(enumFunc uintptr, lparam unsafe.Pointer) (err error) = user32.EnumChildWindows
//sys GetDlgCtrlID(wnd HWND) (ret int) = user32.GetDlgCtrlID
//sys GetMessage(msg *MSG, wnd HWND, msgFilterMin uint32, msgFilterMax uint32) (ret uintptr) = user32.GetMessageW
//sys IsDialogMessage(wnd HWND, msg *MSG) (ok bool) = user32.IsDialogMessageW
//sys SendMessage(wnd HWND, msg uint32, wparam uintptr, lparam uintptr) (ret uintptr) = user32.SendMessageW
//sys SetForegroundWindow(wnd HWND) (ok bool) = user32.SetForegroundWindow
//sys setThreadDpiAwarenessContext(dpiContext uintptr) (ret uintptr) = user32.SetThreadDpiAwarenessContext
//sys SetWindowText(wnd HWND, text *uint16) (err error) = user32.SetWindowTextW
//sys EnumChildWindows(parent HWND, enumFunc uintptr, lparam uintptr) = user32.EnumChildWindows
//sys EnumWindows(enumFunc uintptr, lparam uintptr) (err error) = user32.EnumChildWindows
//sys TranslateMessage(msg *MSG) (ok bool) = user32.TranslateMessage

View file

@ -7,5 +7,6 @@ import "golang.org/x/sys/windows"
type Handle = windows.Handle
type HWND = windows.HWND
type Pointer = windows.Pointer
//sys RtlGetNtVersionNumbers(major *uint32, minor *uint32, build *uint32) = ntdll.RtlGetNtVersionNumbers

View file

@ -48,28 +48,33 @@ var (
moduser32 = windows.NewLazySystemDLL("user32.dll")
modwtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll")
procInitCommonControlsEx = modcomctl32.NewProc("InitCommonControlsEx")
procChooseColorW = modcomdlg32.NewProc("ChooseColorW")
procCommDlgExtendedError = modcomdlg32.NewProc("CommDlgExtendedError")
procGetOpenFileNameW = modcomdlg32.NewProc("GetOpenFileNameW")
procGetSaveFileNameW = modcomdlg32.NewProc("GetSaveFileNameW")
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")
procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolder")
procSHCreateItemFromParsingName = modshell32.NewProc("SHCreateItemFromParsingName")
procSHGetPathFromIDListEx = modshell32.NewProc("SHGetPathFromIDListEx")
procShell_NotifyIconW = modshell32.NewProc("Shell_NotifyIconW")
procEnumChildWindows = moduser32.NewProc("EnumChildWindows")
procGetDlgCtrlID = moduser32.NewProc("GetDlgCtrlID")
procSendMessageW = moduser32.NewProc("SendMessageW")
procSetWindowTextW = moduser32.NewProc("SetWindowTextW")
procWTSSendMessageW = modwtsapi32.NewProc("WTSSendMessageW")
procInitCommonControlsEx = modcomctl32.NewProc("InitCommonControlsEx")
procChooseColorW = modcomdlg32.NewProc("ChooseColorW")
procCommDlgExtendedError = modcomdlg32.NewProc("CommDlgExtendedError")
procGetOpenFileNameW = modcomdlg32.NewProc("GetOpenFileNameW")
procGetSaveFileNameW = modcomdlg32.NewProc("GetSaveFileNameW")
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")
procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolder")
procSHCreateItemFromParsingName = modshell32.NewProc("SHCreateItemFromParsingName")
procSHGetPathFromIDListEx = modshell32.NewProc("SHGetPathFromIDListEx")
procShell_NotifyIconW = modshell32.NewProc("Shell_NotifyIconW")
procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
procEnumChildWindows = moduser32.NewProc("EnumChildWindows")
procGetDlgCtrlID = moduser32.NewProc("GetDlgCtrlID")
procGetMessageW = moduser32.NewProc("GetMessageW")
procIsDialogMessageW = moduser32.NewProc("IsDialogMessageW")
procSendMessageW = moduser32.NewProc("SendMessageW")
procSetForegroundWindow = moduser32.NewProc("SetForegroundWindow")
procSetThreadDpiAwarenessContext = moduser32.NewProc("SetThreadDpiAwarenessContext")
procSetWindowTextW = moduser32.NewProc("SetWindowTextW")
procTranslateMessage = moduser32.NewProc("TranslateMessage")
procWTSSendMessageW = modwtsapi32.NewProc("WTSSendMessageW")
)
func InitCommonControlsEx(icc *INITCOMMONCONTROLSEX) (ok bool) {
@ -148,14 +153,9 @@ func CoCreateInstance(clsid uintptr, unkOuter unsafe.Pointer, clsContext int32,
return
}
func CoTaskMemFree(address uintptr) {
syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(address), 0, 0)
return
}
func SHBrowseForFolder(bi *BROWSEINFO) (ptr uintptr) {
func SHBrowseForFolder(bi *BROWSEINFO) (ptr unsafe.Pointer) {
r0, _, _ := syscall.Syscall(procSHBrowseForFolder.Addr(), 1, uintptr(unsafe.Pointer(bi)), 0, 0)
ptr = uintptr(r0)
ptr = unsafe.Pointer(r0)
return
}
@ -167,7 +167,7 @@ func SHCreateItemFromParsingName(path *uint16, bc unsafe.Pointer, iid uintptr, i
return
}
func SHGetPathFromIDListEx(ptr uintptr, path *uint16, pathLen int, opts int) (ok bool) {
func SHGetPathFromIDListEx(ptr unsafe.Pointer, 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
@ -182,12 +182,18 @@ func ShellNotifyIcon(message uint32, data *NOTIFYICONDATA) (ret int, err error)
return
}
func EnumChildWindows(parent HWND, enumFunc uintptr, lparam uintptr) {
func DispatchMessage(msg *MSG) (ret uintptr) {
r0, _, _ := syscall.Syscall(procDispatchMessageW.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
ret = uintptr(r0)
return
}
func EnumChildWindows(parent HWND, enumFunc uintptr, lparam unsafe.Pointer) {
syscall.Syscall(procEnumChildWindows.Addr(), 3, uintptr(parent), uintptr(enumFunc), uintptr(lparam))
return
}
func EnumWindows(enumFunc uintptr, lparam uintptr) (err error) {
func EnumWindows(enumFunc uintptr, lparam unsafe.Pointer) (err error) {
r1, _, e1 := syscall.Syscall(procEnumChildWindows.Addr(), 2, uintptr(enumFunc), uintptr(lparam), 0)
if r1 == 0 {
err = errnoErr(e1)
@ -201,12 +207,36 @@ func GetDlgCtrlID(wnd HWND) (ret int) {
return
}
func GetMessage(msg *MSG, wnd HWND, msgFilterMin uint32, msgFilterMax uint32) (ret uintptr) {
r0, _, _ := syscall.Syscall6(procGetMessageW.Addr(), 4, uintptr(unsafe.Pointer(msg)), uintptr(wnd), uintptr(msgFilterMin), uintptr(msgFilterMax), 0, 0)
ret = uintptr(r0)
return
}
func IsDialogMessage(wnd HWND, msg *MSG) (ok bool) {
r0, _, _ := syscall.Syscall(procIsDialogMessageW.Addr(), 2, uintptr(wnd), uintptr(unsafe.Pointer(msg)), 0)
ok = r0 != 0
return
}
func SendMessage(wnd HWND, msg uint32, wparam uintptr, lparam uintptr) (ret uintptr) {
r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(wnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
ret = uintptr(r0)
return
}
func SetForegroundWindow(wnd HWND) (ok bool) {
r0, _, _ := syscall.Syscall(procSetForegroundWindow.Addr(), 1, uintptr(wnd), 0, 0)
ok = r0 != 0
return
}
func setThreadDpiAwarenessContext(dpiContext uintptr) (ret uintptr) {
r0, _, _ := syscall.Syscall(procSetThreadDpiAwarenessContext.Addr(), 1, uintptr(dpiContext), 0, 0)
ret = uintptr(r0)
return
}
func SetWindowText(wnd HWND, text *uint16) (err error) {
r1, _, e1 := syscall.Syscall(procSetWindowTextW.Addr(), 2, uintptr(wnd), uintptr(unsafe.Pointer(text)), 0)
if r1 == 0 {
@ -215,6 +245,12 @@ func SetWindowText(wnd HWND, text *uint16) (err error) {
return
}
func TranslateMessage(msg *MSG) (ok bool) {
r0, _, _ := syscall.Syscall(procTranslateMessage.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
ok = r0 != 0
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 {

View file

@ -131,7 +131,7 @@ func (dlg *listDialog) setup(text string, opts options) ([]string, error) {
}()
}
if err := messageLoop(dlg.wnd); err != nil {
if err := win.MessageLoop(win.HWND(dlg.wnd)); err != nil {
return nil, err
}
if opts.ctx != nil && opts.ctx.Err() != nil {

View file

@ -90,7 +90,7 @@ func message(kind messageKind, text string, opts options) error {
func hookMessageDialog(opts options) (unhook context.CancelFunc, err error) {
return hookDialog(opts.ctx, opts.windowIcon, nil, func(wnd win.HWND) {
win.EnumChildWindows(wnd, syscall.NewCallback(hookMessageDialogCallback),
uintptr(unsafe.Pointer(&opts)))
unsafe.Pointer(&opts))
})
}

View file

@ -197,7 +197,7 @@ func (dlg *progressDialog) setup(opts options) error {
}()
}
if err := messageLoop(dlg.wnd); err != nil {
if err := win.MessageLoop(win.HWND(dlg.wnd)); err != nil {
return err
}
if opts.ctx != nil && opts.ctx.Err() != nil {

View file

@ -128,7 +128,7 @@ func (dlg *passwordDialog) setup(opts options) (string, string, error) {
}()
}
if err := messageLoop(dlg.wnd); err != nil {
if err := win.MessageLoop(win.HWND(dlg.wnd)); err != nil {
return "", "", err
}
if opts.ctx != nil && opts.ctx.Err() != nil {

View file

@ -25,40 +25,34 @@ var (
deactivateActCtx = kernel32.NewProc("DeactivateActCtx")
getModuleHandle = kernel32.NewProc("GetModuleHandleW")
callNextHookEx = user32.NewProc("CallNextHookEx")
createIconFromResource = user32.NewProc("CreateIconFromResource")
createWindowEx = user32.NewProc("CreateWindowExW")
defWindowProc = user32.NewProc("DefWindowProcW")
destroyIcon = user32.NewProc("DestroyIcon")
destroyWindow = user32.NewProc("DestroyWindow")
dispatchMessage = user32.NewProc("DispatchMessageW")
enableWindow = user32.NewProc("EnableWindow")
getDpiForWindow = user32.NewProc("GetDpiForWindow")
getMessage = user32.NewProc("GetMessageW")
getSystemMetrics = user32.NewProc("GetSystemMetrics")
getWindowDC = user32.NewProc("GetWindowDC")
getWindowRect = user32.NewProc("GetWindowRect")
getWindowText = user32.NewProc("GetWindowTextW")
getWindowTextLength = user32.NewProc("GetWindowTextLengthW")
isDialogMessage = user32.NewProc("IsDialogMessageW")
loadIcon = user32.NewProc("LoadIconW")
loadImage = user32.NewProc("LoadImageW")
postQuitMessage = user32.NewProc("PostQuitMessage")
registerClassEx = user32.NewProc("RegisterClassExW")
releaseDC = user32.NewProc("ReleaseDC")
sendMessage = user32.NewProc("SendMessageW")
setFocus = user32.NewProc("SetFocus")
setForegroundWindow = user32.NewProc("SetForegroundWindow")
setThreadDpiAwarenessContext = user32.NewProc("SetThreadDpiAwarenessContext")
setWindowLong = user32.NewProc("SetWindowLongW")
setWindowPos = user32.NewProc("SetWindowPos")
setWindowsHookEx = user32.NewProc("SetWindowsHookExW")
setWindowText = user32.NewProc("SetWindowTextW")
showWindow = user32.NewProc("ShowWindow")
systemParametersInfo = user32.NewProc("SystemParametersInfoW")
translateMessage = user32.NewProc("TranslateMessage")
unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx")
unregisterClass = user32.NewProc("UnregisterClassW")
callNextHookEx = user32.NewProc("CallNextHookEx")
createIconFromResource = user32.NewProc("CreateIconFromResource")
createWindowEx = user32.NewProc("CreateWindowExW")
defWindowProc = user32.NewProc("DefWindowProcW")
destroyIcon = user32.NewProc("DestroyIcon")
destroyWindow = user32.NewProc("DestroyWindow")
enableWindow = user32.NewProc("EnableWindow")
getDpiForWindow = user32.NewProc("GetDpiForWindow")
getSystemMetrics = user32.NewProc("GetSystemMetrics")
getWindowDC = user32.NewProc("GetWindowDC")
getWindowRect = user32.NewProc("GetWindowRect")
getWindowText = user32.NewProc("GetWindowTextW")
getWindowTextLength = user32.NewProc("GetWindowTextLengthW")
loadIcon = user32.NewProc("LoadIconW")
loadImage = user32.NewProc("LoadImageW")
postQuitMessage = user32.NewProc("PostQuitMessage")
registerClassEx = user32.NewProc("RegisterClassExW")
releaseDC = user32.NewProc("ReleaseDC")
sendMessage = user32.NewProc("SendMessageW")
setFocus = user32.NewProc("SetFocus")
setWindowLong = user32.NewProc("SetWindowLongW")
setWindowPos = user32.NewProc("SetWindowPos")
setWindowsHookEx = user32.NewProc("SetWindowsHookExW")
setWindowText = user32.NewProc("SetWindowTextW")
showWindow = user32.NewProc("ShowWindow")
systemParametersInfo = user32.NewProc("SystemParametersInfoW")
unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx")
unregisterClass = user32.NewProc("UnregisterClassW")
)
func intptr(i int64) uintptr {
@ -73,28 +67,23 @@ func hwnd(i uint64) win.HWND { return win.HWND(uintptr(i)) }
func setup() context.CancelFunc {
var wnd win.HWND
win.EnumWindows(syscall.NewCallback(setupEnumCallback), uintptr(unsafe.Pointer(&wnd)))
win.EnumWindows(syscall.NewCallback(setupEnumCallback), unsafe.Pointer(&wnd))
if wnd == 0 {
wnd = win.GetConsoleWindow()
}
if wnd != 0 {
setForegroundWindow.Call(uintptr(wnd))
win.SetForegroundWindow(wnd)
}
runtime.LockOSThread()
var restore uintptr
cookie := enableVisualStyles()
if setThreadDpiAwarenessContext.Find() == nil {
// try:
// DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
// DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
// DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
for i := -4; i <= -2; i++ {
restore, _, _ = setThreadDpiAwarenessContext.Call(uintptr(i))
if restore != 0 {
break
}
for dpi := win.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; dpi <= win.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; dpi++ {
var err error
restore, err = win.SetThreadDpiAwarenessContext(dpi)
if restore != 0 || err != nil {
break
}
}
@ -105,7 +94,7 @@ func setup() context.CancelFunc {
return func() {
if restore != 0 {
setThreadDpiAwarenessContext.Call(restore)
win.SetThreadDpiAwarenessContext(restore)
}
if cookie != 0 {
deactivateActCtx.Call(0, cookie)
@ -391,31 +380,6 @@ func registerClass(instance, icon, proc uintptr) (uintptr, error) {
return atom, err
}
// https://docs.microsoft.com/en-us/windows/win32/winmsg/using-messages-and-message-queues
func messageLoop(wnd uintptr) error {
getMessage := getMessage.Addr()
isDialogMessage := isDialogMessage.Addr()
translateMessage := translateMessage.Addr()
dispatchMessage := dispatchMessage.Addr()
for {
var msg _MSG
s, _, err := syscall.Syscall6(getMessage, 4, uintptr(unsafe.Pointer(&msg)), 0, 0, 0, 0, 0)
if int32(s) == -1 {
return err
}
if s == 0 {
return nil
}
s, _, _ = syscall.Syscall(isDialogMessage, 2, wnd, uintptr(unsafe.Pointer(&msg)), 0)
if s == 0 {
syscall.Syscall(translateMessage, 1, uintptr(unsafe.Pointer(&msg)), 0, 0)
syscall.Syscall(dispatchMessage, 1, uintptr(unsafe.Pointer(&msg)), 0, 0)
}
}
}
// https://stackoverflow.com/questions/4308503/how-to-enable-visual-styles-without-a-manifest
func enableVisualStyles() (cookie uintptr) {
dir, err := win.GetSystemDirectory()
@ -477,21 +441,6 @@ type _NONCLIENTMETRICS struct {
MessageFont win.LOGFONT
}
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-msg
type _MSG struct {
Owner syscall.Handle
Message uint32
WParam uintptr
LParam uintptr
Time uint32
Pt _POINT
}
// https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-point
type _POINT struct {
x, y int32
}
// https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect
type _RECT struct {
left int32