You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Win32 API与ctypes修改窗口过程触发OverflowError问题

问题分析与解决

错误根源

你遇到的OverflowError是64位系统下Win32 API类型不匹配导致的,核心问题包括:

  1. 窗口过程返回值类型错误:64位系统中LRESULT是64位整数,原代码用ctypes.c_long(32位)会引发类型截断。
  2. 旧窗口过程类型未正确转换:GetWindowLongPtrA返回的是函数指针,直接作为整数传给CallWindowProcA会触发参数类型错误。
  3. 窗口句柄获取错误:GetForegroundWindow()可能获取到非Pygame窗口的句柄,导致钩子挂错窗口。
  4. 回调指针转换错误:SetWindowLongPtrA不需要将回调函数强制转换为POINTER(c_long),直接传递正确的函数指针类型即可。
  5. 未恢复原窗口过程:程序退出时未重置窗口过程,会导致后续窗口操作异常。

修复后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 21:45:31