Каждое Win окно может иметь 0 или более дочерних окон, и каждое из этих дочерних окон также может иметь 0 или более собственных дочерних окон, ии так далее. Таким образом, у каждого окна может быть целое дерево детей.
В окнах больше, чем кажется на первый взгляд.Пользователь может взглянуть на одно (верхнее) окно и представить, что его дерево выглядит определенным образом, хотя на самом деле это дерево может выглядеть совершенно иначе (более сложным), поскольку могут быть некоторые окна, которые не видны.
При отправке сообщения в окно и в ожидании определенного поведения сообщение должно быть отправлено в точное окно (или одному из его предков, которые сконструированы таким образом, чтобы пересылать его)в противном случае сообщение будет просто проигнорировано (так как окно неправильно не обрабатывает такого рода сообщения).
В нашем случае это означает, что сообщение WM_KEYDOWN (или WM_CHAR ) должно быть отправлено:
- ( Редактировать *)1024 *) окно, которое содержит текст для Блокнот
- Окно ( TreeView ), которое содержит список устройств для Диспетчер устройств
Вы используете [ActiveState.Docs]: win32gui.GetWindow , который включает [MS.Docs]: функция GetWindow , которая сообщает (для * 1041)* GW_CHILD ):
Полученный дескриптор идентифицирует дочернее окно вверху Z-порядка, если указанное окно является родительским окном;в противном случае извлекаемый дескриптор равен NULL .Функция проверяет только дочерние окна указанного окна.Он не проверяет дочерние окна.
По совпадению , для Блокнот , отправляющий сообщение своему 1 st дочернему элементу, потому что этоchild оказался тем самым окном Edit , о котором я упоминал выше (кроме этого дочернего элемента, Notepad есть только еще одно - StatusBar , и это все, ни одногоиз этих окон есть собственные дочерние элементы).
Для Диспетчер устройств с другой стороны, все не так просто.Как видите, его структура более сложная (например, окно ToolBar видно).В соответствии с рекомендациями, для работы с окнами я использую [MS.Docs]: функцию EnumChildWindows .
code.py :
#!/usr/bin/env python3
import sys
import pywintypes
import win32gui
import win32con
def enum_child_proc(wnd, param):
print(" Handling child 0x{:08X} - [{:}] - 0x{:08X}".format(wnd, win32gui.GetWindowText(wnd), win32gui.GetParent(wnd)))
if param[0] >= 0:
if param[1] == param[0]:
win32gui.SendMessage(wnd, win32con.WM_KEYDOWN, win32con.VK_DOWN, 0)
return 0
param[1] += 1
def handle_window(wnd, child_index=-1):
print("Handling 0x{:08X} - [{:}]".format(wnd, win32gui.GetWindowText(wnd)))
cur_child = 0
param = [child_index, cur_child]
try:
win32gui.EnumChildWindows(wnd, enum_child_proc, param)
except pywintypes.error as e:
if child_index < 0 or e.args[0]:
raise e
def main():
np_wnd = 0x01DB1EE2 # Notepad handle
dm_wnd = 0x000E2042 # Device Manager handle
handle_window(np_wnd, child_index=0)
handle_window(dm_wnd, child_index=6)
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
Примечания :
- Я жестко закодировал 2 дескриптора окна ( np_wnd , dm_wnd ).Очевидно, что они не будут действительными (они больше не действительны на моей машине, так как я закрыл окна), и их значения необходимо изменить
- , чтобы найти дескриптор окна (и некоторые егодети) Я использую Spy ++ ( [MS.Docs]: Как: запустить Spy ++ ), который является частью VStudio , но я уверенЕсть множество других подобных приложений
Вывод :
e:\Work\Dev\StackOverflow\q053778227>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32
Handling 0x01DB1EE2 - [Untitled - Notepad]
Handling child 0x01811FA4 - [] - 0x01DB1EE2
Handling 0x000E2042 - [Device Manager]
Handling child 0x00621A5A - [] - 0x000E2042
Handling child 0x01991F44 - [Device Manager] - 0x00621A5A
Handling child 0x01691F3E - [] - 0x01991F44
Handling child 0x000C20B0 - [] - 0x01691F3E
Handling child 0x004D2000 - [] - 0x000C20B0
Handling child 0x004420CA - [] - 0x004D2000
Handling child 0x01191F20 - [] - 0x004420CA
Как видно из вывода, TreeViewОкно является 7 th child (из 7 th child :)) окна Device Manager , означающее, что есть 6 промежуточных (и невидимых) окон между ними (которые игнорируют это сообщение).
Хотя код справился с этими окнами, нет действующего рецепта, который работаетдля любого окна (или, если есть, я не знаю об этом).Я должен упомянуть, что я попытался определить дочернее окно интереса в дереве, взглянув на его:
- Имя
- Класс
- Стиль ( MS документация в этой области довольно плохая)
- Положение (по отношению к своему родителю)
- SendMessage код возврата
но я не смог найти ничего, что отличало бы его от других окон.Единственное, что я заметил, это то, что для Notepad желаемым окном является перечисляемый дочерний элемент 1 st , а для Диспетчер устройств это 7 st один, поэтому я сделал фильтрацию на основе этого факта ( child_index ), но я считаю его совершенно ненадежным .
В качестве альтернативы, может бытьнет никакой фильтрации, и сообщение отправляется всем дочерним окнам в дереве, но это может иметь нежелательные последствия, так как могут быть другие окна, которые отвечают на это сообщение.Например, Диспетчер устройств * Дерево 1159 * состоит из ~ 30 дочерних окон.
В заключение я также хотел бы отметить, что некоторые окна (веб-браузеры, такие как )Chrome ), имеют свои собственные системы Windows, поэтому ничего из этого не будет работать.