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)
Explanation
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 GetWindowText
(using GetWindowTextLength
to find out the right buffer size to hold the string).
Now let’s see the documentation for EnumWindows
:
BOOL WINAPI EnumWindows( __in WNDENUMPROC lpEnumFunc, __in LPARAM lParam );
Translated into Python (and English), here’s how you call the function:
EnumWindows(some_callback_function, some_data)
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; HWND
and 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 ctypes.cdll
.
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.
Because IsWindowVisible
, GetWindowText
, and GetWindowTextLength
are quite straightforward, I’ll skip the explanation. If you can’t figure out how to use them, refer to my previous tutorial.
Conclusion
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.
Corrections
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”.
Hello,
I tried your codes with Python 2.6.6, and got the error message
Traceback (most recent call last):
File “C:/test.py”, line 17, in
EnumWindows(EnumWindowsProc(foreach_window), 0)
ValueError: Procedure probably called with not enough arguments (2029202 bytes missing)
Any help would appreciated.
-Paul Kang
Oops, you’re right! The callback function should be WINFUNCTYPE, not CFUNCTYPE. This is fixed in the current post.
Pingback: Python: Getting the title of windows, getting their processes and their commandlines using ctypes and win32 | Pixomania
Great! It works. 🙂
Hi, your code worked and it’s good, while is there a way to enum windows’ title which belong to a specific program?
I’m not sure this is the most efficient way to do it, but you can enumerate all windows as in this post, then:
Pingback: python - Ottenere HWND di ogni Finestra?
Pingback: Python ctypes获取当前所有打开窗口title | 小核桃
Pingback: python - Obtenir HWND de chaque Fenêtre?
Pingback: python - Ottenere il titolo di una finestra di un altro programma che utilizza il nome del processo
Pingback: python - Conseguir el título de una ventana de otro programa usando el nombre del proceso
Hi, Your code worked well and helped me a lot!
You can actually use anonymous function in EnumWindowsProc to make the code more clear 😀
have a good day!