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

SetWindowsHookExW返回0且无错误:HID鼠标钩子拦截问题求助

解决SetWindowsHookExW返回0且错误126的问题

问题原因分析

你遇到的[WinError 126] 找不到指定的模块错误,核心原因是SetWindowsHookExW的第三个参数(模块句柄)的获取方式存在问题,同时代码缺少低级别鼠标钩子必需的消息循环——即使钩子设置成功,没有消息循环也无法触发回调函数。

另外,原代码没有为SetWindowsHookExW开启use_last_error=True,导致GetLastError()返回的错误码被后续ctypes调用覆盖,出现返回0的异常情况。

修正后的代码

import ctypes
from ctypes import wintypes
import win32api
import win32con

# 定义钩子回调函数类型
HOOKPROC = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, wintypes.WPARAM, wintypes.LPARAM)

# 鼠标钩子回调函数
def low_level_mouse_proc(nCode, wParam, lParam):
    if nCode >= 0:
        # 拦截左键按下和抬起事件
        if wParam == win32con.WM_LBUTTONDOWN:
            print("左键按下已拦截")
            return 1  # 返回1阻止默认事件
        if wParam == win32con.WM_LBUTTONUP:
            print("左键抬起已拦截")
            return 1  # 返回1阻止默认事件
    # 传递未拦截的事件给下一个钩子
    return ctypes.windll.user32.CallNextHookEx(None, nCode, wParam, lParam)

# 转换Python函数为C回调
low_level_mouse_proc_c = HOOKPROC(low_level_mouse_proc)

def set_mouse_hook():
    WH_MOUSE_LL = 14
    # 获取当前进程的模块句柄(python.exe)
    kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
    module_handle = kernel32.GetModuleHandleW(None)
    
    # 正确配置SetWindowsHookExW,开启use_last_error
    user32 = ctypes.WinDLL('user32', use_last_error=True)
    mouse_hook = user32.SetWindowsHookExW(
        WH_MOUSE_LL,
        low_level_mouse_proc_c,
        module_handle,
        0
    )
    
    if not mouse_hook:
        print(f"钩子设置失败: {ctypes.WinError(ctypes.get_last_error())}")
        return None
    
    print("鼠标钩子已成功设置")
    return mouse_hook

def main():
    hook = set_mouse_hook()
    if not hook:
        return
    
    # 启动消息循环,低级别钩子依赖此循环分发事件
    msg = wintypes.MSG()
    user32 = ctypes.WinDLL('user32')
    while user32.GetMessageW(ctypes.byref(msg), None, 0, 0) != 0:
        user32.TranslateMessage(ctypes.byref(msg))
        user32.DispatchMessageW(ctypes.byref(msg))
    
    # 卸载钩子(程序退出时执行)
    ctypes.windll.user32.UnhookWindowsHookEx(hook)

if __name__ == "__main__":
    main()

关键修正点

  • 模块句柄获取:明确使用kernel32.GetModuleHandleW(None)获取当前进程的可执行文件句柄,确保系统能找到钩子函数所在的模块。
  • 错误码处理:为kernel32和user32的WinDLL实例开启use_last_error=True,并通过ctypes.get_last_error()获取准确的错误码,避免错误被覆盖。
  • 添加消息循环:低级别全局钩子(如WH_MOUSE_LL)需要调用进程运行消息循环,才能接收和处理钩子事件,否则回调函数永远不会被触发。
  • 保留回调引用:将转换后的C回调函数low_level_mouse_proc_c设为全局变量,防止Python垃圾回收机制回收该函数,导致钩子失效。

额外注意事项

  • 确保你的Python版本与系统位数一致(64位Python对应64位Windows),否则可能出现模块加载失败的问题。
  • 低级别鼠标钩子不需要管理员权限即可正常工作。
  • 测试时建议直接运行Python脚本文件,避免在部分IDE控制台中运行(可能影响消息循环正常执行)。

内容的提问来源于stack exchange,提问作者CodingCode

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 10:28:11