views:

1033

answers:

5

From a couple of preliminary tests it seems that EnumWindows always returns windows in reverse instantiation order, i.e. most recently instantiated window first. Is that a valid observation? If so, is it true across all versions of Windows? And is this a reliable assumption, i.e. is that behaviour documented somewhere?


Context: I'm dealing with a situation where I am triggering a third-party application to open several non-modal windows and I need to send some window messages to those windows once they're open, yet I have no sure-fire way of identifying them as neither their window classes nor their captions will differ and I also do not know their expected coordinates. However, if I could rely on the above behaviour of EnumWindows I could simply use the first handle returned by EnumWindows whose class and caption match my expectation. That still leaves some hypothetical loop holes but I think it will be good enough. Alternative suggestions welcome nevertheless.

+4  A: 

It returns them in Z order. First the top-most window with WS_EX_TOPMOST set, until the bottom-most window with WS_EX_TOPMOST set, then the top-most window without WS_EX_TOPMOST, though to the bottom-most window without WS_EX_TOPMOST. Note that visibility is not a determining factor, so an invisible window that's higher in the Z-order than a visible window will still appear before it.

EDIT:

It's highly unlikely that you could use this as you want, just taking the first return from EnumWindows. Not only is your new window unlikely to be the first return, but you'd have a race condition where other windows could be opened in the meantime. You could, however, keep a list of all known windows for the application, and when you need to find a newly opened window, call EnumWindows and compare the window handles to those in your list. When you find one that has the correct class and caption (you might even check that it belongs to the right process with GetWindowThreadProcessID) that is not in your list, then you've found the new window.

For your purposes, though, you may be even better served by installing a CBT hook and watching for the HCBT_CREATEWND notification. See MSDN help on SetWindowsHookEx() and the CBTProc callback for more information.

Level of certainty about enumeration order:

A number of comments and other answers to this question have mentioned a lack of precise documentation in MSDN about the order in which EnumWindows returns window handles. And indeed, the pages on EnumWindows and the EnumWindowsProc callback are both quite silent on the issue. I offer as evidence the following:

  1. A C++ Q&A article in MSDN magazine does state specifically:

    EnumWindows enumerates the windows in top-down Z-order

  2. The page on EnumChildWindows alludes to the order in the remarks section:

    A child window that is moved or repositioned in the Z order during the enumeration process will be properly enumerated.

    This implies that the order is Z-order dependent. And since, in the description of the hWndParent parameter, it says this:

    If this parameter is NULL, this function is equivalent to EnumWindows.

    one can assume that the same logic and ordering applies to EnumWindows.

  3. This is the observable behavior of this function, which makes it a breaking change to alter it. In general, Microsoft has been very good about not making breaking changes to observable behavior. That's not a guarantee, but it's a pretty safe bet. You're more likely to find that in the next version the function you're using has been deprecated—and replaced with yet another "Ex" version—than to find that its observable behavior has changed.

Of course, this is all very academic at this point, since EnumWindows is probably not the best solution for the OP's problem—at the very least EnumThreadWindows would probably be a better fit—but I thought it was worth mentioning for other people who might come across this post.

P Daddy
That sounds reasonable. Do you have a link to the documentation of this behaviour somewhere? I would have expected this in the `EnumWindows` docs...
Oliver Giesen
Note that I wrote "the first handle returned by EnumWindows *whose class and caption match my expectation*". I am aware that other windows that match the same criteria might be opened in the meantime but in this case I am 95% confident that this is rather hypothetical.
Oliver Giesen
the problem with keeping a list of known handles is that (so far) I have no way of telling when a window gets closed to remove it from the list again. this might again be hypothetical, but how would I know that the (potentially freed) handle hasn't been reassigned to a new window in the meantime?
Oliver Giesen
I would imagine that the likelihood of the same window handle being reassigned to a new window in your same process would be negligible. Using a CBT hook instead of EnumWindows would remove this concern altogether, though.
P Daddy
"Microsoft has been very good about not making breaking changes to observable behavior." - MS has been good about spending time analyzing (some most popular) apps and introducing various compat layers, so that these broken apps still see the "observable" behavior, and continue working.
liggett78
Brilliant! Thanks for the links to the CBT hook thingy! That'll surely be useful. Though it seems that I would still have the same problem of not being able to identify the windows I triggered, wouldn't I?
Oliver Giesen
You would be notified when a new window was opened. Whether or not you'd be able to tell if it was opened because of your trigger, I couldn't say.
P Daddy
+1  A: 

The order is not specified in the API (MSDN link) so it's not guaranteed to be anything in particular - if there was a guarantee it would be explicitly specified in the API. What happens, for example, if a window is created halfway through the enumeration - does it get included in the enumeration? This allows the window manager the freedom to change its implementation should it become more efficent to do so.

However, there is a unique value that can be used to differentiate between windows - the window handle itself. In your EnumWindowProc method, save the window handle for each matching window - you need it anyway to send messages to the window.

Skizz

Skizz
i need not only be able to differentiate between them. i need to know which is the one that I just triggered into life....
Oliver Giesen
A: 

If you control both processes you can send from the first one a SendMessage with "HWND_BROADCAST" as first parameter.

Then the other program when receive the msg, can do a SendMessage to his child windows.

João Augusto
sorry, I do not control the program that creates the window, at least not in the sense that I can make it send messages.
Oliver Giesen
A: 

If the documentation does not say anything about the order of enumeration, I would STRONGLY suggest you stay away from any assumptions. A couple of posts on Raymond Chen's blog (blogs.msdn.com/oldnewthing) would reveal you how many apps are there that rely on all this undocumented stuff/observation, and something goes terribly wrong when a new version of Windows comes out (unless MS developers introduce yet another shim for yet another app that behaves badly).

As for your purpose, there are several functions, like GetWindowThreadProcessID, GetParent, EnumThreadWindows and EnumWindows that could help you achieve the task.

liggett78
A: 

Avoid R. Chen blog : it's plenty of bullshit. Always read MSDN instead and simply see the source code of EnumWindows()