Reputation: 111
I can't seem to get EnumThreadWindows to work. It keeps failing with error 87. Code:
error = ctypes.WinDLL('Kernel32').GetLastError
enum_func = ctypes.WINFUNCTYPE(wintypes.BOOL,
wintypes.HWND,
wintypes.LPARAM)
def callback(hwnd, lParam):
length = ctypes.WinDLL('User32').GetWindowTextLengthW(hwnd) + 1
buf = ctypes.create_unicode_buffer(length)
ctypes.WinDLL('User32').GetWindowTextW(hwnd, buf, length)
print(buf.value)
worker = enum_func(callback)
test = ctypes.WinDLL('User32').EnumThreadWindows(6000, worker, None)
print(error(test))
I've tried pid = wintypes.DWORD(6000)
, test = ctypes.WinDLL('User32').EnumThreadWindows(pid.value, worker, None)
to no avail.
What am I doing wrong?
Upvotes: 0
Views: 239
Reputation: 177461
Here's working code. Make sure to pass a valid thread ID.
You might be interested in the fact that an LPARAM can be anything, including a python object, so if you pass a Python object it can be manipulated in the callback:
import ctypes
from ctypes import wintypes
from collections import namedtuple
Window = namedtuple('Window','hwnd title')
WNDENUMPROC = ctypes.WINFUNCTYPE(wintypes.BOOL,
wintypes.HWND,
ctypes.py_object) # to allow any Python object.
u32 = ctypes.WinDLL('user32',use_last_error=True) # to ensure GetLastError was captured
# Declaring arguments and return type helps catch errors and support 64-bit.
# HWND is 64-bit on 64-bit Python, and could get truncated if left to ctypes default
# of c_int (32-bit). This code works on Python 2.7 and 3.9.
u32.GetWindowTextLengthW.argtypes = wintypes.HWND,
u32.GetWindowTextLengthW.restype = ctypes.c_int
u32.GetWindowTextW.argtypes = wintypes.HWND,wintypes.LPWSTR,ctypes.c_int
u32.GetWindowTextW.restype = ctypes.c_int
u32.EnumThreadWindows.argtypes = wintypes.DWORD,WNDENUMPROC,ctypes.py_object # to pass Python object
u32.EnumThreadWindows.restype = wintypes.BOOL
@WNDENUMPROC # decorator makes this a ctypes-compatible function
def callback(hwnd, lParam):
length = u32.GetWindowTextLengthW(hwnd) + 1
buf = ctypes.create_unicode_buffer(length)
u32.GetWindowTextW(hwnd, buf, length)
lParam.append(Window(hwnd,buf.value)) # append data to the callback parameter
return True # return True to continue enumeration
result = [] # A python object
if u32.EnumThreadWindows(6332, callback, result): # 6332 was a thread in my explore.exe
for wnd in result: # list results when enumeration complete
print(wnd)
else:
print('error:',ctypes.get_last_error()) # print error of EnumThreadWindows.
# Python could use a Win32 function that fails in
# between the ctypes call and calling GetLastError
# directly.
Output:
Window(hwnd=65832, title='')
Window(hwnd=65838, title='')
Window(hwnd=131174, title='')
Window(hwnd=65682, title='')
Window(hwnd=65678, title='')
Window(hwnd=65826, title='Program Manager')
Window(hwnd=196928, title='MSCTFIME UI')
Window(hwnd=65680, title='Default IME')
Upvotes: 2