package main import ( "syscall" "unsafe" "github.com/tadvi/winc/w32" ) // user32 procs winc does not export — or exports incorrectly. winc's own // w32.SetWindowLongPtr / GetWindowLongPtr are bound to the 32-bit // SetWindowLongW / GetWindowLongW, which truncate a 64-bit callback pointer on // amd64; these bind the real *Ptr variants instead. var ( procSetTimer = syscall.NewLazyDLL("user32").NewProc("SetTimer") procKillTimer = syscall.NewLazyDLL("user32").NewProc("KillTimer") procShowWindow = syscall.NewLazyDLL("user32").NewProc("ShowWindow") procSetWindowLongPtrW = syscall.NewLazyDLL("user32").NewProc("SetWindowLongPtrW") procGetWindowLongPtrW = syscall.NewLazyDLL("user32").NewProc("GetWindowLongPtrW") procAdjustWindowRectEx = syscall.NewLazyDLL("user32").NewProc("AdjustWindowRectEx") procGetConsoleProcessList = syscall.NewLazyDLL("kernel32").NewProc("GetConsoleProcessList") ) const swHide = 0 // SW_HIDE — hide a window without destroying it // GWLP_WNDPROC (-4), as the unsigned index value user32 reads in its low DWORD. const gwlpWndProcIdx = ^uintptr(3) func setTimer(hwnd w32.HWND, id, ms uintptr, cb uintptr) bool { ret, _, _ := procSetTimer.Call(uintptr(hwnd), id, ms, cb) return ret != 0 } func killTimer(hwnd w32.HWND, id uintptr) bool { ret, _, _ := procKillTimer.Call(uintptr(hwnd), id) return ret != 0 } // setWndProc replaces hwnd's window procedure with the full (un-truncated) // callback pointer and returns the previous one. func setWndProc(hwnd w32.HWND, cb uintptr) uintptr { ret, _, _ := procSetWindowLongPtrW.Call(uintptr(hwnd), gwlpWndProcIdx, cb) return ret } func getWndProc(hwnd w32.HWND) uintptr { ret, _, _ := procGetWindowLongPtrW.Call(uintptr(hwnd), gwlpWndProcIdx) return ret } // hideConsoleWindow hides (not destroys) a console window; its stderr stream // stays fully attached and usable. func hideConsoleWindow(hwnd w32.HWND) bool { ret, _, _ := procShowWindow.Call(uintptr(hwnd), swHide) return ret != 0 } func getWindowLong(hwnd w32.HWND, index int) uintptr { ret, _, _ := procGetWindowLongPtrW.Call(uintptr(hwnd), uintptr(index)) return ret } // sizeWindowToClient resizes hwnd so its CLIENT area is exactly cw x ch. // winc's SetSize moves the full WINDOW rect (title bar + borders included), // which silently clips child controls positioned near the bottom edge in // client coordinates — on GameNative that put the button row out of reach. func sizeWindowToClient(hwnd w32.HWND, cw, ch int) { style := getWindowLong(hwnd, -16) // GWL_STYLE exstyle := getWindowLong(hwnd, -20) // GWL_EXSTYLE var r w32.RECT r.Right, r.Bottom = int32(cw), int32(ch) procAdjustWindowRectEx.Call(uintptr(unsafe.Pointer(&r)), style, 0, exstyle) cur := w32.GetWindowRect(hwnd) w32.MoveWindow(hwnd, int(cur.Left), int(cur.Top), int(r.Right-r.Left), int(r.Bottom-r.Top), true) } // consoleProcessCount is how many processes share this process's console: 1 // means we own a private one (created for us at double-click launch); more // means it belongs to a terminal we were started from. 0 = no console or error. func consoleProcessCount() int { buf := make([]uint32, 64) ret, _, _ := procGetConsoleProcessList.Call( uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf))) return int(ret) }