Как найти hwnd python

Совсем просто не получится, потому что:

  1. Может быть несколько процессов с одним именем (например, можно открыть несколько окон Блокнота).
  2. У процесса может быть несколько окон

Поэтому сначала нужно получить список процессов с заданными именем файла (или для простоты первый попавшийся процесс, подходящий по этому условию), потом список окон для данного процесса (процессов).

1. Получаем список процессов, у которых имя файла равно notepad.exe

Можно воспользоваться пакетом psutil

import psutil

# Список процессов с именем файла notepad.exe:
notepads = [item for item in psutil.process_iter() if item.name() == 'notepad.exe']
print(notepads)  # [<psutil.Process(pid=4416, name='notepad.exe') at 64362512>]

# Просто pid первого попавшегося процесса с именем файла notepad.exe:
pid = next(item for item in psutil.process_iter() if item.name() == 'notepad.exe').pid
# (вызовет исключение StopIteration, если Блокнот не запущен)

print(pid)  # 4416

2. Получаем список окон процесса с заданным pid

Чтобы получить список окон процесса, можно воспользоваться функцией EnumWindows.

Например, нужно получить все окна процесса с ID 4416:

import win32gui
import win32process

def enum_window_callback(hwnd, pid):
    tid, current_pid = win32process.GetWindowThreadProcessId(hwnd)
    if pid == current_pid and win32gui.IsWindowVisible(hwnd):
        windows.append(hwnd)

# pid = 4416  # pid уже получен на предыдущем этапе
windows = []

win32gui.EnumWindows(enum_window_callback, pid)

# Выводим заголовки всех полученных окон
print([win32gui.GetWindowText(item) for item in windows])

Вывод:

['Безымянный — Блокнот']

Если в Блокноте открыть еще настройку параметров страницы, то список будет такой:

['Параметры страницы', 'Безымянный — Блокнот']

Python —- pywin32 How to get a window handle

  • One: Introduce the library you want to use
  • Two: Display the properties of the window
    • 1. Get the handle of all windows
    • 2. Get the sub-window handle of the window
    • 3. Get the title of the handle
    • 4. Get the window class name
  • Third, actual operation
    • Top and cancel
    • 2. Display and hide the window
  • Fourth, case demonstration
    • Show and hide trays

Halo, readers, this column opens an expansion of “how to make PC software with python”.

When we want to handle Windows software windows, we often hit the top, hide and display the window, and readers want to hide the computer tray, taskbar, etc. This article is to lead the reader learning window handle, and how to apply the Win32 module of the Python band to read the handle of each window in the interface.

I hope that through this article, readers can make their own small software in this article.

One: Introduce the library you want to use

import sys 
import win32gui
import win32con

Two: Display the properties of the window

1. Get the handle of all windows

def get_all_windows():
    hWnd_list = []
    win32gui.EnumWindows(lambda hWnd, param: param.append(hWnd), hWnd_list)
    print(hWnd_list)
    return hWnd_list
>>[66364, 66014, 65964, 65854, 65850, 65846, 65842, 65826, 65812, 65802, 65858, 65862, 65876, 65794, ....]

2. Get the sub-window handle of the window

def get_son_windows(parent):
      hWnd_child_list = []
      win32gui.EnumChildWindows(parent, lambda hWnd, param: param.append(hWnd), hWnd_child_list)
      print(hWnd_child_list)
      return hWnd_child_list
>>[66364, 66014, 65964, 65854, ...]

3. Get the title of the handle

def get_title(hwnd):
    title = win32gui.GetWindowText(hwnd)
    print('Window Title:% S' % (title))
    return title
>>Window header:set up 

4. Get the window class name

def get_clasname(hwnd):
    clasname = win32gui.GetClassName(hwnd)
    print('Window class name:% s' % (clasname))
    return clasname
>>Window class name:ApplicationFrameWindow

Third, actual operation

Top and cancel

Window top
def set_top(hwnd):
    win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0,
                          win32con.SWP_NOMOVE | win32con.SWP_NOACTIVATE | win32con.SWP_NOOWNERZORDER | win32con.SWP_SHOWWINDOW | win32con.SWP_NOSIZE)
Window cancels top
def set_down(hwnd):
    win32gui.SetWindowPos(hwnd, win32con.HWND_NOTOPMOST, 0, 0, 0, 0,
                          win32con.SWP_SHOWWINDOW | win32con.SWP_NOSIZE | win32con.SWP_NOMOVE)

2. Display and hide the window

Get the handle according to the window name
# Get the handle according to the window name
def get_hwnd_from_name(name):
    hWnd_list = get_all_windows()
    for hwd in hWnd_list:
        title = get_title(hwd)
        if title == name:
            return hwd
Window display
def xianshi(name):
    hwd = get_hwnd_from_name(name)
    win32gui.ShowWindow(hwd, win32con.SW_SHOW)  
Window hidden
def yingcang(name):
    hwd = get_hwnd_from_name(name)
    win32gui.ShowWindow(hwd, win32con.SW_HIDE)

Fourth, case demonstration

Show and hide trays

Get the task handle of the upper right corner tray
# Get the task handle of the pallet in the lower right corner
def get_tuopan_hwd():
    handle = win32gui.FindWindow("Shell_TrayWnd", None)
    hWnd_child_list = get_son_windows(handle)[1:]
    tuopan_hwd_list = []
    flag = False
    for i in hWnd_child_list:
        if get_clasname(i) ==  'TrayNotifyWnd':
            flag = True
        if flag:
            tuopan_hwd_list.append(i)
    return tuopan_hwd_list
Hidden tray
def yingcang(name=''):
    tuopan_hwd_list = get_tuopan_hwd()
    if name == '':
        for i in tuopan_hwd_list[:7] :# [: 7] Because some basic content should be retained, you can also hide
            win32gui.ShowWindow(i, win32con.SW_HIDE)
    else:
        win32gui.ShowWindow(name, win32con.SW_HIDE)
Show tray
def xianshi(name = ''):
    tuopan_hwd_list = get_tuopan_hwd()
    if name == '':
        for i in tuopan_hwd_list:
​
            win32gui.ShowWindow(i, win32con.SW_SHOW)
    else:
        win32gui.ShowWindow(name, win32con.SW_SHOW)

how can I get the handle of a tkinter window?
I tried …

h = self._get_hwnd()

but it doesn’t work. I’m using Python
IDLE Shell 3.10.1 (OS: Windows 10).

Example:

import tkinter as tk
root=tk.Tk()
root.title=("Test")
text1=tk.Text(root, height=10, width=50)
text1.insert(tk.INSERT,self._get_hwnd())
text1.pack()
root.mainloop()

martineau's user avatar

martineau

118k25 gold badges164 silver badges294 bronze badges

asked Dec 27, 2021 at 20:15

Werner925's user avatar

12

According to the official tk documentation, the winfo_id method will return the HWND on windows.

From the official tcl/tk man page for the winfo command:

winfo id window
Returns a hexadecimal string giving a low-level platform-specific identifier for window. On Unix platforms, this is the X window identifier. Under Windows, this is the Windows HWND. On the Macintosh the value has no meaning outside Tk.

Translated to tkinter, winfo id window is window.winfo_id().

answered Dec 27, 2021 at 21:44

Bryan Oakley's user avatar

Bryan OakleyBryan Oakley

366k52 gold badges532 silver badges679 bronze badges

3

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

Ce contenu a été publié dans Non classé. Vous pouvez le mettre en favoris avec ce permalien.

Question:

How to get hwnd of a window by process name. For example, I can get hwnd by the window name

hwnd = win32gui.FindWindow(None, "Notepad")

Is it just as easy to get hwnd by process name?

Answer:

It just won’t work, because:

  1. There can be multiple processes with the same name (for example, you can open multiple Notepad windows).
  2. A process can have multiple windows

Therefore, first you need to get a list of processes with a given file name (or, for simplicity, the first available process that matches this condition), then a list of windows for this process (processes).

1. We get a list of processes for which the file name is equal to notepad.exe

You can use the psutil package

import psutil

# Список процессов с именем файла notepad.exe:
notepads = [item for item in psutil.process_iter() if item.name() == 'notepad.exe']
print(notepads)  # [<psutil.Process(pid=4416, name='notepad.exe') at 64362512>]

# Просто pid первого попавшегося процесса с именем файла notepad.exe:
pid = next(item for item in psutil.process_iter() if item.name() == 'notepad.exe').pid
# (вызовет исключение StopIteration, если Блокнот не запущен)

print(pid)  # 4416

2. Get a list of process windows with a given pid

You can use the EnumWindows function to get a list of windows in a process.

For example, you need to get all windows of the process with ID 4416:

import win32gui
import win32process

def enum_window_callback(hwnd, pid):
    tid, current_pid = win32process.GetWindowThreadProcessId(hwnd)
    if pid == current_pid and win32gui.IsWindowVisible(hwnd):
        windows.append(hwnd)

# pid = 4416  # pid уже получен на предыдущем этапе
windows = []

win32gui.EnumWindows(enum_window_callback, pid)

# Выводим заголовки всех полученных окон
print([win32gui.GetWindowText(item) for item in windows])

Conclusion:

['Безымянный — Блокнот']

If you also open the page settings setting in Notepad, the list will be as follows:

['Параметры страницы', 'Безымянный — Блокнот']

Post Views: 72

Добавить комментарий