python ctypes实现api测试_Python編程.利用ctypes調用Windows API

Python是一種容易入門的編程語言,對於已經掌握C/C++或Java等任意一門編程語言的程序員來說,通過Python官網的Tutorial文檔,可以在較短時間內掌握基本語法。

Ctypes是我喜歡的Python特性之一,它讓你的Python程序可以方便地調用已有的C語言編寫的動態鏈接庫。在Windows操作系統上,利用ctypes提供的幫助,Python程序直接調用Windows API變得非常容易。

比如,mouse_event函數用於制造一個虛擬的鼠標事件,如果我們需要模擬一個鼠標移動事件,只需要執行以下代碼:

import ctypes

ctypes.windll.user32.mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE, 100, 200, 0, 0)

其中MOUSEEVENTF_ABSOLUTE和MOUSEEVENTF_MOVE的值,根據MSDN文檔,分別是0x8000和0x0001。此段代碼執行后,鼠標指針將出現在(100,200)坐標點上。

由於種種原因,SendInput函數被設計用來替代mouse_event函數。在Windows 7之前,mouse_event函數仍能順利完成它的功能。不過,在Windows 8以后,Windows系統增強了對Touch輸入模式的支持,當Touch發生時,鼠標指針將自動隱藏,此時調用mouse_event函數將不能讓鼠標指針顯示出來,但SendInput函數卻可以。

Python程序調用SendInput函數略微麻煩,因為我們要創建一個INPUT結構體數組,填充它的內容,並把它的地址作為參數傳遞給SendInput函數。當你發現INPUT結構體內又包含了union以及其他結構體時,情況就變得更麻煩些。不過ctypes提供了足夠的手段來完成這個任務。(以下代碼非原創,借鑒了開源Project)

import ctypes

LONG = ctypes.c_long

DWORD = ctypes.c_ulong

ULONG_PTR = ctypes.POINTER(DWORD)

WORD = ctypes.c_ushort

class MOUSEINPUT(ctypes.Structure):

_fields_ = (('dx', LONG),

('dy', LONG),

('mouseData', DWORD),

('dwFlags', DWORD),

('time', DWORD),

('dwExtraInfo', ULONG_PTR))

class KEYBDINPUT(ctypes.Structure):

_fields_ = (('wVk', WORD),

('wScan', WORD),

('dwFlags', DWORD),

('time', DWORD),

('dwExtraInfo', ULONG_PTR))

class HARDWAREINPUT(ctypes.Structure):

_fields_ = (('uMsg', DWORD),

('wParamL', WORD),

('wParamH', WORD))

class _INPUTunion(ctypes.Union):

_fields_ = (('mi', MOUSEINPUT),

('ki', KEYBDINPUT),

('hi', HARDWAREINPUT))

class INPUT(ctypes.Structure):

_fields_ = (('type', DWORD),

('union', _INPUTunion))

到此,我們通過繼承ctypes.Structure和ctypes.Union這個兩類,得到了最終的INPUT類,我們將用它來表示INPUT結構體。也許我們還需要幾個輔助函數來幫我們構造INPUT結構體:

def MouseInput(flags, x, y, data):

return MOUSEINPUT(x, y, data, flags, 0, None)

def KeybdInput(code, flags):

return KEYBDINPUT(code, code, flags, 0, None)

def HardwareInput(message, parameter):

return HARDWAREINPUT(message&0xFFFFFFFF, parameter&0xFFFF, parameter>>16&0xFFFF)

INPUT_MOUSE = 0

INPUT_KEYBOARD = 1

INPUT_HARDWARD = 2

def Input(structure):

if isinstance(structure, MOUSEINPUT):

return INPUT(INPUT_MOUSE, _INPUTunion(mi=structure))

if isinstance(structure, KEYBDINPUT):

return INPUT(INPUT_KEYBOARD, _INPUTunion(ki=structure))

if isinstance(structure, HARDWAREINPUT):

return INPUT(INPUT_HARDWARE, _INPUTunion(hi=structure))

raise TypeError('Cannot create INPUT structure!')

def Mouse(flags, x=0, y=0, data=0):

return Input(MouseInput(flags, x, y, data))

def Keyboard(code, flags=0):

return Input(KeybdInput(code, flags))

def Hardware(message, parameter=0):

return Input(HardwareInput(message, parameter))

現在我們只要調用Mouse()、Keyboard()和Hardware()函數,即可構造出一個INPUT結構體。

是時候調用SendInput函數了。

def SendInput(*inputs):

nInputs = len(inputs)

LPINPUT = INPUT * nInputs

pInputs = LPINPUT(*inputs)

cbSize = ctypes.c_int(ctypes.sizeof(INPUT))

return ctypes.windll.user32.SendInput(nInputs, pInputs, cbSize)

通常ctypes會自動完成參數的類型轉換,不過如果有必要,我們也可以手動設置SendInput的參數類型。比如:

ctypes.windll.user32.SendInput.argtypes = [ ctypes.c_uint, ctypes.POINTER(INPUT), ctypes.c_int ]

現在我們可以發送一個虛擬Move事件測試一下,看看鼠標指針是不是出現在預期的位置:

if __name__ == '__main__':

SendInput(Mouse(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE, 100, 200))

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python 中设置 Windows Hook,可以使用 ctypes调用 Windows API。具体步骤如下: 1. 导入 ctypes 库和 Windows API 函数: ```python import ctypes # 导入 Windows API 函数 user32 = ctypes.WinDLL('user32') kernel32 = ctypes.WinDLL('kernel32') ``` 2. 定义 Windows Hook 回调函数: ```python # 定义回调函数类型 HOOKPROC = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.wintypes.WPARAM, ctypes.wintypes.LPARAM) # 定义回调函数 def hook_callback(nCode, wParam, lParam): # 处理钩子消息 return user32.CallNextHookEx(hook_id, nCode, wParam, lParam) ``` 3. 安装 Hook: ```python # 安装 Hook hook_id = user32.SetWindowsHookExW( 13, # WH_KEYBOARD_LL 钩子类型 HOOKPROC(hook_callback), # 回调函数 kernel32.GetModuleHandleW(None), # 模块句柄 0 # 线程 ID,0 表示钩子适用于所有线程 ) ``` 4. 处理消息循环: ```python # 处理消息循环 msg = ctypes.wintypes.MSG() while user32.GetMessageW(ctypes.byref(msg), None, 0, 0) != 0: user32.TranslateMessage(ctypes.byref(msg)) user32.DispatchMessageW(ctypes.byref(msg)) ``` 5. 卸载 Hook: ```python # 卸载 Hook user32.UnhookWindowsHookEx(hook_id) ``` 完整代码示例: ```python import ctypes import ctypes.wintypes # 导入 Windows API 函数 user32 = ctypes.WinDLL('user32') kernel32 = ctypes.WinDLL('kernel32') # 定义回调函数类型 HOOKPROC = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.wintypes.WPARAM, ctypes.wintypes.LPARAM) # 定义回调函数 def hook_callback(nCode, wParam, lParam): # 处理钩子消息 return user32.CallNextHookEx(hook_id, nCode, wParam, lParam) # 安装 Hook hook_id = user32.SetWindowsHookExW( 13, # WH_KEYBOARD_LL 钩子类型 HOOKPROC(hook_callback), # 回调函数 kernel32.GetModuleHandleW(None), # 模块句柄 0 # 线程 ID,0 表示钩子适用于所有线程 ) # 处理消息循环 msg = ctypes.wintypes.MSG() while user32.GetMessageW(ctypes.byref(msg), None, 0, 0) != 0: user32.TranslateMessage(ctypes.byref(msg)) user32.DispatchMessageW(ctypes.byref(msg)) # 卸载 Hook user32.UnhookWindowsHookEx(hook_id) ``` 注意:Windows Hook 需要在 Windows 操作系统上运行,而且需要管理员权限。同时,Hook 回调函数的处理时间应该尽量短,以免影响系统性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值