gioui.org/ui@v0.0.0-20190926171558-ce74bc0cbaea/app/os_windows.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package app 4 5 import ( 6 "errors" 7 "fmt" 8 "image" 9 "runtime" 10 "sync" 11 "time" 12 "unicode" 13 "unsafe" 14 15 syscall "golang.org/x/sys/windows" 16 17 "gioui.org/ui/f32" 18 "gioui.org/ui/key" 19 "gioui.org/ui/pointer" 20 ) 21 22 var winMap = make(map[syscall.Handle]*window) 23 24 type rect struct { 25 left, top, right, bottom int32 26 } 27 28 type wndClassEx struct { 29 cbSize uint32 30 style uint32 31 lpfnWndProc uintptr 32 cnClsExtra int32 33 cbWndExtra int32 34 hInstance syscall.Handle 35 hIcon syscall.Handle 36 hCursor syscall.Handle 37 hbrBackground syscall.Handle 38 lpszMenuName *uint16 39 lpszClassName *uint16 40 hIconSm syscall.Handle 41 } 42 43 type msg struct { 44 hwnd syscall.Handle 45 message uint32 46 wParam uintptr 47 lParam uintptr 48 time uint32 49 pt point 50 lPrivate uint32 51 } 52 53 type point struct { 54 x, y int32 55 } 56 57 type window struct { 58 hwnd syscall.Handle 59 hdc syscall.Handle 60 w *Window 61 width int 62 height int 63 stage Stage 64 dead bool 65 66 mu sync.Mutex 67 animating bool 68 } 69 70 const ( 71 _CS_HREDRAW = 0x0002 72 _CS_VREDRAW = 0x0001 73 _CS_OWNDC = 0x0020 74 75 _CW_USEDEFAULT = -2147483648 76 77 _IDC_ARROW = 32512 78 79 _INFINITE = 0xFFFFFFFF 80 81 _LOGPIXELSX = 88 82 83 _SIZE_MAXIMIZED = 2 84 _SIZE_MINIMIZED = 1 85 _SIZE_RESTORED = 0 86 87 _SW_SHOWDEFAULT = 10 88 89 _USER_TIMER_MINIMUM = 0x0000000A 90 91 _VK_CONTROL = 0x11 92 _VK_SHIFT = 0x10 93 94 _VK_BACK = 0x08 95 _VK_DELETE = 0x2e 96 _VK_DOWN = 0x28 97 _VK_END = 0x23 98 _VK_ESCAPE = 0x1b 99 _VK_HOME = 0x24 100 _VK_LEFT = 0x25 101 _VK_NEXT = 0x22 102 _VK_PRIOR = 0x21 103 _VK_RIGHT = 0x27 104 _VK_RETURN = 0x0d 105 _VK_UP = 0x26 106 107 _UNICODE_NOCHAR = 65535 108 109 _WM_CANCELMODE = 0x001F 110 _WM_CHAR = 0x0102 111 _WM_CREATE = 0x0001 112 _WM_DESTROY = 0x0002 113 _WM_KEYDOWN = 0x0100 114 _WM_KEYUP = 0x0101 115 _WM_LBUTTONDOWN = 0x0201 116 _WM_LBUTTONUP = 0x0202 117 _WM_MOUSEMOVE = 0x0200 118 _WM_MOUSEWHEEL = 0x020A 119 _WM_PAINT = 0x000F 120 _WM_QUIT = 0x0012 121 _WM_SETFOCUS = 0x0007 122 _WM_KILLFOCUS = 0x0008 123 _WM_SHOWWINDOW = 0x0018 124 _WM_SIZE = 0x0005 125 _WM_SYSKEYDOWN = 0x0104 126 _WM_TIMER = 0x0113 127 _WM_UNICHAR = 0x0109 128 _WM_USER = 0x0400 129 130 _WS_CLIPCHILDREN = 0x00010000 131 _WS_CLIPSIBLINGS = 0x04000000 132 _WS_VISIBLE = 0x10000000 133 _WS_OVERLAPPED = 0x00000000 134 _WS_OVERLAPPEDWINDOW = _WS_OVERLAPPED | _WS_CAPTION | _WS_SYSMENU | _WS_THICKFRAME | 135 _WS_MINIMIZEBOX | _WS_MAXIMIZEBOX 136 _WS_CAPTION = 0x00C00000 137 _WS_SYSMENU = 0x00080000 138 _WS_THICKFRAME = 0x00040000 139 _WS_MINIMIZEBOX = 0x00020000 140 _WS_MAXIMIZEBOX = 0x00010000 141 142 _WS_EX_APPWINDOW = 0x00040000 143 _WS_EX_WINDOWEDGE = 0x00000100 144 145 _QS_ALLINPUT = 0x04FF 146 147 _MWMO_WAITALL = 0x0001 148 _MWMO_INPUTAVAILABLE = 0x0004 149 150 _WAIT_OBJECT_0 = 0 151 152 _PM_REMOVE = 0x0001 153 _PM_NOREMOVE = 0x0000 154 ) 155 156 const _WM_REDRAW = _WM_USER + 0 157 158 var onceMu sync.Mutex 159 var mainDone = make(chan struct{}) 160 161 func main() { 162 <-mainDone 163 } 164 165 func createWindow(window *Window, opts *windowOptions) error { 166 onceMu.Lock() 167 defer onceMu.Unlock() 168 if len(winMap) > 0 { 169 return errors.New("multiple windows are not supported") 170 } 171 cerr := make(chan error) 172 go func() { 173 // Call win32 API from a single OS thread. 174 runtime.LockOSThread() 175 w, err := createNativeWindow(opts) 176 if err != nil { 177 cerr <- err 178 return 179 } 180 defer w.destroy() 181 cerr <- nil 182 winMap[w.hwnd] = w 183 defer delete(winMap, w.hwnd) 184 w.w = window 185 w.w.setDriver(w) 186 defer w.w.event(DestroyEvent{}) 187 showWindow(w.hwnd, _SW_SHOWDEFAULT) 188 setForegroundWindow(w.hwnd) 189 setFocus(w.hwnd) 190 if err := w.loop(); err != nil { 191 panic(err) 192 } 193 close(mainDone) 194 }() 195 return <-cerr 196 } 197 198 func createNativeWindow(opts *windowOptions) (*window, error) { 199 setProcessDPIAware() 200 screenDC, err := getDC(0) 201 if err != nil { 202 return nil, err 203 } 204 cfg := configForDC(screenDC) 205 releaseDC(screenDC) 206 hInst, err := getModuleHandle() 207 if err != nil { 208 return nil, err 209 } 210 curs, err := loadCursor(_IDC_ARROW) 211 if err != nil { 212 return nil, err 213 } 214 wcls := wndClassEx{ 215 cbSize: uint32(unsafe.Sizeof(wndClassEx{})), 216 style: _CS_HREDRAW | _CS_VREDRAW | _CS_OWNDC, 217 lpfnWndProc: syscall.NewCallback(windowProc), 218 hInstance: hInst, 219 hCursor: curs, 220 lpszClassName: syscall.StringToUTF16Ptr("GioWindow"), 221 } 222 cls, err := registerClassEx(&wcls) 223 if err != nil { 224 return nil, err 225 } 226 wr := rect{ 227 right: int32(cfg.Px(opts.Width)), 228 bottom: int32(cfg.Px(opts.Height)), 229 } 230 dwStyle := uint32(_WS_OVERLAPPEDWINDOW) 231 dwExStyle := uint32(_WS_EX_APPWINDOW | _WS_EX_WINDOWEDGE) 232 adjustWindowRectEx(&wr, dwStyle, 0, dwExStyle) 233 hwnd, err := createWindowEx(dwExStyle, 234 cls, 235 opts.Title, 236 dwStyle|_WS_CLIPSIBLINGS|_WS_CLIPCHILDREN, 237 _CW_USEDEFAULT, _CW_USEDEFAULT, 238 wr.right-wr.left, 239 wr.bottom-wr.top, 240 0, 241 0, 242 hInst, 243 0) 244 if err != nil { 245 return nil, err 246 } 247 w := &window{ 248 hwnd: hwnd, 249 } 250 w.hdc, err = getDC(hwnd) 251 if err != nil { 252 return nil, err 253 } 254 return w, nil 255 } 256 257 func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr { 258 w := winMap[hwnd] 259 switch msg { 260 case _WM_UNICHAR: 261 if wParam == _UNICODE_NOCHAR { 262 // Tell the system that we accept WM_UNICHAR messages. 263 return 1 264 } 265 fallthrough 266 case _WM_CHAR: 267 if r := rune(wParam); unicode.IsPrint(r) { 268 w.w.event(key.EditEvent{Text: string(r)}) 269 } 270 // The message is processed. 271 return 1 272 case _WM_KEYDOWN, _WM_SYSKEYDOWN: 273 if n, ok := convertKeyCode(wParam); ok { 274 cmd := key.Event{Name: n} 275 if getKeyState(_VK_CONTROL)&0x1000 != 0 { 276 cmd.Modifiers |= key.ModCommand 277 } 278 if getKeyState(_VK_SHIFT)&0x1000 != 0 { 279 cmd.Modifiers |= key.ModShift 280 } 281 w.w.event(cmd) 282 } 283 case _WM_LBUTTONDOWN: 284 setCapture(w.hwnd) 285 x, y := coordsFromlParam(lParam) 286 p := f32.Point{X: float32(x), Y: float32(y)} 287 w.w.event(pointer.Event{ 288 Type: pointer.Press, 289 Source: pointer.Mouse, 290 Position: p, 291 Time: getMessageTime(), 292 }) 293 case _WM_CANCELMODE: 294 w.w.event(pointer.Event{ 295 Type: pointer.Cancel, 296 }) 297 case _WM_SETFOCUS: 298 w.w.event(key.FocusEvent{Focus: true}) 299 case _WM_KILLFOCUS: 300 w.w.event(key.FocusEvent{Focus: false}) 301 case _WM_LBUTTONUP: 302 releaseCapture() 303 x, y := coordsFromlParam(lParam) 304 p := f32.Point{X: float32(x), Y: float32(y)} 305 w.w.event(pointer.Event{ 306 Type: pointer.Release, 307 Source: pointer.Mouse, 308 Position: p, 309 Time: getMessageTime(), 310 }) 311 case _WM_MOUSEMOVE: 312 x, y := coordsFromlParam(lParam) 313 p := f32.Point{X: float32(x), Y: float32(y)} 314 w.w.event(pointer.Event{ 315 Type: pointer.Move, 316 Source: pointer.Mouse, 317 Position: p, 318 Time: getMessageTime(), 319 }) 320 case _WM_MOUSEWHEEL: 321 w.scrollEvent(wParam, lParam) 322 case _WM_DESTROY: 323 w.dead = true 324 case _WM_PAINT: 325 w.draw(true) 326 case _WM_SIZE: 327 switch wParam { 328 case _SIZE_MINIMIZED: 329 w.setStage(StagePaused) 330 case _SIZE_MAXIMIZED, _SIZE_RESTORED: 331 w.setStage(StageRunning) 332 w.draw(true) 333 } 334 } 335 return defWindowProc(hwnd, msg, wParam, lParam) 336 } 337 338 func coordsFromlParam(lParam uintptr) (int, int) { 339 x := int(int16(lParam & 0xffff)) 340 y := int(int16((lParam >> 16) & 0xffff)) 341 return x, y 342 } 343 344 func (w *window) scrollEvent(wParam, lParam uintptr) { 345 x, y := coordsFromlParam(lParam) 346 // The WM_MOUSEWHEEL coordinates are in screen coordinates, in contrast 347 // to other mouse events. 348 np := point{x: int32(x), y: int32(y)} 349 screenToClient(w.hwnd, &np) 350 p := f32.Point{X: float32(np.x), Y: float32(np.y)} 351 dist := float32(int16(wParam >> 16)) 352 w.w.event(pointer.Event{ 353 Type: pointer.Move, 354 Source: pointer.Mouse, 355 Position: p, 356 Scroll: f32.Point{Y: -dist}, 357 Time: getMessageTime(), 358 }) 359 } 360 361 // Adapted from https://blogs.msdn.microsoft.com/oldnewthing/20060126-00/?p=32513/ 362 func (w *window) loop() error { 363 msg := new(msg) 364 for !w.dead { 365 w.mu.Lock() 366 anim := w.animating 367 w.mu.Unlock() 368 if anim && !peekMessage(msg, w.hwnd, 0, 0, _PM_NOREMOVE) { 369 w.draw(false) 370 continue 371 } 372 getMessage(msg, w.hwnd, 0, 0) 373 if msg.message == _WM_QUIT { 374 postQuitMessage(msg.wParam) 375 break 376 } 377 translateMessage(msg) 378 dispatchMessage(msg) 379 } 380 return nil 381 } 382 383 func (w *window) setAnimating(anim bool) { 384 w.mu.Lock() 385 w.animating = anim 386 w.mu.Unlock() 387 if anim { 388 w.postRedraw() 389 } 390 } 391 392 func (w *window) postRedraw() { 393 if err := postMessage(w.hwnd, _WM_REDRAW, 0, 0); err != nil { 394 panic(err) 395 } 396 } 397 398 func (w *window) setStage(s Stage) { 399 w.stage = s 400 w.w.event(StageEvent{s}) 401 } 402 403 func (w *window) draw(sync bool) { 404 var r rect 405 getClientRect(w.hwnd, &r) 406 w.width = int(r.right - r.left) 407 w.height = int(r.bottom - r.top) 408 cfg := configForDC(w.hdc) 409 cfg.now = time.Now() 410 w.w.event(UpdateEvent{ 411 Size: image.Point{ 412 X: w.width, 413 Y: w.height, 414 }, 415 Config: cfg, 416 sync: sync, 417 }) 418 } 419 420 func (w *window) destroy() { 421 if w.hdc != 0 { 422 releaseDC(w.hdc) 423 w.hdc = 0 424 } 425 if w.hwnd != 0 { 426 destroyWindow(w.hwnd) 427 w.hwnd = 0 428 } 429 } 430 431 func (w *window) showTextInput(show bool) {} 432 433 func (w *window) display() uintptr { 434 return uintptr(w.hdc) 435 } 436 437 func (w *window) nativeWindow(visID int) (uintptr, int, int) { 438 return uintptr(w.hwnd), w.width, w.height 439 } 440 441 func convertKeyCode(code uintptr) (rune, bool) { 442 if '0' <= code && code <= '9' || 'A' <= code && code <= 'Z' { 443 return rune(code), true 444 } 445 var r rune 446 switch code { 447 case _VK_ESCAPE: 448 r = key.NameEscape 449 case _VK_LEFT: 450 r = key.NameLeftArrow 451 case _VK_RIGHT: 452 r = key.NameRightArrow 453 case _VK_RETURN: 454 r = key.NameReturn 455 case _VK_UP: 456 r = key.NameUpArrow 457 case _VK_DOWN: 458 r = key.NameDownArrow 459 case _VK_HOME: 460 r = key.NameHome 461 case _VK_END: 462 r = key.NameEnd 463 case _VK_BACK: 464 r = key.NameDeleteBackward 465 case _VK_DELETE: 466 r = key.NameDeleteForward 467 case _VK_PRIOR: 468 r = key.NamePageUp 469 case _VK_NEXT: 470 r = key.NamePageDown 471 default: 472 return 0, false 473 } 474 return r, true 475 } 476 477 func configForDC(hdc syscall.Handle) Config { 478 dpi := getDeviceCaps(hdc, _LOGPIXELSX) 479 ppdp := float32(dpi) * inchPrDp * monitorScale 480 // Force a minimum density to keep text legible and to handle bogus output geometry. 481 if ppdp < minDensity { 482 ppdp = minDensity 483 } 484 return Config{ 485 pxPerDp: ppdp, 486 pxPerSp: ppdp, 487 } 488 } 489 490 var ( 491 kernel32 = syscall.NewLazySystemDLL("kernel32.dll") 492 _GetModuleHandleW = kernel32.NewProc("GetModuleHandleW") 493 494 user32 = syscall.NewLazySystemDLL("user32.dll") 495 _AdjustWindowRectEx = user32.NewProc("AdjustWindowRectEx") 496 _CallMsgFilter = user32.NewProc("CallMsgFilterW") 497 _CreateWindowEx = user32.NewProc("CreateWindowExW") 498 _DefWindowProc = user32.NewProc("DefWindowProcW") 499 _DestroyWindow = user32.NewProc("DestroyWindow") 500 _DispatchMessage = user32.NewProc("DispatchMessageW") 501 _GetClientRect = user32.NewProc("GetClientRect") 502 _GetDC = user32.NewProc("GetDC") 503 _GetKeyState = user32.NewProc("GetKeyState") 504 _GetMessage = user32.NewProc("GetMessageW") 505 _GetMessageTime = user32.NewProc("GetMessageTime") 506 _KillTimer = user32.NewProc("KillTimer") 507 _LoadCursor = user32.NewProc("LoadCursorW") 508 _MsgWaitForMultipleObjectsEx = user32.NewProc("MsgWaitForMultipleObjectsEx") 509 _PeekMessage = user32.NewProc("PeekMessageW") 510 _PostMessage = user32.NewProc("PostMessageW") 511 _PostQuitMessage = user32.NewProc("PostQuitMessage") 512 _ReleaseCapture = user32.NewProc("ReleaseCapture") 513 _RegisterClassExW = user32.NewProc("RegisterClassExW") 514 _ReleaseDC = user32.NewProc("ReleaseDC") 515 _ScreenToClient = user32.NewProc("ScreenToClient") 516 _ShowWindow = user32.NewProc("ShowWindow") 517 _SetCapture = user32.NewProc("SetCapture") 518 _SetForegroundWindow = user32.NewProc("SetForegroundWindow") 519 _SetFocus = user32.NewProc("SetFocus") 520 _SetProcessDPIAware = user32.NewProc("SetProcessDPIAware") 521 _SetTimer = user32.NewProc("SetTimer") 522 _TranslateMessage = user32.NewProc("TranslateMessage") 523 _UnregisterClass = user32.NewProc("UnregisterClassW") 524 _UpdateWindow = user32.NewProc("UpdateWindow") 525 526 gdi32 = syscall.NewLazySystemDLL("gdi32") 527 _GetDeviceCaps = gdi32.NewProc("GetDeviceCaps") 528 ) 529 530 func getModuleHandle() (syscall.Handle, error) { 531 h, _, err := _GetModuleHandleW.Call(uintptr(0)) 532 if h == 0 { 533 return 0, fmt.Errorf("GetModuleHandleW failed: %v", err) 534 } 535 return syscall.Handle(h), nil 536 } 537 538 func adjustWindowRectEx(r *rect, dwStyle uint32, bMenu int, dwExStyle uint32) { 539 _AdjustWindowRectEx.Call(uintptr(unsafe.Pointer(r)), uintptr(dwStyle), uintptr(bMenu), uintptr(dwExStyle)) 540 issue34474KeepAlive(r) 541 } 542 543 func callMsgFilter(m *msg, nCode uintptr) bool { 544 r, _, _ := _CallMsgFilter.Call(uintptr(unsafe.Pointer(m)), nCode) 545 issue34474KeepAlive(m) 546 return r != 0 547 } 548 549 func createWindowEx(dwExStyle uint32, lpClassName uint16, lpWindowName string, dwStyle uint32, x, y, w, h int32, hWndParent, hMenu, hInstance syscall.Handle, lpParam uintptr) (syscall.Handle, error) { 550 wname := syscall.StringToUTF16Ptr(lpWindowName) 551 hwnd, _, err := _CreateWindowEx.Call( 552 uintptr(dwExStyle), 553 uintptr(lpClassName), 554 uintptr(unsafe.Pointer(wname)), 555 uintptr(dwStyle), 556 uintptr(x), uintptr(y), 557 uintptr(w), uintptr(h), 558 uintptr(hWndParent), 559 uintptr(hMenu), 560 uintptr(hInstance), 561 uintptr(lpParam)) 562 issue34474KeepAlive(wname) 563 if hwnd == 0 { 564 return 0, fmt.Errorf("CreateWindowEx failed: %v", err) 565 } 566 return syscall.Handle(hwnd), nil 567 } 568 569 func defWindowProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) uintptr { 570 r, _, _ := _DefWindowProc.Call(uintptr(hwnd), uintptr(msg), wparam, lparam) 571 return r 572 } 573 574 func destroyWindow(hwnd syscall.Handle) { 575 _DestroyWindow.Call(uintptr(hwnd)) 576 } 577 578 func dispatchMessage(m *msg) { 579 _DispatchMessage.Call(uintptr(unsafe.Pointer(m))) 580 issue34474KeepAlive(m) 581 } 582 583 func getClientRect(hwnd syscall.Handle, r *rect) { 584 _GetClientRect.Call(uintptr(hwnd), uintptr(unsafe.Pointer(r))) 585 issue34474KeepAlive(r) 586 } 587 588 func getDC(hwnd syscall.Handle) (syscall.Handle, error) { 589 hdc, _, err := _GetDC.Call(uintptr(hwnd)) 590 if hdc == 0 { 591 return 0, fmt.Errorf("GetDC failed: %v", err) 592 } 593 return syscall.Handle(hdc), nil 594 } 595 596 func getDeviceCaps(hdc syscall.Handle, index int32) int { 597 c, _, _ := _GetDeviceCaps.Call(uintptr(hdc), uintptr(index)) 598 return int(c) 599 } 600 601 func getKeyState(nVirtKey int32) int16 { 602 c, _, _ := _GetKeyState.Call(uintptr(nVirtKey)) 603 return int16(c) 604 } 605 606 func getMessage(m *msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax uint32) int32 { 607 r, _, _ := _GetMessage.Call(uintptr(unsafe.Pointer(m)), 608 uintptr(hwnd), 609 uintptr(wMsgFilterMin), 610 uintptr(wMsgFilterMax)) 611 issue34474KeepAlive(m) 612 return int32(r) 613 } 614 615 func getMessageTime() time.Duration { 616 r, _, _ := _GetMessageTime.Call() 617 return time.Duration(r) * time.Millisecond 618 } 619 620 func killTimer(hwnd syscall.Handle, nIDEvent uintptr) error { 621 r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), 0, 0) 622 if r == 0 { 623 return fmt.Errorf("KillTimer failed: %v", err) 624 } 625 return nil 626 } 627 628 func loadCursor(curID uint16) (syscall.Handle, error) { 629 h, _, err := _LoadCursor.Call(0, uintptr(curID)) 630 if h == 0 { 631 return 0, fmt.Errorf("LoadCursorW failed: %v", err) 632 } 633 return syscall.Handle(h), nil 634 } 635 636 func msgWaitForMultipleObjectsEx(nCount uint32, pHandles uintptr, millis, mask, flags uint32) (uint32, error) { 637 r, _, err := _MsgWaitForMultipleObjectsEx.Call(uintptr(nCount), pHandles, uintptr(millis), uintptr(mask), uintptr(flags)) 638 res := uint32(r) 639 if res == 0xFFFFFFFF { 640 return 0, fmt.Errorf("MsgWaitForMultipleObjectsEx failed: %v", err) 641 } 642 return res, nil 643 } 644 645 func peekMessage(m *msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool { 646 r, _, _ := _PeekMessage.Call(uintptr(unsafe.Pointer(m)), uintptr(hwnd), uintptr(wMsgFilterMin), uintptr(wMsgFilterMax), uintptr(wRemoveMsg)) 647 issue34474KeepAlive(m) 648 return r != 0 649 } 650 651 func postQuitMessage(exitCode uintptr) { 652 _PostQuitMessage.Call(exitCode) 653 } 654 655 func postMessage(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) error { 656 r, _, err := _PostMessage.Call(uintptr(hwnd), uintptr(msg), wParam, lParam) 657 if r == 0 { 658 return fmt.Errorf("PostMessage failed: %v", err) 659 } 660 return nil 661 } 662 663 func releaseCapture() bool { 664 r, _, _ := _ReleaseCapture.Call() 665 return r != 0 666 } 667 668 func registerClassEx(cls *wndClassEx) (uint16, error) { 669 a, _, err := _RegisterClassExW.Call(uintptr(unsafe.Pointer(cls))) 670 issue34474KeepAlive(cls) 671 if a == 0 { 672 return 0, fmt.Errorf("RegisterClassExW failed: %v", err) 673 } 674 return uint16(a), nil 675 } 676 677 func releaseDC(hdc syscall.Handle) { 678 _ReleaseDC.Call(uintptr(hdc)) 679 } 680 681 func setForegroundWindow(hwnd syscall.Handle) { 682 _SetForegroundWindow.Call(uintptr(hwnd)) 683 } 684 685 func setFocus(hwnd syscall.Handle) { 686 _SetFocus.Call(uintptr(hwnd)) 687 } 688 689 func setProcessDPIAware() { 690 _SetProcessDPIAware.Call() 691 } 692 693 func setCapture(hwnd syscall.Handle) syscall.Handle { 694 r, _, _ := _SetCapture.Call(uintptr(hwnd)) 695 return syscall.Handle(r) 696 } 697 698 func setTimer(hwnd syscall.Handle, nIDEvent uintptr, uElapse uint32, timerProc uintptr) error { 699 r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), uintptr(uElapse), timerProc) 700 if r == 0 { 701 return fmt.Errorf("SetTimer failed: %v", err) 702 } 703 return nil 704 } 705 706 func screenToClient(hwnd syscall.Handle, p *point) { 707 _ScreenToClient.Call(uintptr(hwnd), uintptr(unsafe.Pointer(p))) 708 issue34474KeepAlive(p) 709 } 710 711 func showWindow(hwnd syscall.Handle, nCmdShow int32) { 712 _ShowWindow.Call(uintptr(hwnd), uintptr(nCmdShow)) 713 } 714 715 func translateMessage(m *msg) { 716 _TranslateMessage.Call(uintptr(unsafe.Pointer(m))) 717 issue34474KeepAlive(m) 718 } 719 720 func unregisterClass(cls uint16, hInst syscall.Handle) { 721 _UnregisterClass.Call(uintptr(cls), uintptr(hInst)) 722 } 723 724 func updateWindow(hwnd syscall.Handle) { 725 _UpdateWindow.Call(uintptr(hwnd)) 726 } 727 728 // issue34474KeepAlive calls runtime.KeepAlive as a 729 // workaround for golang.org/issue/34474. 730 func issue34474KeepAlive(v interface{}) { 731 runtime.KeepAlive(v) 732 }