2016-07-24 98 views
1

我一样,设立一个鼠标钩子在python:蟒蛇窗户鼠标钩子崩溃

def listen(): 
    global hook_id 

    def low_level_handler(aCode, wParam, lParam): 
     if aCode != win32con.HC_ACTION: 
      return ctypes.windll.user32.CallNextHookEx(hook_id, aCode, wParam, lParam) 

     return ctypes.windll.user32.CallNextHookEx(hook_id, aCode, wParam, lParam) 

    # Our low level handler signature. 
    CMPFUNC = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_void_p)) 
    # Convert the Python handler into C pointer. 
    pointer = CMPFUNC(low_level_handler) 


    # Hook both key up and key down events for common keys (non-system). 
    hook_id = ctypes.windll.user32.SetWindowsHookExA(win32con.WH_MOUSE_LL, pointer, 
              GetModuleHandle(None), 0) 
    # Register to remove the hook when the interpreter exits. Unfortunately a 
    # try/finally block doesn't seem to work here. 
    atexit.register(ctypes.windll.user32.UnhookWindowsHookEx, hook_id) 

def process_msg(): 
    while True: 
     status, msg = PeekMessage(None, 0, 0, win32con.PM_REMOVE) 
     if status == 0: 
      break 
     TranslateMessage(ctypes.byref(msg)) 
     DispatchMessage(ctypes.byref(msg)) 

process_msg被后来称为一个循环

似乎一切,直到我做SendInput工作正常它模拟同一应用程序内的鼠标点击。一旦我模拟点击,就会发生崩溃。可能是什么原因?

谢谢。

+0

'GetModuleHandle'返回一个指向模块基地址的指针。通常对于64位支持,您需要将其'restype'属性设置为指针类型,例如'c_void_p'。另外一个'WPARAM'是无符号的,指针的大小;你可以使用'c_void_p'来做到这一点。 – eryksun

+1

避免使用'ctypes.windll'。毫无疑问,这是ctypes中最糟糕的事情。它让你摆脱任何使用ctypes的模块碰巧被加载,因为它缓存库,缓存函数指针。而是使用'user32 = ctypes.WinDLL('user32',use_last_error = True)'。 – eryksun

+0

@eryksun谢谢,你给我修好了! – Andrew

回答

1

它看起来像def low_level_handler超出了范围,并被垃圾收集(?)/从内存中删除。在我将其移出def listen之后,它全部正常工作。

+0

是的,回调函数必须为蹦床代码分配一小块可执行内存,这是传递给C代码的指针地址。您必须保留对回调的引用,以防止回拨及其蹦床被释放。 – eryksun