I've wrote A code that gets the HWND from any program I want. So thats how I got the hwnd if your asking.
The following code should bring up device manger and send the down arrow to the program.
But it doenst. It does bring up the device manager but it doesnt send the arrow down key to the program, at least nothing happens.
If I change the hwndMain number with the hwnd code of a notepad window, the code does work and sends the arrow down key
import win32api
import win32con
import win32gui
import time
hwndMain = 133082
hwndChild = win32gui.GetWindow(hwndMain, win32con.GW_CHILD)
win32gui.SetForegroundWindow(hwndMain)
time.sleep(1)
win32api.SendMessage(hwndChild, win32con.WM_CHAR, 0x28, 0)
EDIT
I've tried
win32api.SendMessage(hwndChild, win32con.WM_CHAR, win32con.WM_KEYDOWN, 0)
Instead of
win32api.SendMessage(hwndChild, win32con.WM_CHAR, 0x28, 0)
But that doesnt work either.
I'm on python 2.7
Every Win window can have 0 or more child windows, and each of those child windows can also have 0 or more children of their own, and so on... So each window may have a whole tree of children.
There is more about windows, than meets the eye. The user might look at one (top) window and imagine that its tree looks in a certain way, when in fact that tree could look totally different (more complex), as there might be some windows that are not visible.
When sending the message to a window and expecting a certain behavior to occur, the message must be sent to the exact window (or to one of its ancestors which are designed in such a way to forward it), otherwise the message will simply be ignored (as the wrong window doesn't handle that kind of message).
In our case, it means that the WM_KEYDOWN (or WM_CHAR) message should be sent to:
You are using [ActiveState.Docs]: win32gui.GetWindow, which wraps [MS.Docs]: GetWindow function which states (for GW_CHILD):
The retrieved handle identifies the child window at the top of the Z order, if the specified window is a parent window; otherwise, the retrieved handle is NULL. The function examines only child windows of the specified window. It does not examine descendant windows.
Coincidentally, for Notepad sending the message to its 1st child works, because that child turned to be the very Edit window that I mentioned above (besides that child, Notepad only has another one which is the StatusBar, and that's it, none of these windows has any children of their own).
For Device Manager on the other hand things are not so simple. As you can see, its structure is more complex (e.g. ToolBar window is visible). As recommended, In order to work with windows, I'm using [MS.Docs]: EnumChildWindows function.
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()
Notes:
Output:
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
As seen from the output, the TreeView window is the 7th child (of the 7th child :) ) of the Device Manager window meaning that there are 6 intermediary (and invisible) windows between them (which ignore that message).
Although the code did the trick for the windows in question, there's no current recipe that works for any window (or if there is, I am not aware of it). I must mention that I've tried to determine the child window of interest in the tree by looking at its:
but I couldn't find anything that would differentiate it from other windows. The only thing that I noticed is that for Notepad, the desired window is the 1st child enumerated, while for Device Manager it's the 7st one, so I did the filtering based on this fact (child_index), but I consider it totally unreliable.
As an alternative, there could be no filtering at all, and the message sent to all the child windows in the tree, but this might have unwanted effects, as there could be other windows that respond to that message. For example Device Manager tree consists of ~30 child windows.
At the end, I would also like to mention that some windows (web browsers like Chrome), have their own windows systems, so none of this will work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With