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  }