fix(ctypes): pin LPMSG across MSG-pump prototypes for Python 3.13

Python 3.13's ctypes tightened argtypes checks and now rejects
mismatched POINTER(MSG) cache entries — each call to POINTER(MSG)
can return a class identity that doesn't match what byref() of an
instance produces, raising "expected LP_MSG instance instead of
pointer to _MSG" inside GetMessageW/TranslateMessage/DispatchMessageW.

Capture POINTER(MSG) once into LPMSG and reuse the same class object
across all three prototypes in both the WindowsShutdownGuard pump and
the PlatformDetector display-power monitor. Restores the 4 failing
win_shutdown tests.
This commit is contained in:
2026-05-28 17:25:37 +03:00
parent bb3a316e35
commit e4d24a02da
2 changed files with 23 additions and 3 deletions
@@ -84,6 +84,21 @@ class PlatformDetector:
]
user32.DefWindowProcW.restype = ctypes.c_ssize_t
# Pin the MSG pointer type so byref(msg) matches the prototype
# (Python 3.13 ctypes rejects mismatched POINTER(MSG) caches).
LPMSG = ctypes.POINTER(ctypes.wintypes.MSG)
user32.GetMessageW.argtypes = [
LPMSG,
ctypes.wintypes.HWND,
ctypes.c_uint,
ctypes.c_uint,
]
user32.GetMessageW.restype = ctypes.c_int
user32.TranslateMessage.argtypes = [LPMSG]
user32.TranslateMessage.restype = ctypes.wintypes.BOOL
user32.DispatchMessageW.argtypes = [LPMSG]
user32.DispatchMessageW.restype = ctypes.c_ssize_t
def wnd_proc(hwnd, msg, wparam, lparam):
if msg == WM_POWERBROADCAST and wparam == PBT_POWERSETTINGCHANGE:
try:
+8 -3
View File
@@ -133,18 +133,23 @@ def _bind_winapi() -> None:
]
user32.DefWindowProcW.restype = LRESULT
# Pin the MSG pointer type once and reuse the same class object on all
# three prototypes — Python 3.13 ctypes rejects mismatched POINTER(_MSG)
# caches across argtypes, even though they look identical.
LPMSG = ctypes.POINTER(_MSG)
user32.GetMessageW.argtypes = [
ctypes.POINTER(_MSG),
LPMSG,
wintypes.HWND,
wintypes.UINT,
wintypes.UINT,
]
user32.GetMessageW.restype = wintypes.BOOL
user32.TranslateMessage.argtypes = [ctypes.POINTER(_MSG)]
user32.TranslateMessage.argtypes = [LPMSG]
user32.TranslateMessage.restype = wintypes.BOOL
user32.DispatchMessageW.argtypes = [ctypes.POINTER(_MSG)]
user32.DispatchMessageW.argtypes = [LPMSG]
user32.DispatchMessageW.restype = LRESULT
user32.PostMessageW.argtypes = [