I have used pymouse to help automate repetitive games in the past with success.
However, when playing a game downloaded on BlueStacks, pymouse will appear to move to the correct position on the screen, but then no clicks will "register".
If I put something else native to the OS in the same position, it will be clicked. I do not understand why the clicks dont "work" in this case when I move the mouse to a position over the game being played in Bluestacks.
Here is the code:
from pymouse import PyMouse
import time
m = PyMouse()
i=1
for i in range(1,1000):
time.sleep(2)
x, y = m.position()
print(x, y)
m.click(x,y,1)
i+=1
This (below) will return values even if the mouse is hovered over the window from Bluestacks.
print(m.position())
There is one option left open to you without resorting to a virtual machine or writing a custom driver. if you install a hook for mouse commands you have the capability to alter the flags in that hook before passing them to the next hook.
Due to how windows queues the hooks you need the hook altering the flags to be the last registered hook, so in this example you would need to start your game before installing the hook.
some example code to do this is below, I tested this using pyHook to check the result. for your purposes you will probably want to wrap this in a thread so it happens in the background.
import atexit
import ctypes
import time
from ctypes import c_short, c_char, c_uint8, c_int32, c_int, c_uint, c_uint32, c_long, byref, Structure, CFUNCTYPE, POINTER
from ctypes.wintypes import DWORD, BOOL, HHOOK, MSG, LPWSTR, WCHAR, WPARAM, LPARAM
from collections import namedtuple
LPMSG = POINTER(MSG)
user32 = ctypes.WinDLL('user32', use_last_error = True)
class MSLLHOOKSTRUCT(Structure):
_fields_ = [("x", c_long),
("y", c_long),
('data', c_int32),
("flags", DWORD),
("time", c_int),
('extrainfo', c_int32),
]
LowLevelMouseProc = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(MSLLHOOKSTRUCT))
SetWindowsHookEx = user32.SetWindowsHookExA
#SetWindowsHookEx.argtypes = [c_int, LowLevelMouseProc, c_int, c_int]
SetWindowsHookEx.restype = HHOOK
CallNextHookEx = user32.CallNextHookEx
#CallNextHookEx.argtypes = [c_int , c_int, c_int, POINTER(MSLLHOOKSTRUCT)]
CallNextHookEx.restype = c_int
UnhookWindowsHookEx = user32.UnhookWindowsHookEx
UnhookWindowsHookEx.argtypes = [HHOOK]
UnhookWindowsHookEx.restype = BOOL
GetMessage = user32.GetMessageW
GetMessage.argtypes = [LPMSG, c_int, c_int, c_int]
GetMessage.restype = BOOL
TranslateMessage = user32.TranslateMessage
TranslateMessage.argtypes = [LPMSG]
TranslateMessage.restype = BOOL
DispatchMessage = user32.DispatchMessageA
DispatchMessage.argtypes = [LPMSG]
# Beware, as of 2016-01-30 the official docs have a very incomplete list.
# This one was compiled from experience and may be incomplete.
WM_MOUSEMOVE = 0x200
WM_LBUTTONDOWN = 0x201
WM_LBUTTONUP = 0x202
WM_LBUTTONDBLCLK = 0x203
WM_RBUTTONDOWN = 0x204
WM_RBUTTONUP = 0x205
WM_RBUTTONDBLCLK = 0x206
WM_MBUTTONDOWN = 0x207
WM_MBUTTONUP = 0x208
WM_MBUTTONDBLCLK = 0x209
WM_MOUSEWHEEL = 0x20A
WM_XBUTTONDOWN = 0x20B
WM_XBUTTONUP = 0x20C
WM_XBUTTONDBLCLK = 0x20D
WM_NCXBUTTONDOWN = 0x00AB
WM_NCXBUTTONUP = 0x00AC
WM_NCXBUTTONDBLCLK = 0x00AD
WM_MOUSEHWHEEL = 0x20E
WM_LBUTTONDOWN = 0x0201
WM_LBUTTONUP = 0x0202
WM_MOUSEMOVE = 0x0200
WM_MOUSEWHEEL = 0x020A
WM_MOUSEHWHEEL = 0x020E
WM_RBUTTONDOWN = 0x0204
WM_RBUTTONUP = 0x0205
LEFT = 'left'
RIGHT = 'right'
MIDDLE = 'middle'
X = 'x'
UP = 'up'
DOWN = 'down'
DOUBLE = 'double'
buttons_by_wm_code = {
WM_LBUTTONDOWN: (DOWN, LEFT),
WM_LBUTTONUP: (UP, LEFT),
WM_LBUTTONDBLCLK: (DOUBLE, LEFT),
WM_RBUTTONDOWN: (DOWN, RIGHT),
WM_RBUTTONUP: (UP, RIGHT),
WM_RBUTTONDBLCLK: (DOUBLE, RIGHT),
WM_MBUTTONDOWN: (DOWN, MIDDLE),
WM_MBUTTONUP: (UP, MIDDLE),
WM_MBUTTONDBLCLK: (DOUBLE, MIDDLE),
WM_XBUTTONDOWN: (DOWN, X),
WM_XBUTTONUP: (UP, X),
WM_XBUTTONDBLCLK: (DOUBLE, X),
}
NULL = c_int(0)
def translate_injected_mouse():
def low_level_mouse_handler(nCode, wParam, lParam):
struct = lParam.contents
if wParam in buttons_by_wm_code:
struct.flags &= 0x11111100 # clear the injected flags
return CallNextHookEx(NULL, nCode, wParam, lParam)
WH_MOUSE_LL = c_int(14)
mouse_callback = LowLevelMouseProc(low_level_mouse_handler)
mouse_hook = SetWindowsHookEx(WH_MOUSE_LL, mouse_callback, user32._handle, NULL)
# Register to remove the hook when the interpreter exits. Unfortunately a
# try/finally block doesn't seem to work here.
atexit.register(UnhookWindowsHookEx, mouse_hook)
msg = LPMSG()
while not GetMessage(msg, NULL, NULL, NULL):
TranslateMessage(msg)
DispatchMessage(msg)
if __name__ == '__main__':
translate_injected_mouse()
stripped down example that wraps functionality into a thread class:
import atexit
import ctypes
from ctypes import c_int, c_uint, c_uint32, c_long, Structure, CFUNCTYPE, POINTER
from ctypes.wintypes import DWORD, BOOL, HWND, HHOOK, MSG, WPARAM, LPARAM
import threading
LPMSG = POINTER(MSG)
user32 = ctypes.WinDLL('user32', use_last_error = True)
class MSLLHOOKSTRUCT(Structure):
_fields_ = [("x", c_long), ("y", c_long),
('data', c_uint32), ("flags", DWORD),
("time", c_int), ('extrainfo', c_uint32), ]
LowLevelMouseProc = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(MSLLHOOKSTRUCT))
SetWindowsHookEx = user32.SetWindowsHookExA
#SetWindowsHookEx.argtypes = [c_int, LowLevelMouseProc, c_int, c_int]
SetWindowsHookEx.restype = HHOOK
CallNextHookEx = user32.CallNextHookEx
#CallNextHookEx.argtypes = [c_int , c_int, c_int, POINTER(MSLLHOOKSTRUCT)]
CallNextHookEx.restype = c_int
UnhookWindowsHookEx = user32.UnhookWindowsHookEx
UnhookWindowsHookEx.argtypes = [HHOOK]
UnhookWindowsHookEx.restype = BOOL
GetMessage = user32.GetMessageW
GetMessage.argtypes = [LPMSG, c_int, c_int, c_int]
GetMessage.restype = BOOL
TranslateMessage = user32.TranslateMessage
TranslateMessage.argtypes = [LPMSG]
TranslateMessage.restype = BOOL
DispatchMessage = user32.DispatchMessageA
DispatchMessage.argtypes = [LPMSG]
NULL = c_int(0)
class TranslateInjectedMouse(threading.Thread):
daemon=True
def run(self):
def low_level_mouse_handler(nCode, wParam, lParam):
print("handler")
lParam.contents.flags &= 0x11111100
return CallNextHookEx(NULL, nCode, wParam, lParam)
WH_MOUSE_LL = c_int(14)
mouse_callback = LowLevelMouseProc(low_level_mouse_handler)
self.mouse_hook = SetWindowsHookEx(WH_MOUSE_LL, mouse_callback, user32._handle, NULL)
# Register to remove the hook when the interpreter exits. Unfortunately a
# try/finally block doesn't seem to work here.
atexit.register(UnhookWindowsHookEx, self.mouse_hook)
msg = LPMSG()
while not GetMessage(msg, NULL, NULL, NULL):
TranslateMessage(msg)
DispatchMessage(msg)
def stop(self):
UnhookWindowsHookEx(self.mouse_hook)
if __name__ == '__main__':
# this is all you need to translate in background
t = TranslateInjectedMouse()
t.start()
# below this is test code to create clicks
import time
mouse_event = user32.mouse_event
MOUSEEVENTF_LEFTDOWN = 0x0002
MOUSEEVENTF_LEFTUP = 0x0004
while True:
try:
time.sleep(1)
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
except KeyboardInterrupt:
if t.is_alive():
t.stop()
else:
break
note that presently I cannot find a way to kill this thread on command. the thread execution blocks at GetMessage waiting for messages to handle such as WM_QUIT, because this happens in C rather than in python raising an exception in the thread does not cause it to exit, I've tried a large number of combinations such as SendMessage, PostMessage and PostThreadMessage to try and send a WM_QUIT message but with no success. instead the daemon flag is set which forces it to exit when the main thread exits.
It use mouse_event which called SendInput internally.
The SendInput function will insert input events into the same queue as a hardware device but the events are marked with a LLMHF_INJECTED flag that can be detected by hooks. To avoid this flag you probably have to write a custom driver.
For your special case,i think you can use SetWindowsHookEx clear the flag.
but for easy use,just using a VMware.please see this post.
try this, it work for me.
# -*- coding: UTF-8 -*-
import pyautogui as gui
from time import sleep
from threading import Thread
from pymouse import PyMouse
__author__ = 'lpe234'
def click(x, y):
print(x, y)
gui.click(x, y)
def main():
# make sure the window is active. pyautogui.click can't active the window, don't know why
PyMouse().click(489, 316)
t = Thread(target=click, args=[400, 500])
t.daemon = True
t.start()
sleep(5)
if __name__ == '__main__':
main()
If you use the pywin32 library,
you can easily bring the application window to the top before performing clicks
import win32gui
bluestacks_hwnd=win32gui.FindWindow(None,"bluestacks")
win32gui.BringWindowToTop(bluestacks_hwnd)
...
Related
Not wx, gtk3, pyqt etc...
I need something like:
cef.Initialize(settings=settings)
window_info = cef.WindowInfo()
browser = cef.CreateBrowserSync(url="localhost:8080/", window_title="Hello World!" icon="myicon.png")
On Linux execute xseticon program programmtically using os.system() function or similar, see: http://www.leonerd.org.uk/code/xseticon/ .
On Windows use ctypes built-in Python module to execute native win32 functions. Example code below. The _hWnd variable holds window handle which can be obtained by calling browser.GetWindowHandle().
from ctypes import *
from ctypes.wintypes import *
from os import path
import platform
LRESULT = c_int64 if platform.architecture()[0] == "64bit" else c_long
SendMessage = windll.user32.SendMessageW
SendMessage.restype = LRESULT
SendMessage.argtypes = [HWND, UINT, WPARAM, LPARAM]
GetModuleHandle = windll.kernel32.GetModuleHandleW
GetModuleHandle.restype = HMODULE
GetModuleHandle.argtypes = [LPCWSTR]
IMAGE_ICON = 1
LR_LOADFROMFILE = 0x00000010
LR_CREATEDIBSECTION = 0x00002000
LoadImage = windll.user32.LoadImageW
LoadImage.restype = HANDLE
LoadImage.argtypes = [HINSTANCE, LPCWSTR, UINT, c_int, c_int, UINT]
RelPath = lambda file : path.join(path.dirname(path.abspath(__file__)), file)
def AlterIcon(_hWnd, lpszIcon):
WM_SETICON = 0x0080
ICON_BIG = 1
hModel = GetModuleHandle(None)
hIcon = LoadImage(hModel,
RelPath(lpszIcon),
IMAGE_ICON,
0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION)
SendMessage(_hWnd, WM_SETICON, ICON_BIG, hIcon)
Ref: http://qaru.site/questions/7837596/how-to-include-image-in-message-box-using-ctypes-in-python
I am attempting to cause my python application to flash its parent console's icon in the taskbar. I have tried the following:
ctypes.windll.user32.FlashWindow(
ctypes.windll.kernel32.GetConsoleWindow(), True)
and
ctypes.windll.user32.FlashWindow(
ctypes.windll.user32.GetParent(ctypes.windll.kernel32.GetConsoleWindow()), True)
But neither of these cause the desired effect.
I am using python 3.5.4, on Windows 10. I am using cmder as my console.
Use FlashWindowEx to specifically flash just the taskbar icon. For a regular console window, get the window handle via GetConsoleWindow. This may not work for alternative consoles such as ConEmu, unless it's one of the API functions that they hack.
For example:
import ctypes
from ctypes import wintypes
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
user32 = ctypes.WinDLL('user32', use_last_error=True)
FLASHW_STOP = 0
FLASHW_CAPTION = 0x00000001
FLASHW_TRAY = 0x00000002
FLASHW_ALL = 0x00000003
FLASHW_TIMER = 0x00000004
FLASHW_TIMERNOFG = 0x0000000C
class FLASHWINFO(ctypes.Structure):
_fields_ = (('cbSize', wintypes.UINT),
('hwnd', wintypes.HWND),
('dwFlags', wintypes.DWORD),
('uCount', wintypes.UINT),
('dwTimeout', wintypes.DWORD))
def __init__(self, hwnd, flags=FLASHW_TRAY, count=5, timeout_ms=0):
self.cbSize = ctypes.sizeof(self)
self.hwnd = hwnd
self.dwFlags = flags
self.uCount = count
self.dwTimeout = timeout_ms
kernel32.GetConsoleWindow.restype = wintypes.HWND
user32.FlashWindowEx.argtypes = (ctypes.POINTER(FLASHWINFO),)
def flash_console_icon(count=5):
hwnd = kernel32.GetConsoleWindow()
if not hwnd:
raise ctypes.WinError(ctypes.get_last_error())
winfo = FLASHWINFO(hwnd, count=count)
previous_state = user32.FlashWindowEx(ctypes.byref(winfo))
return previous_state
I am trying to globally track the mouse with a Python (3.4.3) background app (in Windows 7/8). This involves setting up a WindowsHook which should return me a valid handle to that specific hook - but my handle is always 0.
Tracking only the mouse position is very easy with GetCursorPos (as an alternative GetCursorInfo works as well):
from ctypes.wintypes import *
ppoint = ctypes.pointer(POINT())
ctypes.windll.user32.GetCursorPos(ppoint)
print('({}, {})'.format(ppoint[0].x, ppoint[0].y))
Also convenient to track only the position is GetMouseMovePointsEx, which tracks the last 64 mouse positions:
from ctypes.wintypes import *
# some additional types and structs
ULONG_PTR = ctypes.c_ulong
class MOUSEMOVEPOINT(ctypes.Structure):
_fields_ = [
("x", ctypes.c_int),
("y", ctypes.c_int),
("time", DWORD),
("dwExtraInfo", ULONG_PTR)
]
GMMP_USE_DISPLAY_POINTS = 1
# get initial tracking point
ppoint = ctypes.pointer(POINT())
ctypes.windll.user32.GetCursorPos(ppoint)
point = MOUSEMOVEPOINT(ppoint[0].x,ppoint[0].y)
# track last X points
number_mouse_points = 64
points = (MOUSEMOVEPOINT * number_mouse_points)()
ctypes.windll.user32.GetMouseMovePointsEx(ctypes.sizeof(MOUSEMOVEPOINT),
ctypes.pointer(point), ctypes.pointer(points), number_mouse_points,
GMMP_USE_DISPLAY_POINTS)
# print results
for point in points:
print('({}, {})'.format(point.x, point.y))
However I want to be able to also track clicks, drags, etc.
A good solution seems to be the LowLevelMouseProc. (There might be another way yet to be explored: Raw Input)
To be able to use the LowLevelMouseProc the documentation tells us to use SetWindowsHookEx(W/A), which is also covered in various (C++) tutorials (C#), as well as some interesting projects (also C#).
The documentation defines it in C++ as follows:
HHOOK WINAPI SetWindowsHookEx(
_In_ int idHook,
_In_ HOOKPROC lpfn,
_In_ HINSTANCE hMod,
_In_ DWORD dwThreadId
);
Where the following should be the correct values for me in python:
idHook: WH_MOUSE_LL = 14
hMod: HINSTANCE(0) (basically a null pointer)
dwThreadId: ctypes.windll.kernel32.GetCurrentThreadId()
And for the lpfn I need some callback implementing the LowLevelMouseProc, here LLMouseProc:
def _LLMouseProc (nCode, wParam, lParam):
return ctypes.windll.user32.CallNextHookEx(None, nCode, wParam, lParam)
LLMouseProcCB = ctypes.CFUNCTYPE(LRESULT, ctypes.c_int, WPARAM, LPARAM)
LLMouseProc = LLMouseProcCB(_LLMouseProc)
Putting it all together I expected this to work:
from ctypes.wintypes import *
LONG_PTR = ctypes.c_long
LRESULT = LONG_PTR
WH_MOUSE_LL = 14
def _LLMouseProc(nCode, wParam, lParam):
print("_LLMouseProc({!s}, {!s}, {!s})".format(nCode, wParam, lParam))
return ctypes.windll.user32.CallNextHookEx(None, nCode, wParam, lParam)
LLMouseProcCB = ctypes.CFUNCTYPE(LRESULT, ctypes.c_int, WPARAM, LPARAM)
LLMouseProc = LLMouseProcCB(_LLMouseProc)
threadId = ctypes.windll.kernel32.GetCurrentThreadId()
# register callback as hook
print('hook = SetWindowsHookExW({!s}, {!s}, {!s}, {!s})'.format(WH_MOUSE_LL, LLMouseProc,
HINSTANCE(0), threadId))
hook = ctypes.windll.user32.SetWindowsHookExW(WH_MOUSE_LL, LLMouseProc,
HINSTANCE(0), threadId)
print('Hook: {}'.format(hook))
import time
try:
while True:
time.sleep(0.2)
except KeyboardInterrupt:
pass
But the output reveals that hook == 0:
hook = SetWindowsHookExW(14, <CFunctionType object at 0x026183F0>, c_void_p(None), 5700)
Hook: 0
I think that maybe the last parameter of the callback function, name lParam is not really correct as LPARAM (which is ctypes.c_long), since what I assume is really expected is a pointer to this struct:
class MSLLHOOKSTRUCT(ctypes.Structure):
_fields_ = [
("pt", POINT),
("mouseData", DWORD),
("flags", DWORD),
("time", DWORD),
("dwExtraInfo", ULONG_PTR)
]
But changing the signature to LLMouseProcCB = ctypes.CFUNCTYPE(LRESULT, ctypes.c_int, WPARAM, ctypes.POINTER(MSLLHOOKSTRUCT)) does not solve the problem, I still have a hook of 0.
Is this the right approach of tracking the mouse? What do I need to change to be able to correctly register hooks with Windows?
If you check GetLastError you should discover that the error is ERROR_GLOBAL_ONLY_HOOK (1429), i.e. WH_MOUSE_LL requires setting a global hook. The dwThreadId parameter is for setting a local hook. Fortunately WH_MOUSE_LL is unusual in that the global hook callback can be any function in the hooking process instead of having to be defined in a DLL, i.e. hMod can be NULL.
Pay attention to the calling convention if you need to support 32-bit Windows. The 32-bit Windows API generally requires stdcall (callee stack cleanup), so the callback needs to be defined via WINFUNCTYPE instead of CFUNCTYPE.
Another issue is that your code lacks a message loop. The thread that sets the hook needs to run a message loop in order to dispatch the message to the callback. In the example below I use a dedicated thread for this message loop. The thread sets the hook and enters a loop that only breaks on error or when a WM_QUIT message is posted. When the user enters Ctrl+C, I call PostThreadMessageW to gracefully exit.
from ctypes import *
from ctypes.wintypes import *
user32 = WinDLL('user32', use_last_error=True)
HC_ACTION = 0
WH_MOUSE_LL = 14
WM_QUIT = 0x0012
WM_MOUSEMOVE = 0x0200
WM_LBUTTONDOWN = 0x0201
WM_LBUTTONUP = 0x0202
WM_RBUTTONDOWN = 0x0204
WM_RBUTTONUP = 0x0205
WM_MBUTTONDOWN = 0x0207
WM_MBUTTONUP = 0x0208
WM_MOUSEWHEEL = 0x020A
WM_MOUSEHWHEEL = 0x020E
MSG_TEXT = {WM_MOUSEMOVE: 'WM_MOUSEMOVE',
WM_LBUTTONDOWN: 'WM_LBUTTONDOWN',
WM_LBUTTONUP: 'WM_LBUTTONUP',
WM_RBUTTONDOWN: 'WM_RBUTTONDOWN',
WM_RBUTTONUP: 'WM_RBUTTONUP',
WM_MBUTTONDOWN: 'WM_MBUTTONDOWN',
WM_MBUTTONUP: 'WM_MBUTTONUP',
WM_MOUSEWHEEL: 'WM_MOUSEWHEEL',
WM_MOUSEHWHEEL: 'WM_MOUSEHWHEEL'}
ULONG_PTR = WPARAM
LRESULT = LPARAM
LPMSG = POINTER(MSG)
HOOKPROC = WINFUNCTYPE(LRESULT, c_int, WPARAM, LPARAM)
LowLevelMouseProc = HOOKPROC
class MSLLHOOKSTRUCT(Structure):
_fields_ = (('pt', POINT),
('mouseData', DWORD),
('flags', DWORD),
('time', DWORD),
('dwExtraInfo', ULONG_PTR))
LPMSLLHOOKSTRUCT = POINTER(MSLLHOOKSTRUCT)
def errcheck_bool(result, func, args):
if not result:
raise WinError(get_last_error())
return args
user32.SetWindowsHookExW.errcheck = errcheck_bool
user32.SetWindowsHookExW.restype = HHOOK
user32.SetWindowsHookExW.argtypes = (c_int, # _In_ idHook
HOOKPROC, # _In_ lpfn
HINSTANCE, # _In_ hMod
DWORD) # _In_ dwThreadId
user32.CallNextHookEx.restype = LRESULT
user32.CallNextHookEx.argtypes = (HHOOK, # _In_opt_ hhk
c_int, # _In_ nCode
WPARAM, # _In_ wParam
LPARAM) # _In_ lParam
user32.GetMessageW.argtypes = (LPMSG, # _Out_ lpMsg
HWND, # _In_opt_ hWnd
UINT, # _In_ wMsgFilterMin
UINT) # _In_ wMsgFilterMax
user32.TranslateMessage.argtypes = (LPMSG,)
user32.DispatchMessageW.argtypes = (LPMSG,)
#LowLevelMouseProc
def LLMouseProc(nCode, wParam, lParam):
msg = cast(lParam, LPMSLLHOOKSTRUCT)[0]
if nCode == HC_ACTION:
msgid = MSG_TEXT.get(wParam, str(wParam))
msg = ((msg.pt.x, msg.pt.y),
msg.mouseData, msg.flags,
msg.time, msg.dwExtraInfo)
print('{:15s}: {}'.format(msgid, msg))
return user32.CallNextHookEx(None, nCode, wParam, lParam)
def mouse_msg_loop():
hHook = user32.SetWindowsHookExW(WH_MOUSE_LL, LLMouseProc, None, 0)
msg = MSG()
while True:
bRet = user32.GetMessageW(byref(msg), None, 0, 0)
if not bRet:
break
if bRet == -1:
raise WinError(get_last_error())
user32.TranslateMessage(byref(msg))
user32.DispatchMessageW(byref(msg))
if __name__ == '__main__':
import time
import threading
t = threading.Thread(target=mouse_msg_loop)
t.start()
while True:
try:
time.sleep(1)
except KeyboardInterrupt:
user32.PostThreadMessageW(t.ident, WM_QUIT, 0, 0)
break
A simplified version of the accepted answer
Note: pip install pywin32 first.
# Created by BaiJiFeiLong#gmail.com at 2022/2/10 22:27
from ctypes import WINFUNCTYPE, c_int, Structure, cast, POINTER, windll
from ctypes.wintypes import LPARAM, WPARAM, DWORD, PULONG, LONG
import win32con
import win32gui
def genStruct(name="Structure", **kwargs):
return type(name, (Structure,), dict(
_fields_=list(kwargs.items()),
__str__=lambda self: "%s(%s)" % (name, ",".join("%s=%s" % (k, getattr(self, k)) for k in kwargs))
))
#WINFUNCTYPE(LPARAM, c_int, WPARAM, LPARAM)
def hookProc(nCode, wParam, lParam):
msg = cast(lParam, POINTER(HookStruct))[0]
print(msgDict[wParam], msg)
return windll.user32.CallNextHookEx(None, nCode, WPARAM(wParam), LPARAM(lParam))
HookStruct = genStruct(
"Hook", pt=genStruct("Point", x=LONG, y=LONG), mouseData=DWORD, flags=DWORD, time=DWORD, dwExtraInfo=PULONG)
msgDict = {v: k for k, v in win32con.__dict__.items() if k.startswith("WM_")}
windll.user32.SetWindowsHookExW(win32con.WH_MOUSE_LL, hookProc, None, 0)
win32gui.PumpMessages()
Sample Output
WM_MOUSEMOVE Hook(pt=Point(x=50,y=702),mouseData=0,flags=0,time=343134468,dwExtraInfo=<ctypes.wintypes.LP_c_ulong object at 0x000001A466CDF8C8>)
WM_MOUSEMOVE Hook(pt=Point(x=49,y=704),mouseData=0,flags=0,time=343134484,dwExtraInfo=<ctypes.wintypes.LP_c_ulong object at 0x000001A466CDF8C8>)
WM_MOUSEMOVE Hook(pt=Point(x=49,y=705),mouseData=0,flags=0,time=343134484,dwExtraInfo=<ctypes.wintypes.LP_c_ulong object at 0x000001A466CDF8C8>)
WM_MOUSEMOVE Hook(pt=Point(x=49,y=705),mouseData=0,flags=0,time=343134500,dwExtraInfo=<ctypes.wintypes.LP_c_ulong object at 0x000001A466CDF8C8>)
WM_MOUSEMOVE Hook(pt=Point(x=49,y=706),mouseData=0,flags=0,time=343134500,dwExtraInfo=<ctypes.wintypes.LP_c_ulong object at 0x000001A466CDF8C8>)
WM_MOUSEMOVE Hook(pt=Point(x=48,y=707),mouseData=0,flags=0,time=343134515,dwExtraInfo=<ctypes.wintypes.LP_c_ulong object at 0x000001A466CDF8C8>)
WM_LBUTTONDOWN Hook(pt=Point(x=48,y=707),mouseData=0,flags=0,time=343134593,dwExtraInfo=<ctypes.wintypes.LP_c_ulong object at 0x000001A466CDF8C8>)
WM_LBUTTONUP Hook(pt=Point(x=48,y=707),mouseData=0,flags=0,time=343134671,dwExtraInfo=<ctypes.wintypes.LP_c_ulong object at 0x000001A466CDF8C8>)
I'm trying to get a list of all visible windows using ctypes in Python3.3
But with the code i have, not a single window is returned. The EnumWindows function fails, and the returned error code is 0.
import ctypes
user32 = ctypes.windll.user32
def worker(hwnd, lParam):
length = user32.GetWindowTextLengthW(hwnd) + 1
buffer = ctypes.create_unicode_buffer(length)
user32.GetWindowTextW(hwnd, buffer, length)
print("Buff: ", repr(buffer.value))
a = ctypes.WINFUNCTYPE(ctypes.c_bool,
ctypes.POINTER(ctypes.c_int),
ctypes.POINTER(ctypes.c_int))(worker)
if not user32.EnumWindows(a, True):
print("Err: ", ctypes.windll.kernel32.GetLastError())
Here is the current output:
Buff: ''
Err: 0
And this is what i expected:
Buff: 'Python 3.3.2 shell'
Buff: 'test.py - C:\Users\...'
[...]
Could you point me in the right direction to achieve this? Thanks in advance.
The callback needs to return TRUE to continue the enumeration. Your callback is implicitly returning None, which is false. The following revised version should do what you want:
import ctypes
from ctypes import wintypes
WNDENUMPROC = ctypes.WINFUNCTYPE(wintypes.BOOL,
wintypes.HWND,
wintypes.LPARAM)
user32 = ctypes.windll.user32
user32.EnumWindows.argtypes = [
WNDENUMPROC,
wintypes.LPARAM]
user32.GetWindowTextLengthW.argtypes = [
wintypes.HWND]
user32.GetWindowTextW.argtypes = [
wintypes.HWND,
wintypes.LPWSTR,
ctypes.c_int]
def worker(hwnd, lParam):
length = user32.GetWindowTextLengthW(hwnd) + 1
buffer = ctypes.create_unicode_buffer(length)
user32.GetWindowTextW(hwnd, buffer, length)
print("Buff: ", repr(buffer.value))
return True
cb_worker = WNDENUMPROC(worker)
if not user32.EnumWindows(cb_worker, 42):
raise ctypes.WinError()
The HWND handle type is an alias for c_void_p. LPARAM is an integer that's the same storage size as a pointer. It's defined as follows in wintypes:
if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
WPARAM = ctypes.c_ulong
LPARAM = ctypes.c_long
elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
WPARAM = ctypes.c_ulonglong
LPARAM = ctypes.c_longlong
Please don't get scared but the following code, if you are familiar with ctypes or C it should be easy to read.
I have been trying to get my ReadProcessMemory() and WriteProcessMemory() functions to be working for so long and have tried almost every possibility but the right one.
It launches the target program, returns its PID and handle just fine. But I always get a error code of 5 - ERROR_ACCESS_DENIED. When I run the read function(forget the write for now). I am launching this program as what I believe to be a CHILD process with PROCESS_ALL_ACCESS or CREATE_PRESERVE_CODE_AUTHZ_LEVEL.
I have also tried PROCESS_ALL_ACCESS and PROCESS_VM_READ when I open the handle.
I can also say that it is a valid memory location because I can find it on the running program with CheatEngine.
As for VirtualQuery() I get an error code of 998 - ERROR_NOACCESS which further confirms my suspicion of it being some security/privilege problem.
Any help or ideas would be very appreciated, again, it's my whole program so far, don't let it scare you =P.
from ctypes import *
from ctypes.wintypes import BOOL
import binascii
BYTE = c_ubyte
WORD = c_ushort
DWORD = c_ulong
LPBYTE = POINTER(c_ubyte)
LPTSTR = POINTER(c_char)
HANDLE = c_void_p
PVOID = c_void_p
LPVOID = c_void_p
UNIT_PTR = c_ulong
SIZE_T = c_ulong
class STARTUPINFO(Structure):
_fields_ = [("cb", DWORD),
("lpReserved", LPTSTR),
("lpDesktop", LPTSTR),
("lpTitle", LPTSTR),
("dwX", DWORD),
("dwY", DWORD),
("dwXSize", DWORD),
("dwYSize", DWORD),
("dwXCountChars", DWORD),
("dwYCountChars", DWORD),
("dwFillAttribute",DWORD),
("dwFlags", DWORD),
("wShowWindow", WORD),
("cbReserved2", WORD),
("lpReserved2", LPBYTE),
("hStdInput", HANDLE),
("hStdOutput", HANDLE),
("hStdError", HANDLE),]
class PROCESS_INFORMATION(Structure):
_fields_ = [("hProcess", HANDLE),
("hThread", HANDLE),
("dwProcessId", DWORD),
("dwThreadId", DWORD),]
class MEMORY_BASIC_INFORMATION(Structure):
_fields_ = [("BaseAddress", PVOID),
("AllocationBase", PVOID),
("AllocationProtect", DWORD),
("RegionSize", SIZE_T),
("State", DWORD),
("Protect", DWORD),
("Type", DWORD),]
class SECURITY_ATTRIBUTES(Structure):
_fields_ = [("Length", DWORD),
("SecDescriptor", LPVOID),
("InheritHandle", BOOL)]
class Main():
def __init__(self):
self.h_process = None
self.pid = None
def launch(self, path_to_exe):
CREATE_NEW_CONSOLE = 0x00000010
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000
startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION()
security_attributes = SECURITY_ATTRIBUTES()
startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x0
startupinfo.cb = sizeof(startupinfo)
security_attributes.Length = sizeof(security_attributes)
security_attributes.SecDescriptior = None
security_attributes.InheritHandle = True
if windll.kernel32.CreateProcessA(path_to_exe,
None,
byref(security_attributes),
byref(security_attributes),
True,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL,
None,
None,
byref(startupinfo),
byref(process_information)):
self.pid = process_information.dwProcessId
print "Success: CreateProcess - ", path_to_exe
else:
print "Failed: Create Process - Error code: ", windll.kernel32.GetLastError()
def get_handle(self, pid):
PROCESS_ALL_ACCESS = 0x001F0FFF
PROCESS_VM_READ = 0x0010
self.h_process = windll.kernel32.OpenProcess(PROCESS_VM_READ, False, pid)
if self.h_process:
print "Success: Got Handle - PID:", self.pid
else:
print "Failed: Get Handle - Error code: ", windll.kernel32.GetLastError()
windll.kernel32.SetLastError(10000)
def read_memory(self, address):
buffer = c_char_p("The data goes here")
bufferSize = len(buffer.value)
bytesRead = c_ulong(0)
if windll.kernel32.ReadProcessMemory(self.h_process, address, buffer, bufferSize, byref(bytesRead)):
print "Success: Read Memory - ", buffer.value
else:
print "Failed: Read Memory - Error Code: ", windll.kernel32.GetLastError()
windll.kernel32.CloseHandle(self.h_process)
windll.kernel32.SetLastError(10000)
def write_memory(self, address, data):
count = c_ulong(0)
length = len(data)
c_data = c_char_p(data[count.value:])
null = c_int(0)
if not windll.kernel32.WriteProcessMemory(self.h_process, address, c_data, length, byref(count)):
print "Failed: Write Memory - Error Code: ", windll.kernel32.GetLastError()
windll.kernel32.SetLastError(10000)
else:
return False
def virtual_query(self, address):
basic_memory_info = MEMORY_BASIC_INFORMATION()
windll.kernel32.SetLastError(10000)
result = windll.kernel32.VirtualQuery(address, byref(basic_memory_info), byref(basic_memory_info))
if result:
return True
else:
print "Failed: Virtual Query - Error Code: ", windll.kernel32.GetLastError()
main = Main()
address = None
main.launch("C:\Program Files\ProgramFolder\Program.exe")
main.get_handle(main.pid)
#main.write_memory(address, "\x61")
while 1:
print '1 to enter an address'
print '2 to virtual query address'
print '3 to read address'
choice = raw_input('Choice: ')
if choice == '1':
address = raw_input('Enter and address: ')
if choice == '2':
main.virtual_query(address)
if choice == '3':
main.read_memory(address)
Thanks!
You should try to set debugging privileges to your process.
Use the following code once before you try to Open / Create a process.
class TOKEN_PRIVILEGES( Structure ):
_fields_ = [
('PrivilegeCount', c_uint),
('Luid', LUID),
('Attributes', c_uint) ]
OpenProcessToken = windll.advapi32.OpenProcessToken
OpenProcessToken.argtypes = [
c_int, # HANDLE ProcessHandle
c_uint, # DWORD DesiredAccess
c_void_p ] # PHANDLE TokenHandle
OpenProcessToken.restype = ErrorIfZero
AdjustTokenPrivileges = windll.advapi32.AdjustTokenPrivileges
AdjustTokenPrivileges.argtypes = [
c_int, # HANDLE TokenHandle
c_int, # BOOL DisableAllPrivileges
c_void_p, # PTOKEN_PRIVILEGES NewState
c_uint, # DWORD BufferLength
c_void_p, # PTOKEN_PRIVILEGES PreviousState
c_void_p ] # PDWORD ReturnLength
AdjustTokenPrivileges.restype = ErrorIfZero
LookupPrivilegeValue = windll.advapi32.LookupPrivilegeValueA
LookupPrivilegeValue.argtypes = [
c_char_p, # LPCTSTR lpSystemName
c_char_p, # LPCTSTR lpName
c_void_p ] # PLUID lpLuid
LookupPrivilegeValue.restype = ErrorIfZero
access_token = c_int(0)
privileges = TOKEN_PRIVILEGES()
OpenProcessToken( GetCurrentProcess(), win32con.TOKEN_QUERY | win32con.TOKEN_ADJUST_PRIVILEGES, byref(access_token) )
access_token = access_token.value
LookupPrivilegeValue( None, "SeDebugPrivilege", byref(privileges.Luid) )
privileges.PrivilegeCount = 1
privileges.Attributes = 2
AdjustTokenPrivileges(
access_token,
0,
byref(privileges),
0,
None,
None )
CloseHandle( access_token )
Maybe this will help you: Creating a Security Descriptor for a New Object in C++
One possible reason for your access denied error is that the user under which you run WriteProcessMemory runs needs to have DEBUG privilege.
Starting with Vista, this privilege is only activated for Administrators, and only when running the application with "Run as Admin".
You can add the privilege to any account.
I see several problems with your code, and it's difficult to know which one is the underlying cause of your exact problem. For example, the line:
address = raw_input('Enter and address: ')
Should probably be something like:
address = long(raw_input('Enter and address: '), 0)
As the code stands, every time you pass address to a function via ctypes what you are actually doing is creating a temporary buffer which contains exactly the string typed by the user and passing in the address of that buffer in the Python process. Definitely not what you want. If I fix that issue, then your program seems to work most of the time.
From my limited testing, most (all?) of the rest of the failures can be fixed by setting the correct argtypes for ReadProcessMemory. This is the single biggest issue I see with ctypes code, a problem exacerbated by handling ctypes.c_voidp as int in Python. If argtypes is not specified, then all arguments are considered to be ctypes.c_int. Anything outside of the range of signed integer -- a pointer or handle with high bit set, for example -- is silently truncated.
Not the cause of your bugs but suboptimal are the lines:
buffer = c_char_p("The data goes here")
bufferSize = len(buffer.value)
The ctypes module provides functions for creating buffers:
bufferSize = 32
buffer = ctypes.create_string_buffer(bufferSize)
Hopefully this will get you down the right path.
PROCESS_VM_READ is not enough: Try use both PROCESS_VM_WRITE + PROCESS_VM_OPERATION. I also received an error violation but the process memory still changed. Add try catch to keep your program alive.
PROCESS_VM_READ = 0x0010
PROCESS_VM_WRITE = 0x0020
PROCESS_VM_OPERATION = 0x0008
PROCESS_ALL_ACCESS = 0x1F0FFF
For me PROCESS_VM_WRITE was not enough, I needed to add PROCESS_VM_OPERATION as well.