From 25df2e86bc59de0601fec1d178bd0c304cb4b26c Mon Sep 17 00:00:00 2001 From: Nick Khyl Date: Mon, 14 Apr 2025 17:02:47 -0500 Subject: [PATCH] ipn/desktop: fix panics on Windows 10, x86 [G,S]etWindowLongPtrW are not available on 32-bit Windows, where [G,S]etWindowLongW should be used instead. The initial revision of #14945 imported the win package for calling and other Win32 API functions, which exported the correct API depending on the platform. However, the same logic wasn't implemented when we removed the win package dependency in a later revision, resulting in panics on Windows 10 x86 (there's no 32-bit Windows 11). In this PR, we update the ipn/desktop package to use either [G,S]etWindowLongPtrW or [G,S]etWindowLongW depending on the platform. Fixes #15684 Signed-off-by: Nick Khyl (cherry picked from commit 60614fa) --- ipn/desktop/mksyscall.go | 2 -- ipn/desktop/sessions_windows.go | 35 +++++++++++++++++++++++++++++++++ ipn/desktop/zsyscall_windows.go | 20 ------------------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/ipn/desktop/mksyscall.go b/ipn/desktop/mksyscall.go index 305138468..b7af12366 100644 --- a/ipn/desktop/mksyscall.go +++ b/ipn/desktop/mksyscall.go @@ -11,8 +11,6 @@ package desktop //sys registerClassEx(windowClass *_WNDCLASSEX) (atom uint16, err error) [atom==0] = user32.RegisterClassExW //sys createWindowEx(dwExStyle uint32, lpClassName *uint16, lpWindowName *uint16, dwStyle uint32, x int32, y int32, nWidth int32, nHeight int32, hWndParent windows.HWND, hMenu windows.Handle, hInstance windows.Handle, lpParam unsafe.Pointer) (hWnd windows.HWND, err error) [hWnd==0] = user32.CreateWindowExW //sys defWindowProc(hwnd windows.HWND, msg uint32, wparam uintptr, lparam uintptr) (res uintptr) = user32.DefWindowProcW -//sys setWindowLongPtr(hwnd windows.HWND, index int32, newLong uintptr) (res uintptr, err error) [res==0 && e1!=0] = user32.SetWindowLongPtrW -//sys getWindowLongPtr(hwnd windows.HWND, index int32) (res uintptr, err error) [res==0 && e1!=0] = user32.GetWindowLongPtrW //sys sendMessage(hwnd windows.HWND, msg uint32, wparam uintptr, lparam uintptr) (res uintptr) = user32.SendMessageW //sys getMessage(lpMsg *_MSG, hwnd windows.HWND, msgMin uint32, msgMax uint32) (ret int32) = user32.GetMessageW //sys translateMessage(lpMsg *_MSG) (res bool) = user32.TranslateMessage diff --git a/ipn/desktop/sessions_windows.go b/ipn/desktop/sessions_windows.go index b26172d77..83b884228 100644 --- a/ipn/desktop/sessions_windows.go +++ b/ipn/desktop/sessions_windows.go @@ -670,3 +670,38 @@ func (cs _WTS_CONNECTSTATE_CLASS) ToSessionStatus() SessionStatus { return ClosedSession } } + +var ( + procGetWindowLongPtrW *windows.LazyProc + procSetWindowLongPtrW *windows.LazyProc +) + +func init() { + // GetWindowLongPtrW and SetWindowLongPtrW are only available on 64-bit platforms. + // https://web.archive.org/web/20250414195520/https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowlongptrw + if runtime.GOARCH == "386" || runtime.GOARCH == "arm" { + procGetWindowLongPtrW = moduser32.NewProc("GetWindowLongW") + procSetWindowLongPtrW = moduser32.NewProc("SetWindowLongW") + } else { + procGetWindowLongPtrW = moduser32.NewProc("GetWindowLongPtrW") + procSetWindowLongPtrW = moduser32.NewProc("SetWindowLongPtrW") + } +} + +func getWindowLongPtr(hwnd windows.HWND, index int32) (res uintptr, err error) { + r0, _, e1 := syscall.Syscall(procGetWindowLongPtrW.Addr(), 2, uintptr(hwnd), uintptr(index), 0) + res = uintptr(r0) + if res == 0 && e1 != 0 { + err = errnoErr(e1) + } + return +} + +func setWindowLongPtr(hwnd windows.HWND, index int32, newLong uintptr) (res uintptr, err error) { + r0, _, e1 := syscall.Syscall(procSetWindowLongPtrW.Addr(), 3, uintptr(hwnd), uintptr(index), uintptr(newLong)) + res = uintptr(r0) + if res == 0 && e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/ipn/desktop/zsyscall_windows.go b/ipn/desktop/zsyscall_windows.go index 222ab49e5..535274016 100644 --- a/ipn/desktop/zsyscall_windows.go +++ b/ipn/desktop/zsyscall_windows.go @@ -48,11 +48,9 @@ var ( procDestroyWindow = moduser32.NewProc("DestroyWindow") procDispatchMessageW = moduser32.NewProc("DispatchMessageW") procGetMessageW = moduser32.NewProc("GetMessageW") - procGetWindowLongPtrW = moduser32.NewProc("GetWindowLongPtrW") procPostQuitMessage = moduser32.NewProc("PostQuitMessage") procRegisterClassExW = moduser32.NewProc("RegisterClassExW") procSendMessageW = moduser32.NewProc("SendMessageW") - procSetWindowLongPtrW = moduser32.NewProc("SetWindowLongPtrW") procTranslateMessage = moduser32.NewProc("TranslateMessage") procWTSRegisterSessionNotificationEx = modwtsapi32.NewProc("WTSRegisterSessionNotificationEx") procWTSUnRegisterSessionNotificationEx = modwtsapi32.NewProc("WTSUnRegisterSessionNotificationEx") @@ -98,15 +96,6 @@ func getMessage(lpMsg *_MSG, hwnd windows.HWND, msgMin uint32, msgMax uint32) (r return } -func getWindowLongPtr(hwnd windows.HWND, index int32) (res uintptr, err error) { - r0, _, e1 := syscall.Syscall(procGetWindowLongPtrW.Addr(), 2, uintptr(hwnd), uintptr(index), 0) - res = uintptr(r0) - if res == 0 && e1 != 0 { - err = errnoErr(e1) - } - return -} - func postQuitMessage(exitCode int32) { syscall.Syscall(procPostQuitMessage.Addr(), 1, uintptr(exitCode), 0, 0) return @@ -127,15 +116,6 @@ func sendMessage(hwnd windows.HWND, msg uint32, wparam uintptr, lparam uintptr) return } -func setWindowLongPtr(hwnd windows.HWND, index int32, newLong uintptr) (res uintptr, err error) { - r0, _, e1 := syscall.Syscall(procSetWindowLongPtrW.Addr(), 3, uintptr(hwnd), uintptr(index), uintptr(newLong)) - res = uintptr(r0) - if res == 0 && e1 != 0 { - err = errnoErr(e1) - } - return -} - func translateMessage(lpMsg *_MSG) (res bool) { r0, _, _ := syscall.Syscall(procTranslateMessage.Addr(), 1, uintptr(unsafe.Pointer(lpMsg)), 0, 0) res = r0 != 0