Interoperate with win32 api with python

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
ci
Ce contenu a été publié dans Non classé. Vous pouvez le mettre en favoris avec ce permalien.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *