win32 api with python
pywin32 is currently the best way to manipulate windows API.
It is maintained and the github source code is also public and available here :
pywin32 github
The imports used in this page are:
import win32com.client import win32gui import win32process |
Find window functions
Find the first window which the window title matches and/or the class name of the window class
matches:
win32gui.FindWindow(class, title)
The FindWindow() functions return the handle id (int) of the first window matching to the
criteria we submit.
Its concrete signature is: win32gui.FindWindow(class: str=None, title: str=None)->int
Behavior:
– the class name and the title are optional, we can pass one or the other or
both.
– The case of the input is not sensitive.
– The text input has to match exactly with the title of the window, we cannot provide only a
part of the title as input.
Examples where we search only on the title
Suppose we have a window opened which the title is ‘david’, we can retrieve it in this way.
Note the 3rd example which doesn’t return any match because the input contains only a part of
the full title:
window = win32gui.FindWindow(None, 'david') print(f'window with title match(with input the exact case and characters)={window}') # window with title match(with input the exact case and characters)=281646 window = win32gui.FindWindow(None, 'davID') print(f'window with title match(with input the exact characters but different case )={window}') # window with title match(with input the exact characters but different case )=281646 window = win32gui.FindWindow(None, 'davi') print(f'window with title match(with input the exact case but with only a part of characters)=' f'{window}') # window with title match(with input the exact case but with only a part of characters)=0 |
Examples where we search only on the class
Suppose we have a window file explorer opened, we can retrieve it thanks to the class name that
is CabinetWClass
:
window = win32gui.FindWindow('CabinetWClass', None) window_text = win32gui.GetWindowText(window) print(f'window with CabinetWClass class. window={window}: window_text={window_text}') |
Output:
window with CabinetWClass class. window=611882: window_text=PC |
We may have multiple windows of file explorer but as seen previously the function will return only the first result.
Examples where we search both on the class and the title
Beware: The 2 parameters have to match if we provide both of them.
window = win32gui.FindWindow('CabinetWClass', 'daviD') window_text = win32gui.GetWindowText(window) print(f'window with CabinetWClass class and title "daviD". window={window}: window_text={window_text}') |
Output:
window with CabinetWClass class and title "daviD". window=87772: window_text=david |
Find all windows which match with our input where our input maybe anything: win32gui.EnumWindows(foo_callback, foo_input)
The function EnumWindows
accepts as parameter a callback and a
string that we can use in anyway to perform our matching in the callback function.
Beyond the parameter we can provide, with that function we have the hand to define how to
perform the match.
That is we can do a match on the title, on the class name or in any other attribute that defines
a window object such as the state of the window.
Behavior
– The function enumerates all windows and so doesn’t stop until the loop is finished.
It means that we have to store the handle information that interest us inside the callback to be
able to reuse it later.
Example: List all windows
Here is the callback function:
def window_enum_callback_print_all(hwnd, text): print(hex(hwnd), win32gui.GetWindowText(hwnd)) print(f'win32gui.GetClassName()={win32gui.GetClassName(hwnd)}') |
Here is the code that calls the win32gui.EnumWindows()
function:
win32gui.EnumWindows(window_enum_callback_print_all, '') |
Example: List windows which title contains ‘owertoys’ whatever the case.
Here is the callback function:
def window_enum_callback_set_if_text_matches(hwnd, part_of_title): """Set the handle of the current instance if text matches with the text title """ window_title = str(win32gui.GetWindowText(hwnd)) if part_of_title.lower() in window_title.lower(): matching_windows.append(hwnd) |
We can notice that we store the window ids in a list.
Here is the code that calls the win32gui.EnumWindows()
function:
matching_windows: List[int] = [] win32gui.EnumWindows(window_enum_callback_set_if_text_matches, 'owertoys') print(f'matching_windows with loose title matching for owertoys={matching_windows}') handles_title: List[str] = [win32gui.GetWindowText(m) for m in matching_windows] print(f'handles_title={handles_title}') |
Output:
matching_windows with loose title matching for owertoys=[66744, 66456, 66140] handles_title=['GDI+ Window (PowerToys.Awake.exe)', 'PowerToys Runner', 'GDI+ Window (PowerToys.exe)'] |
Example: List all windows matching a class name and a title if it is provided
It is an interesting case because the FindWindow()
function doesn’t return all
windows matching but only the first one matching a class name, so the EnumWindows()
function here solves this problem
We will we reuse the example of the file explorer class name seen previously
here is the callback function:
def window_enum_callback_set_for_file_explorer_window(hwnd, text: str): """Pass to win32gui.EnumWindows() to check all the opened windows""" # if win32gui.IsWindowVisible(hwnd): if win32gui.GetClassName(hwnd) == 'CabinetWClass': if not text: matching_windows.append(hwnd) else: window_text = win32gui.GetWindowText(hwnd) if text.lower() in window_text.lower(): matching_windows.append(hwnd) |
The client code:
matching_windows: List[int] = [] win32gui.EnumWindows(window_enum_callback_set_for_file_explorer_window, None) print(f'matching_windows with explorer class match ={matching_windows}') handles_title: List[str] = [win32gui.GetWindowText(m) for m in matching_windows] print(f'handles_title={handles_title}') # If we want to, we can specify also as seen previously a text to match with the window title matching_windows: List[int] = [] win32gui.EnumWindows(window_enum_callback_set_for_file_explorer_window, 'DAvi') print(f'matching_windows with explorer class match and David as title match={matching_windows}') handles_title: List[str] = [win32gui.GetWindowText(m) for m in matching_windows] print(f'handles_title={handles_title}') |
Output:
matching_windows with explorer class match =[18569228, 611882, 87772] handles_title=['AppData', 'PC', 'david'] matching_windows with explorer class match and David as title match=[87772] handles_title=['david'] |
focus on windows function
We can focus on a specific window if we know its handle id.
We achieve it with this function: win32gui.SetForegroundWindow(handle_id)
Important:
In some specific cases, we cannot focus on a window without sending a key on it before.
To send a key on a window, we can use this function: win32com.client.Dispatch("WScript.Shell")
that returns a shell object.
Example: find a google chrome window and focus on it
without sending a key:
window = win32gui.FindWindow('Chrome_WidgetWin_1', None) win32gui.SetForegroundWindow(window) |
with sending a key:
window = win32gui.FindWindow('Chrome_WidgetWin_1', None) shell = win32com.client.Dispatch("WScript.Shell") shell.SendKeys('') win32gui.SetForegroundWindow(window) |
Important:
Sending a key to the window we want to focus may be needed. But we cannot send any key because
some keys such as a letter or a modifier may have a side effect on the window which we want to
focus.
A good workaround to avoid any side effect is to send the ‘none’ key. This one may be not
recognized
in all windows versions but in windows 10 it is.
It is what we have done in the previous example:
shell.SendKeys('')
Retrieve a process id associated to a window
To achieve it, we need to know the window handle id of the window and to call the function:
win32process.GetWindowThreadProcessId(window_handle_id)
.
The function returns a tuple representing the thread id and the process id.
example
window = win32gui.FindWindow('Chrome_WidgetWin_1', None) threadid, pid = win32process.GetWindowThreadProcessId(window) print(f'threadid, pid ={threadid, pid} for window with class name Chrome_WidgetWin_1 and window handle id {window}') |
Output:
threadid, pid =(6636, 8756) for window with class name Chrome_WidgetWin_1 and window handle id 460658 |