使用Win32 API与ctypes修改窗口过程触发OverflowError问题
问题分析与解决
错误根源
你遇到的OverflowError是64位系统下Win32 API类型不匹配导致的,核心问题包括:
- 窗口过程返回值类型错误:64位系统中
LRESULT是64位整数,原代码用ctypes.c_long(32位)会引发类型截断。 - 旧窗口过程类型未正确转换:
GetWindowLongPtrA返回的是函数指针,直接作为整数传给CallWindowProcA会触发参数类型错误。 - 窗口句柄获取错误:
GetForegroundWindow()可能获取到非Pygame窗口的句柄,导致钩子挂错窗口。 - 回调指针转换错误:
SetWindowLongPtrA不需要将回调函数强制转换为POINTER(c_long),直接传递正确的函数指针类型即可。 - 未恢复原窗口过程:程序退出时未重置窗口过程,会导致后续窗口操作异常。
修复后的完整代码
import pygame import ctypes from ctypes import wintypes user32 = ctypes.windll.user32 # 修正窗口过程的类型定义:返回值用wintypes.LRESULT(适配64位系统) WNDPROC = ctypes.WINFUNCTYPE( wintypes.LRESULT, wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM ) WM_SIZE = 0x0005 RDW_INVALIDATE = 0x0001 RDW_ERASE = 0x0004 GWL_WNDPROC = -4 def main(): pygame.init() screen = pygame.display.set_mode((320, 240), pygame.RESIZABLE | pygame.DOUBLEBUF) # 获取Pygame窗口的正确句柄,避免获取到其他窗口 hwnd = pygame.display.get_wm_info()['window'] def draw_game(): screen.fill(pygame.Color('black')) pygame.draw.rect(screen, pygame.Color('red'), pygame.Rect(0,0,screen.get_width(),screen.get_height()).inflate(-10, -10)) pygame.display.flip() # 获取旧窗口过程并转换为正确的WNDPROC类型 old_window_proc_ptr = user32.GetWindowLongPtrA(hwnd, GWL_WNDPROC) old_window_proc = WNDPROC(old_window_proc_ptr) def new_window_proc(hwnd, msg, wparam, lparam): if msg == WM_SIZE: # 从lparam中提取窗口宽高,同步更新Pygame显示模式 width = wintypes.LOWORD(lparam) height = wintypes.HIWORD(lparam) pygame.display.set_mode((width, height), pygame.RESIZABLE | pygame.DOUBLEBUF) draw_game() user32.RedrawWindow(hwnd, None, None, RDW_INVALIDATE | RDW_ERASE) # 调用旧窗口过程,使用正确的类型实例 return old_window_proc(hwnd, msg, wparam, lparam) new_window_proc_cb = WNDPROC(new_window_proc) # 设置新窗口过程,直接传递回调指针 user32.SetWindowLongPtrA(hwnd, GWL_WNDPROC, ctypes.cast(new_window_proc_cb, wintypes.LONG_PTR)) try: while True: for event in pygame.event.get(): if event.type == pygame.QUIT: return draw_game() finally: # 程序退出时恢复原窗口过程,避免窗口异常 user32.SetWindowLongPtrA(hwnd, GWL_WNDPROC, old_window_proc_ptr) if __name__ == '__main__': main()
关键修改说明
- 修正类型定义:将窗口过程的返回值改为
wintypes.LRESULT,确保适配32/64位系统。 - 正确获取窗口句柄:用
pygame.display.get_wm_info()['window']获取Pygame自身的窗口句柄,避免钩子错误挂载。 - 旧窗口过程类型转换:把
GetWindowLongPtrA返回的指针转换为WNDPROC类型,调用时直接用该实例,避免参数类型不匹配。 - 移除错误的指针转换:
SetWindowLongPtrA的第三个参数直接传递回调函数的指针(转换为LONG_PTR)。 - 添加窗口过程恢复:在
finally块中恢复原窗口过程,防止程序退出后窗口行为异常。 - 优化WM_SIZE处理:直接从
lparam提取窗口宽高,同步更新Pygame显示模式,避免重复处理VIDEORESIZE事件。
内容的提问来源于stack exchange,提问作者Aradyan
相关产品推荐
相关产品推荐

