This post shows how you can retrieve all window titles in Microsoft Windows using Python’s ctypes module. Moreover, it also acts as a ctypes tutorial, showing how to create and use callback functions.
The following is the full code. Keep reading if you want to understand how it works. (Note: If you are reading this as a ctypes tutorial and are having trouble following the explanation, you may want to go through my previous tutorial first.)
import ctypes EnumWindows = ctypes.windll.user32.EnumWindows EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) GetWindowText = ctypes.windll.user32.GetWindowTextW GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW IsWindowVisible = ctypes.windll.user32.IsWindowVisible titles =  def foreach_window(hwnd, lParam): if IsWindowVisible(hwnd): length = GetWindowTextLength(hwnd) buff = ctypes.create_unicode_buffer(length + 1) GetWindowText(hwnd, buff, length + 1) titles.append(buff.value) return True EnumWindows(EnumWindowsProc(foreach_window), 0) print(titles)
First off, we import some Win32 functions from
user32.dll. The function names are quite self-explanatory and should give you a picture of how everything is going to work: we call
EnumWindows to enumerate all toplevel windows, filter them with
IsWindowVisible to weed out most of the junk, and get the window titles with
GetWindowTextLength to find out the right buffer size to hold the string).
Now let’s see the documentation for
BOOL WINAPI EnumWindows( __in WNDENUMPROC lpEnumFunc, __in LPARAM lParam );
Translated into Python (and English), here’s how you call the function:
The callback function (an
EnumWindowsProc) will be called for each topmost window. lParam is some optional, user-defined data that will also be passed to the callback.
BOOL CALLBACK EnumWindowsProc( __in HWND hwnd, __in LPARAM lParam );
As should be apparent, the function gets passed a window handle (hwnd) and the same data argument that we passed to
EnumWindows (lParam). lParam is useful when, for example, we want to store all the window handles in an array that is not otherwise reachable from the callback’s scope. The callback may return
false to stop the iteration, or
true to continue.
How do we create a callback function in ctypes?
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) def some_function(hwnd, lParam): return True callback = EnumWindowsProc(some_function)
WINFUNCTYPE‘s first parameter is the return value of the callback (a boolean). The other parameters are the actual function parameters;
LPARAM are both aliases of
int *. Note that we use
WINFUNCTYPE instead of
CFUNCTYPE because that’s what the Win32 API expects (stdcall instead of cdecl)—this is the same reason we use
ctypes.windll instead of
Putting together all this information, we have the following code:
hwnds =  def foreach_window(hwnd, lParam): hwnds.append(hwnd) return True EnumWindows(EnumWindowsProc(foreach_window), 0)
Notice how we pass a null (0) as lParam because we’re not using it. In C, we can pass the equivalent to hwnds there to avoid making it a global variable.
This post presents code to retrieve window titles in Windows using ctypes. Most of the post explains the
EnumWindows Win32 function and its interaction with the callback function
EnumWindowsProc. Of particular interest is ctypes’
WINFUNCTYPE function, which is used to declare a callback function.
An earlier version of this post used
CFUNCTYPE instead of
WINFUNCTYPE. This caused the function to be called using the cdecl calling convention instead of stdcall (which Win32 uses), resulting in an error message: “Procedure probably called with not enough arguments”.