Repository: kivy/kivy

Issue:
SetWindowLongW fails on win-amd64
SetWindowLongW is used in kivy/input/providers/wm_touch.py and wm_pen.py. This function has been superseded by the SetWindowLongPtrW function, which provides compatibility with both 32-bit and 64-bit versions of Windows. See http://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx and http://msdn.microsoft.com/en-us/library/windows/desktop/ms644898%28v=vs.85%29.aspx.



Discussion:

Resolving patch:
diff --git a/kivy/input/providers/wm_pen.py b/kivy/input/providers/wm_pen.py
--- a/kivy/input/providers/wm_pen.py
+++ b/kivy/input/providers/wm_pen.py
@@ -6,10 +6,10 @@
 __all__ = ('WM_PenProvider', 'WM_Pen')
 
 import os
-from kivy.input.providers.wm_common import PEN_OR_TOUCH_SIGNATURE, \
-        PEN_OR_TOUCH_MASK, GWL_WNDPROC, WM_MOUSEMOVE, WM_LBUTTONUP, \
-        WM_LBUTTONDOWN, WM_TABLET_QUERYSYSTEMGESTURE, \
-        QUERYSYSTEMGESTURE_WNDPROC, PEN_EVENT_TOUCH_MASK
+from kivy.input.providers.wm_common import (PEN_OR_TOUCH_SIGNATURE,
+        PEN_OR_TOUCH_MASK, GWL_WNDPROC, WM_MOUSEMOVE, WM_LBUTTONUP,
+        WM_LBUTTONDOWN, WM_TABLET_QUERYSYSTEMGESTURE,
+        QUERYSYSTEMGESTURE_WNDPROC, PEN_EVENT_TOUCH_MASK)
 from kivy.input.motionevent import MotionEvent
 
 
@@ -30,13 +30,15 @@ def __str__(self):
 
 else:
     from collections import deque
-    from ctypes.wintypes import ULONG
-    from ctypes import Structure, windll, byref, c_int16, \
-            c_int, c_long, WINFUNCTYPE
+    from ctypes.wintypes import (ULONG, UINT, WPARAM, LPARAM,
+                                 HANDLE, BOOL, POINTER)
+    from ctypes import (Structure, windll, byref, c_int16,
+                        c_int, WINFUNCTYPE)
     from kivy.input.provider import MotionEventProvider
     from kivy.input.factory import MotionEventFactory
 
-    WNDPROC = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int)
+    LRESULT = LPARAM
+    WNDPROC = WINFUNCTYPE(LRESULT, HANDLE, UINT, WPARAM, LPARAM)
 
     class RECT(Structure):
         _fields_ = [
@@ -51,6 +53,18 @@ class RECT(Structure):
         h = property(lambda self: self.bottom-self.top)
     win_rect = RECT()
 
+    windll.user32.SetWindowLongPtrW.restype = WNDPROC
+    windll.user32.SetWindowLongPtrW.argtypes = [HANDLE, c_int, WNDPROC]
+    windll.user32.GetMessageExtraInfo.restype = LPARAM
+    windll.user32.GetMessageExtraInfo.argtypes = []
+    windll.user32.GetClientRect.restype = BOOL
+    windll.user32.GetClientRect.argtypes = [HANDLE, POINTER(RECT)]
+    windll.user32.CallWindowProcW.restype = LRESULT
+    windll.user32.CallWindowProcW.argtypes = [WNDPROC, HANDLE, UINT, WPARAM,
+                                              LPARAM]
+    windll.user32.GetActiveWindow.restype = HANDLE
+    windll.user32.GetActiveWindow.argtypes = []
+
     class WM_PenProvider(MotionEventProvider):
 
         def _is_pen_message(self, msg):
@@ -101,7 +115,7 @@ def start(self):
             # inject our own wndProc to handle messages
             # before window manager does
             self.new_windProc = WNDPROC(self._pen_wndProc)
-            self.old_windProc = windll.user32.SetWindowLongW(
+            self.old_windProc = windll.user32.SetWindowLongPtrW(
                 self.hwnd,
                 GWL_WNDPROC,
                 self.new_windProc)
@@ -126,7 +140,7 @@ def update(self, dispatch_fn):
 
         def stop(self):
             self.pen = None
-            windll.user32.SetWindowLongW(
+            windll.user32.SetWindowLongPtrW(
                 self.hwnd,
                 GWL_WNDPROC,
                 self.old_windProc)
diff --git a/kivy/input/providers/wm_touch.py b/kivy/input/providers/wm_touch.py
--- a/kivy/input/providers/wm_touch.py
+++ b/kivy/input/providers/wm_touch.py
@@ -6,11 +6,11 @@
 __all__ = ('WM_MotionEventProvider', 'WM_MotionEvent')
 
 import os
-from kivy.input.providers.wm_common import WM_TABLET_QUERYSYSTEMGESTURE, \
-        GWL_WNDPROC, QUERYSYSTEMGESTURE_WNDPROC, WM_TOUCH, WM_MOUSEMOVE, \
-        WM_MOUSELAST, PEN_OR_TOUCH_MASK, PEN_OR_TOUCH_SIGNATURE, \
-        PEN_EVENT_TOUCH_MASK, TOUCHEVENTF_UP, TOUCHEVENTF_DOWN, \
-        TOUCHEVENTF_MOVE
+from kivy.input.providers.wm_common import (WM_TABLET_QUERYSYSTEMGESTURE,
+        GWL_WNDPROC, QUERYSYSTEMGESTURE_WNDPROC, WM_TOUCH, WM_MOUSEMOVE,
+        WM_MOUSELAST, PEN_OR_TOUCH_MASK, PEN_OR_TOUCH_SIGNATURE,
+        PEN_EVENT_TOUCH_MASK, TOUCHEVENTF_UP, TOUCHEVENTF_DOWN,
+        TOUCHEVENTF_MOVE)
 from kivy.input.motionevent import MotionEvent
 from kivy.input.shape import ShapeRect
 
@@ -41,9 +41,10 @@ def __str__(self):
     WM_MotionEventProvider = None
 
 else:
-    from ctypes.wintypes import ULONG, HANDLE, DWORD, LONG
-    from ctypes import windll, WINFUNCTYPE, c_long, c_int, \
-            Structure, pointer, sizeof, byref
+    from ctypes.wintypes import (ULONG, HANDLE, DWORD, LONG, UINT,
+            WPARAM, LPARAM, POINTER, BOOL)
+    from ctypes import (windll, WINFUNCTYPE, c_int,
+                        Structure, pointer, sizeof, byref)
     from collections import deque
     from kivy.input.provider import MotionEventProvider
     from kivy.input.factory import MotionEventFactory
@@ -52,7 +53,8 @@ def __str__(self):
     if not hasattr(windll.user32, 'RegisterTouchWindow'):
         raise Exception('Unsupported Window version')
 
-    WNDPROC = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int)
+    LRESULT = LPARAM
+    WNDPROC = WINFUNCTYPE(LRESULT, HANDLE, UINT, WPARAM, LPARAM)
 
     class TOUCHINPUT(Structure):
         _fields_ = [
@@ -63,7 +65,7 @@ class TOUCHINPUT(Structure):
             ('flags', DWORD),
             ('mask', DWORD),
             ('time', DWORD),
-            ('extraInfo', ULONG),
+            ('extraInfo', POINTER(ULONG)),
             ('size_x', DWORD),
             ('size_y', DWORD)]
 
@@ -97,6 +99,27 @@ class RECT(Structure):
         w = property(lambda self: self.right-self.left)
         h = property(lambda self: self.bottom-self.top)
 
+    windll.user32.SetWindowLongPtrW.restype = WNDPROC
+    windll.user32.SetWindowLongPtrW.argtypes = [HANDLE, c_int, WNDPROC]
+    windll.user32.GetMessageExtraInfo.restype = LPARAM
+    windll.user32.GetMessageExtraInfo.argtypes = []
+    windll.user32.GetClientRect.restype = BOOL
+    windll.user32.GetClientRect.argtypes = [HANDLE, POINTER(RECT)]
+    windll.user32.GetWindowRect.restype = BOOL
+    windll.user32.GetWindowRect.argtypes = [HANDLE, POINTER(RECT)]
+    windll.user32.CallWindowProcW.restype = LRESULT
+    windll.user32.CallWindowProcW.argtypes = [WNDPROC, HANDLE, UINT, WPARAM,
+                                              LPARAM]
+    windll.user32.GetActiveWindow.restype = HANDLE
+    windll.user32.GetActiveWindow.argtypes = []
+    windll.user32.RegisterTouchWindow.restype = BOOL
+    windll.user32.RegisterTouchWindow.argtypes = [HANDLE, ULONG]
+    windll.user32.UnregisterTouchWindow.restype = BOOL
+    windll.user32.UnregisterTouchWindow.argtypes = [HANDLE]
+    windll.user32.GetTouchInputInfo.restype = BOOL
+    windll.user32.GetTouchInputInfo.argtypes = [HANDLE, UINT,
+                                                POINTER(TOUCHINPUT), c_int]
+    
     class WM_MotionEventProvider(MotionEventProvider):
 
         def start(self):
@@ -111,7 +134,7 @@ def start(self):
             # inject our own wndProc to handle messages
             # before window manager does
             self.new_windProc = WNDPROC(self._touch_wndProc)
-            self.old_windProc = windll.user32.SetWindowLongW(
+            self.old_windProc = windll.user32.SetWindowLongPtrW(
                 self.hwnd,
                 GWL_WNDPROC,
                 self.new_windProc)
@@ -150,7 +173,7 @@ def update(self, dispatch_fn):
 
         def stop(self):
             windll.user32.UnregisterTouchWindow(self.hwnd)
-            self.new_windProc = windll.user32.SetWindowLongW(
+            self.new_windProc = windll.user32.SetWindowLongPtrW(
                 self.hwnd,
                 GWL_WNDPROC,
                 self.old_windProc)
@@ -173,7 +196,6 @@ def _touch_wndProc(self, hwnd, msg, wParam, lParam):
                                                 hwnd, msg, wParam, lParam)
             return 1
 
-
         # this on pushes WM_TOUCH messages onto our event stack
         def _touch_handler(self, msg, wParam, lParam):
             touches = (TOUCHINPUT * wParam)()
@@ -185,7 +207,6 @@ def _touch_handler(self, msg, wParam, lParam):
                 self.touch_events.appendleft(touches[i])
             return True
 
-
         # filter fake mouse events, because touch and stylus
         # also make mouse events
         def _mouse_handler(self, msg, wparam, lParam):
@@ -195,5 +216,4 @@ def _mouse_handler(self, msg, wparam, lParam):
                 if info & PEN_EVENT_TOUCH_MASK:
                     return True
 
-
     MotionEventFactory.register('wm_touch', WM_MotionEventProvider)


Test patch: