概述
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))
最后
以上就是俊秀大侠为你收集整理的python ctypes实现api测试_Python編程.利用ctypes調用Windows API的全部内容,希望文章能够帮你解决python ctypes实现api测试_Python編程.利用ctypes調用Windows API所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复