如何通过Python Win32模块锁定外部窗口大小与位置
完全可以实现,无需注入第三方程序进程,通过Windows标准窗口API即可完成尺寸、位置的锁定,适配Python3.x、Win10、管理员权限的运行环境。
实现原理
- 锁定尺寸:Windows窗口默认的可拖拽调整边框能力由窗口样式位控制,移除
WS_THICKFRAME(即WS_SIZEBOX)样式和最大化按钮样式后,系统会默认禁用边框拖拽调整、最大化改尺寸的能力。针对自定义自绘边框的特殊程序,增加定时校验兜底,只要检测到窗口尺寸偏离锁定值就立刻还原。 - 锁定位置:通过兜底校验逻辑,检测窗口坐标偏移后立刻还原到初始锁定坐标,即可阻止用户通过拖拽标题栏、系统菜单移动指令修改窗口位置。
前置依赖
先安装pywin32库,执行命令:pip install pywin32
完整示例代码
import win32gui import win32con import time from threading import Thread class WindowLocker: def __init__(self, hwnd): self.hwnd = hwnd self.locked = False # 记录锁定时的初始位置、尺寸作为固定基准值 self.fixed_rect = win32gui.GetWindowRect(hwnd) self.lock_pos = False self.lock_size = False self.monitor_thread = None def _apply_size_style_lock(self): # 移除窗口可调整边框、最大化按钮样式 style = win32gui.GetWindowLong(self.hwnd, win32con.GWL_STYLE) style &= ~(win32con.WS_THICKFRAME | win32con.WS_MAXIMIZEBOX) win32gui.SetWindowLong(self.hwnd, win32con.GWL_STYLE, style) # 刷新窗口框架让样式修改立即生效 win32gui.SetWindowPos( self.hwnd, 0, 0, 0, 0, 0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE | win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED ) def _monitor_loop(self): # 兜底校验循环,拦截绕过系统样式的调整操作 left, top, right, bottom = self.fixed_rect fixed_w = right - left fixed_h = bottom - top while self.locked: if not win32gui.IsWindow(self.hwnd): break # 最小化状态不做调整,避免显示异常 if win32gui.IsIconic(self.hwnd): time.sleep(0.1) continue cur_left, cur_top, cur_right, cur_bottom = win32gui.GetWindowRect(self.hwnd) cur_w = cur_right - cur_left cur_h = cur_bottom - cur_top need_reset = False new_left, new_top = cur_left, cur_top new_w, new_h = cur_w, cur_h if self.lock_size and (cur_w != fixed_w or cur_h != fixed_h): new_w = fixed_w new_h = fixed_h need_reset = True if self.lock_pos and (cur_left != left or cur_top != top): new_left = left new_top = top need_reset = True if need_reset: win32gui.MoveWindow(self.hwnd, new_left, new_top, new_w, new_h, True) time.sleep(0.05) def start_lock(self, lock_size=True, lock_pos=False): """ 启动窗口锁定 :param lock_size: 是否锁定窗口尺寸 :param lock_pos: 是否锁定窗口位置 """ if self.locked: return self.lock_size = lock_size self.lock_pos = lock_pos self.locked = True if lock_size: self._apply_size_style_lock() self.monitor_thread = Thread(target=self._monitor_loop, daemon=True) self.monitor_thread.start() def stop_lock(self): """停止锁定,如需恢复窗口可调整样式可在此方法中补全样式还原逻辑""" self.locked = False if self.monitor_thread and self.monitor_thread.is_alive(): self.monitor_thread.join(timeout=1) if __name__ == "__main__": # 示例获取前台窗口句柄,实际使用替换为你持有的目标窗口HWND即可 hwnd = win32gui.GetForegroundWindow() locker = WindowLocker(hwnd) # 同时锁定尺寸和位置,不需要锁位置可将lock_pos设为False locker.start_lock(lock_size=True, lock_pos=True) print("窗口已锁定,按Ctrl+C解除锁定") try: while True: time.sleep(1) except KeyboardInterrupt: locker.stop_lock() print("已解除窗口锁定")
使用说明
- 代码默认通过
win32gui.GetForegroundWindow()获取当前前台窗口作为锁定目标,实际使用时替换成你已经获取到的目标窗口HWND即可 - 兜底校验轮询间隔设为50ms,CPU占用极低,同时能保证调整动作被立刻拦截,人眼不会感知到窗口移位或尺寸变化
- 方案未使用全局钩子、进程注入类高风险操作,兼容性强,不会导致第三方程序崩溃,也不会触发杀毒软件告警
- 如果需要在停止锁定后恢复窗口原本的可调整大小能力,可在
stop_lock方法中添加逻辑,将之前移除的WS_THICKFRAME、WS_MAXIMIZEBOX样式位重新加回,再调用SetWindowPos刷新框架即可
内容的提问来源于stack exchange,提问作者Programer Beginner
相关产品推荐
相关产品推荐

