How to get Windows window names with ctypes in python -
i try windows window title names , pids through handles long objects. code works there wrong it. 4 window titles when should 10 or more. can , tell me how fix code? think problem how convert long objects (i don't understand them well, ctypes in general).
from __future__ import print_function ctypes import * psapi = windll.psapi titles = [] # window title pid def gwtfp(): max_array = c_ulong * 4096 pprocessids = max_array() pbytesreturned = c_ulong() psapi.enumprocesses(byref(pprocessids), sizeof(pprocessids), byref(pbytesreturned)) # number of returned processes nreturned = pbytesreturned.value/sizeof(c_ulong()) pidprocessarray = [i in pprocessids][:nreturned] print(pidprocessarray) # enumwindows = windll.user32.enumwindows enumwindowsproc = winfunctype(c_bool, pointer(c_int), pointer(c_int)) getwindowtext = windll.user32.getwindowtextw getwindowtextlength = windll.user32.getwindowtextlengthw iswindowvisible = windll.user32.iswindowvisible process in pidprocessarray: #print("process pid %d" % process) if iswindowvisible(process): length = getwindowtextlength(process) buff = create_unicode_buffer(length + 1) getwindowtext(process, buff, length + 1) titles.append(buff.value) gwtfp() print(titles)
you're passing process id functions take window handle. want enumerate handles top-level windows , map each window process id.
first lets define ctypes function prototypes proper type checking on function arguments. also, use use_last_error=true
safest error handling via ctypes.get_last_error
. lot of windows functions return 0 error, it's convenient have single errcheck
function case, such check_zero
.
from __future__ import print_function import ctypes ctypes import wintypes collections import namedtuple user32 = ctypes.windll('user32', use_last_error=true) def check_zero(result, func, args): if not result: err = ctypes.get_last_error() if err: raise ctypes.winerror(err) return args if not hasattr(wintypes, 'lpdword'): # py2 wintypes.lpdword = ctypes.pointer(wintypes.dword) windowinfo = namedtuple('windowinfo', 'pid title') wndenumproc = ctypes.winfunctype( wintypes.bool, wintypes.hwnd, # _in_ hwnd wintypes.lparam,) # _in_ lparam user32.enumwindows.errcheck = check_zero user32.enumwindows.argtypes = ( wndenumproc, # _in_ lpenumfunc wintypes.lparam,) # _in_ lparam user32.iswindowvisible.argtypes = ( wintypes.hwnd,) # _in_ hwnd user32.getwindowthreadprocessid.restype = wintypes.dword user32.getwindowthreadprocessid.argtypes = ( wintypes.hwnd, # _in_ hwnd wintypes.lpdword,) # _out_opt_ lpdwprocessid user32.getwindowtextlengthw.errcheck = check_zero user32.getwindowtextlengthw.argtypes = ( wintypes.hwnd,) # _in_ hwnd user32.getwindowtextw.errcheck = check_zero user32.getwindowtextw.argtypes = ( wintypes.hwnd, # _in_ hwnd wintypes.lpwstr, # _out_ lpstring ctypes.c_int,) # _in_ nmaxcount
here's function list visible windows. uses callback that's closure on result
instead of using optional lparam
argument. latter require casting argument. using closure simpler.
def list_windows(): '''return sorted list of visible windows.''' result = [] @wndenumproc def enum_proc(hwnd, lparam): if user32.iswindowvisible(hwnd): pid = wintypes.dword() tid = user32.getwindowthreadprocessid( hwnd, ctypes.byref(pid)) length = user32.getwindowtextlengthw(hwnd) + 1 title = ctypes.create_unicode_buffer(length) user32.getwindowtextw(hwnd, title, length) result.append(windowinfo(pid.value, title.value)) return true user32.enumwindows(enum_proc, 0) return sorted(result)
for completeness, here's function list process ids. includes processes belong other windows sessions (e.g. services in session 0).
psapi = ctypes.windll('psapi', use_last_error=true) psapi.enumprocesses.errcheck = check_zero psapi.enumprocesses.argtypes = ( wintypes.lpdword, # _out_ pprocessids wintypes.dword, # _in_ cb wintypes.lpdword,) # _out_ pbytesreturned def list_pids(): '''return sorted list of process ids.''' length = 4096 pid_size = ctypes.sizeof(wintypes.dword) while true: pids = (wintypes.dword * length)() cb = ctypes.sizeof(pids) cbret = wintypes.dword() psapi.enumprocesses(pids, cb, ctypes.byref(cbret)) if cbret.value < cb: length = cbret.value // pid_size return sorted(pids[:length]) length *= 2
for example:
if __name__ == '__main__': print('process ids:') print(*list_pids(), sep='\n') print('\nwindows:') print(*list_windows(), sep='\n')
msdn links:
Comments
Post a Comment