如何使用ctypes.windll.user32.SetWindowsHookExW钩挂ctypes.windll.user32.MessageBoxW?

时间:2019-06-15 09:26:39

标签: python ctypes

我想制作一个玩笑程序,首先它会打开一个消息框,然后关闭它,然后在随机位置出现另一个消息框。它会一直重复这样,直到任何事情杀死了它的任务。使用tkinter消息框,然后将其挂勾,我必须制作另一种tkinter表单(这确实很丑陋,与Windows消息框不同)。因此我切换到ctypes,问题开始了。然后,我为该钩子创建了一个回调函数,当我将该函数传递给ctypes.windll.user32.SetWindowsHookExA函数的第二个参数时,它将显示TypeError:错误的类型。我该如何解决?

我试图将函数强制转换为c_void_p,但是这样做只会得到更多错误,例如“非法指令”。

这是我的代码:

import ctypes, random

def msgBoxHook(nCode, wParam, lParam):
 if nCode == 3:
  hwnd = ctypes.wintypes.HWND
  hwnd = wParam

  msgRekt = ctypes.wintypes.RECT # >:)

  ctypes.windll.user32.GetWindowRect(hwnd, ctypes.byref(msgRekt))
  ctypes.windll.user32.MoveWindow(hwnd, randint(0, ctypes.windll.user32.GetSystemMetrics(0)), randint(0, ctypes.windll.user32.GetSystemMetrics(1)), msgRekt.right - msgRekt.left, msgRekt.bottom - msgRekt.top, True)
 return ctypes.windll.user32.CallNextHookEx(0, nCode, wParam, lParam)

# When I try to call
ctypes.windll.user32.SetWindowsHookExA(5, msgBoxHook, 0, ctypes.windll.kernel32.GetCurrentThreadId())

# It shows:
"""
Traceback (most recent call last):
  File "test.py", line 1, in <module>
ctypes.ArgumentError: argument 2: <class 'TypeError'>: wrong type
"""

预期:使用ctypes.windll.user32.MessageBoxW(None,'Hello','World',0x00000010 | 0x00000000)时,它将在随机位置打开一个带有标题“ World”,文本“ Hello”和“停止”图标的消息框单击确定按钮。

现实:如上所示。

1 个答案:

答案 0 :(得分:0)

列出[Python 3.Docs]: ctypes - A foreign function library for Python

您不能将 Python 对象传递给普通的 C 函数(我是可以的,但是结果不会是预期的)。

[MS.Docs]: SetWindowsHookExA function在其{ st 参数为 WH_CBT (5)时期望[MS.Docs]: CBTProc callback function
因此,您必须包装函数:

WH_CBT = 5

HOOKProc = ctypes.WINFUNCTYPE(wintypes.LPVOID, ctypes.c_int, wintypes.WPARAM, wintypes.LPARAM)
CBTProc = HOOKProc

hook = ctypes.windll.user32.SetWindowsHookExA(WH_CBT, CBTProc(msgBoxHook), 0, ctypes.windll.kernel32.GetCurrentThreadId())

这应该使您摆脱当前的问题。但是您肯定会碰到其他人(当然这可能是其他问题的主题)。
我已经发现的一个问题是,不要为您使用的任何函数定义 argtypes restype ,因此(几乎)可以肯定使您陷入困境(崩溃)。一些例子: