`pywin32` 是一个广泛使用的 Python 扩展库,用于在 Windows 平台上调用 Win32 API
pywin32是一个广泛使用的 Python 扩展库用于在 Windows 平台上调用 Win32 API、操作 COM 对象、访问 Windows 服务、注册表、事件日志、GUI 控件如窗口、消息等。它并非直接封装所有 Windows API而是通过 Pythonic 的方式如类、方法、属性对底层 Windows SDK 功能进行高层抽象和封装极大简化了 Windows 系统级编程。核心功能包括Windows API 调用通过win32api、win32gui、win32con、win32event等模块提供对常用 API 的封装如FindWindow,SendMessage,GetLastError,RegOpenKeyEx等COM 自动化支持通过win32com.client可轻松调用 Excel、Word、Outlook 等 Office 应用或自定义 COM 组件服务管理win32service和win32serviceutil支持创建、启动、控制 Windows 服务事件日志与安全win32evtlog、win32security提供日志读写、ACL、令牌操作等进程/线程/同步对象win32process、win32event支持进程创建、优先级设置、互斥体、信号量等注册表操作win32con定义常量win32api.Reg*系列函数提供安全便捷的注册表读写。安装方式pipinstallpywin32注意安装后需运行python Scripts/pywin32_postinstall.py -install路径可能因 Python 环境而异以注册 COM 类型库和系统服务支持。示例获取当前前台窗口标题importwin32gui hwndwin32gui.GetForegroundWindow()titlewin32gui.GetWindowText(hwnd)print(f当前窗口标题{title})⚠️ 注意事项pywin32 不是官方 Python 标准库需单独安装部分功能需管理员权限如服务操作、全局钩子、注册表 HKEY_LOCAL_MACHINE 写入64 位 Python 需匹配 64 位 pywin32自动适配但 COM 交互时需注意位数一致性如调用 32 位 Excel 进程需 32 位 Python文档较分散推荐查阅 pywin32 GitHub 及内置帮助help(win32api)或PyWin32.chm帮助文件。在 Windows 上使用pywin32实现全局键盘/鼠标钩子Global Hook是可行的但需特别注意pywin32本身不直接提供全局钩子的高层封装如SetWindowsHookEx的完整 Python 接口其win32gui和win32api模块虽可调用底层 API但缺少对钩子回调函数HookProc跨线程/跨进程正确注册与消息循环的支持——尤其是全局钩子WH_KEYBOARD_LL/WH_MOUSE_LL要求回调必须位于有消息循环的线程中且低级钩子LL虽不要求 DLL 注入但仍需正确处理CallNextHookEx和避免阻塞。✅ 正确、稳定、推荐的方式是结合pywin32用于窗口/消息基础操作 ctypes直接调用user32.dll的SetWindowsHookExW/UnhookWindowsHookEx/CallNextHookEx 主线程运行GetMessage消息循环或使用win32event同步。⚠️pywin32单独无法安全实现全局钩子常见误区是误以为win32gui.SetWindowsHookEx存在它不存在—— pywin32 并未封装该 API。✅ 正确示例使用ctypespywin32辅助实现全局低级键盘钩子监听所有按键importctypesfromctypesimportwintypesimportwin32event# 用于同步/退出控制importpythoncom# 若需 COM 支持本例非必需但常共用importsys# 定义 Windows 常量来自 WinUser.hWH_KEYBOARD_LL13HC_ACTION0VK_ESCAPE0x1B# 钩子回调函数类型stdcall64位需注意调用约定HHOOKwintypes.HHOOK LRESULTwintypes.LRESULT WPARAMwintypes.WPARAM LPARAMwintypes.LPARAM# 键盘结构体LL 钩子 LPARAM 指向 KBDLLHOOKSTRUCTclassKBDLLHOOKSTRUCT(ctypes.Structure):_fields_[(vkCode,wintypes.DWORD),(scanCode,wintypes.DWORD),(flags,wintypes.DWORD),(time,wintypes.DWORD),(dwExtraInfo,ctypes.POINTER(wintypes.ULONG)),]# 全局变量存储钩子句柄避免被 GC 回收hook_handleNoneexit_eventwin32event.CreateEvent(None,0,0,None)# 钩子回调函数必须为 stdcall且不能是 lambda 或内联函数defkeyboard_proc(nCode,wParam,lParam):ifnCodeHC_ACTION:ifwParam0x100:# WM_KEYDOWNkb_structKBDLLHOOKSTRUCT.from_address(lParam)vkkb_struct.vkCodeprint(fKey down: VK{vk}(0x{vk:X}))ifvkVK_ESCAPE:print(ESC pressed → exiting...)win32event.SetEvent(exit_event)# 必须调用 CallNextHookEx否则其他程序收不到按键returnctypes.windll.user32.CallNextHookEx(hook_handle,nCode,wParam,lParam)# 设置钩子需在有消息循环的线程中调用definstall_hook():globalhook_handle# 获取当前线程 ID全局钩子需为 0表示系统级hmodctypes.windll.kernel32.GetModuleHandleW(None)# 注意keyboard_proc 必须是 ctypes.CFUNCTYPE 绑定的可调用对象CMPFUNCctypes.CFUNCTYPE(LRESULT,WPARAM,WPARAM,LPARAM)procCMPFUNC(keyboard_proc)hook_handlectypes.windll.user32.SetWindowsHookExW(WH_KEYBOARD_LL,proc,hmod,0# dwThreadId 0 → 全局钩子)ifnothook_handle:raiseRuntimeError(fFailed to set keyboard hook, error{ctypes.windll.kernel32.GetLastError()})returnproc# 保持引用防止被 GC 回收# 主消息循环关键必须运行以接收系统钩子消息defrun_message_loop():msgwintypes.MSG()whileTrue:# 等待消息或退出事件超时 100ms 避免忙等retwin32event.WaitForSingleObject(exit_event,100)ifretwin32event.WAIT_OBJECT_0:break# PeekMessage 非阻塞检查也可用 GetMessage 阻塞式但需配合退出逻辑ifctypes.windll.user32.PeekMessageW(ctypes.byref(msg),None,0,0,1):ctypes.windll.user32.TranslateMessage(ctypes.byref(msg))ctypes.windll.user32.DispatchMessageW(ctypes.byref(msg))if__name____main__:try:cb_funcinstall_hook()print(Global keyboard hook installed. Press ESC to exit.)run_message_loop()finally:ifhook_handle:ctypes.windll.user32.UnhookWindowsHookEx(hook_handle)print(Hook uninstalled.)关键要点说明✅ 使用ctypes直接调用user32.dll是唯一可靠方式✅keyboard_proc必须是CFUNCTYPE绑定的持久函数对象否则被 GC 后崩溃✅ 必须在主线程运行消息循环PeekMessage/GetMessage否则钩子不触发✅ 全局低级钩子WH_KEYBOARD_LL无需 DLL 注入但需win32gui/win32api之外的ctypes支持❌pywin32不提供SetWindowsHookEx封装不可依赖win32api或win32gui实现钩子⚠️ 全局钩子可能被 UAC、杀毒软件拦截建议以管理员权限运行 高频钩子如鼠标移动需避免耗时操作否则拖慢系统输入响应。 替代方案更简单 更安全若仅需监听当前进程内按键非全局可用win32guiSetWindowsHook局部钩子或pynput跨平台、纯 Python、自动处理钩子生命周期pipinstallpynputfrompynputimportkeyboarddefon_press(key):try:print(fKey{key.char}pressed)exceptAttributeError:print(fSpecial key{key}pressed)listenerkeyboard.Listener(on_presson_press)listener.start()listener.join()# 或 listener.stop() 控制✅pynput内部已用ctypes正确封装钩子推荐日常使用。