diff --git a/stdwndclass_windows.go b/stdwndclass_windows.go index d57cc20..44af126 100644 --- a/stdwndclass_windows.go +++ b/stdwndclass_windows.go @@ -31,8 +31,53 @@ func defWindowProc(hwnd _HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM) _LRE return _LRESULT(r1) } -func stdWndProc(s *sysData) func(hwnd _HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM) _LRESULT { +// don't worry about error returns from GetWindowLongPtr()/SetWindowLongPtr() +// see comments of http://blogs.msdn.com/b/oldnewthing/archive/2014/02/03/10496248.aspx + +func getWindowLongPtr(hwnd _HWND, what uintptr) uintptr { + r1, _, _ := _getWindowLongPtr.Call( + uintptr(hwnd), + what) + return r1 +} + +func setWindowLongPtr(hwnd _HWND, what uintptr, value uintptr) { + _setWindowLongPtr.Call( + uintptr(hwnd), + what, + value) +} + +// we can store a pointer in extra space provided by Windows +// we'll store sysData there +// see http://blogs.msdn.com/b/oldnewthing/archive/2005/03/03/384285.aspx +func getSysData(hwnd _HWND) *sysData { + return (*sysData)(unsafe.Pointer(getWindowLongPtr(hwnd, negConst(_GWLP_USERDATA)))) +} + +func storeSysData(hwnd _HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM) _LRESULT { + // we can get the lpParam from CreateWindowEx() in WM_NCCREATE and WM_CREATE + // we can freely skip any messages that come prior + // see http://blogs.msdn.com/b/oldnewthing/archive/2005/04/22/410773.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2014/02/03/10496248.aspx (note the date on the latter one!) + if uMsg == _WM_NCCREATE { + // the lpParam to CreateWindowEx() is the first uintptr of the CREATESTRUCT + // so rather than create that whole structure, we'll just grab the uintptr at the address pointed to by lParam + cs := (*uintptr)(unsafe.Pointer(lParam)) + saddr := *cs + setWindowLongPtr(hwnd, negConst(_GWLP_USERDATA), saddr) + // don't set s; we return here + } + // TODO is this correct for WM_NCCREATE? I think the above link does it but I'm not entirely sure... + return defWindowProc(hwnd, uMsg, wParam, lParam) +} + +func stdWndProc(unused *sysData) func(hwnd _HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM) _LRESULT { return func(hwnd _HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM) _LRESULT { + s := getSysData(hwnd) + if s == nil { // not yet saved + return storeSysData(hwnd, uMsg, wParam, lParam) + } + switch uMsg { case _WM_COMMAND: id := _HMENU(wParam.LOWORD()) diff --git a/sysdata_windows.go b/sysdata_windows.go index b9df277..f813de3 100644 --- a/sysdata_windows.go +++ b/sysdata_windows.go @@ -30,6 +30,7 @@ type classData struct { xstyle uint32 mkid bool altStyle uint32 + storeSysData bool doNotLoadFont bool appendMsg uintptr insertBeforeMsg uintptr @@ -48,6 +49,7 @@ var classTypes = [nctypes]*classData{ register: registerStdWndClass, style: _WS_OVERLAPPEDWINDOW, xstyle: 0, + storeSysData: true, doNotLoadFont: true, }, c_button: &classData{ @@ -157,6 +159,10 @@ func (s *sysData) make(window *sysData) (err error) { if s.alternate { style = uintptr(ct.altStyle) } + lpParam := uintptr(_NULL) + if ct.storeSysData { + lpParam = uintptr(unsafe.Pointer(s)) + } uitask <- &uimsg{ call: _createWindowEx, p: []uintptr{ @@ -171,7 +177,7 @@ func (s *sysData) make(window *sysData) (err error) { pwin, uintptr(cid), uintptr(hInstance), - uintptr(_NULL), + lpParam, }, ret: ret, } diff --git a/tools/windowsconstgen.go b/tools/windowsconstgen.go index 6be1b59..777324d 100644 --- a/tools/windowsconstgen.go +++ b/tools/windowsconstgen.go @@ -110,8 +110,8 @@ func preamble(pkg string) string { // for backwards compatibiilty reasons, Windows defines GetWindowLongPtr()/SetWindowLongPtr() as a macro which expands to GetWindowLong()/SetWindowLong() on 32-bit systems // we'll just simulate that here var gwlpNames = map[string]string{ - "386": "etWindowLong", - "amd64": "etWindowLongPtr", + "386": "etWindowLongW", + "amd64": "etWindowLongPtrW", } func printConst(f *os.File, goconst string, winconst string) { diff --git a/zconstants_windows_386.go b/zconstants_windows_386.go index c1d88c2..fa0ab76 100644 --- a/zconstants_windows_386.go +++ b/zconstants_windows_386.go @@ -28,6 +28,7 @@ const _ERROR = 0 const _ES_AUTOHSCROLL = 128 const _ES_PASSWORD = 32 const _FALSE = 0 +const _GWLP_USERDATA = -21 const _GWL_STYLE = -16 const _ICC_PROGRESS_CLASS = 32 const _LBS_EXTENDEDSEL = 2048 @@ -140,6 +141,7 @@ const _WM_MBUTTONDOWN = 519 const _WM_MBUTTONUP = 520 const _WM_MOUSEACTIVATE = 33 const _WM_MOUSEMOVE = 512 +const _WM_NCCREATE = 129 const _WM_PAINT = 15 const _WM_RBUTTONDOWN = 516 const _WM_RBUTTONUP = 517 @@ -162,5 +164,5 @@ const _IDC_ARROW = 32512 const _IDI_APPLICATION = 32512 const _INVALID_HANDLE_VALUE = 4294967295 const _NULL = 0 -var _getWindowLongPtr = user32.NewProc("GetWindowLong") -var _setWindowLongPtr = user32.NewProc("SetWindowLong") +var _getWindowLongPtr = user32.NewProc("GetWindowLongW") +var _setWindowLongPtr = user32.NewProc("SetWindowLongW") diff --git a/zconstants_windows_amd64.go b/zconstants_windows_amd64.go index 4d3c1c3..54bbae8 100644 --- a/zconstants_windows_amd64.go +++ b/zconstants_windows_amd64.go @@ -28,6 +28,7 @@ const _ERROR = 0 const _ES_AUTOHSCROLL = 128 const _ES_PASSWORD = 32 const _FALSE = 0 +const _GWLP_USERDATA = -21 const _GWL_STYLE = -16 const _ICC_PROGRESS_CLASS = 32 const _LBS_EXTENDEDSEL = 2048 @@ -140,6 +141,7 @@ const _WM_MBUTTONDOWN = 519 const _WM_MBUTTONUP = 520 const _WM_MOUSEACTIVATE = 33 const _WM_MOUSEMOVE = 512 +const _WM_NCCREATE = 129 const _WM_PAINT = 15 const _WM_RBUTTONDOWN = 516 const _WM_RBUTTONUP = 517 @@ -162,5 +164,5 @@ const _IDC_ARROW = 32512 const _IDI_APPLICATION = 32512 const _INVALID_HANDLE_VALUE = 18446744073709551615 const _NULL = 0 -var _getWindowLongPtr = user32.NewProc("GetWindowLongPtr") -var _setWindowLongPtr = user32.NewProc("SetWindowLongPtr") +var _getWindowLongPtr = user32.NewProc("GetWindowLongPtrW") +var _setWindowLongPtr = user32.NewProc("SetWindowLongPtrW")