Sign in to follow this  
XTAL256

How to enumerate all windows on the desktop

Recommended Posts

XTAL256    106
I sometimes use tools like Spy++ or Winspector Spy to get info on a particular window. But, as good as they are, i am a bit disappointed at the lack of functionality they have. So i decided to write my own. I have been reading up on the Enum*Windows functions which enumerate windows, but none of them seem to get all windows. I am not sure what the best way is to get every single window on the system, even hidden ones. EnumWindows enumerates all top-level windows but not children. EnumChildWindows can get all children of the desktop window (using GetDesktopWindow) but not hidden ones. I thought perhaps i could use EnumWindows and then EnumChildWindows on each top-level window. That seemed to give me a lot of duplicates but no hidden ones. Using EnumDesktopWindows in place of EnumWindows gave me the same results. I shouldn't use GetWindow since it is not as safe (the parent window may be destroyed as i am calling this function to get one of it's children). So that's not an option. I would really like to know how programs like Spy++ and Winspector Spy do it. Winspector appears to only show visible windows in the "Window" tab, i can see that Process Explorer's window disappears from the list when i minimise it. But yet i can see it when i look at the "Process" tab. So does that mean that it uses two different algorithms for finding windows? If so, is that the only way, or is there a way to definitively get all windows?

Share this post


Link to post
Share on other sites
XTAL256    106
Ok, sorry, it turns out i was not using the right method to determine if a window is visible. I should have been using IsWindowVisible.

Regardless of that, i would still like to know what the best way is.
EnumChildWindows using GetDesktopWindow as the parent returns more windows that enumerating all children of EnumWindows or EnumDesktopWindows. What extra windows would it be picking up?

Share this post


Link to post
Share on other sites
jwezorek    2663
I did this a long time ago when I was working on an accessibility app for disabled users.

I think that what eventually worked was first using CreateToolhelp32Snapshot to enumerate all the running processes and threads associated with each process and then calling EnumThreadWindows on each thread to get the top level windows associated with each thread, and finally calling EnumChildWindows on each top-level window.

Here's someone talking about how to use CreateToolhelp32Snapshot.

Share this post


Link to post
Share on other sites
XTAL256    106
Quote:
I think that what eventually worked was first using CreateToolhelp32Snapshot to enumerate all the running processes and threads associated with each process and then calling EnumThreadWindows on each thread to get the top level windows associated with each thread

Yes, that was one of the other methods i read about (although i haven't tried it yet). And i imagine that's what Winspector uses for it's "Process" tab.

But you say that you then also use EnumChildWindows on each top-level window. So this is just an added measure to make sure you don't miss any windows? Is there any case where this would pick up a window that was missed by enumerating all threads?

See, i am thinking of having two trees like Winspector, one which shows windows and their relationship as children of the desktop and the other which shows all processes (which have windows) and the windows they own.
But i am intending on keeping a single flat array of all windows so that i can easily search it if the user wants to find a window. Then i will generate the trees from this array. (I will store a pointer to a window's parent and children so i can build the tree).

Share this post


Link to post
Share on other sites
mattd    1078
You could take a look at how WinSpy does it (or maybe it provides the extra functionality you were going to add? :]). It's a free tool based off of Spy++ (and nicer too, IMO). You can download its source and the application at that above link.

Share this post


Link to post
Share on other sites
jwezorek    2663
Quote:
Original post by XTAL256
But you say that you then also use EnumChildWindows on each top-level window. So this is just an added measure to make sure you don't miss any windows? Is there any case where this would pick up a window that was missed by enumerating all threads?


Whether to use EnumChildWindows or not depends on what you want. I don't know what kind of app you're writing so I can't tell you.

If you are talking about just enumerating windows that have a title bar and so forth, overlapped windows, then you can probably get away with not calling EnumChildWindows.

You would use EnumChildWindows if you wanted to enumerate all of the Win32 controls like buttons, tab ctrls, etc. that a window contains. If you don't need that level of detail then don't do it.

One other detail is there are cases when a window is what is called "owned" but is not a child. It's a window that has a non-null parent but doesn't have it's WS_CHILD bit set. I'm not sure if you would need to call EnumChildWindows to get owned windows or not.

Share this post


Link to post
Share on other sites
XTAL256    106
Quote:
Original post by jwezorek
Whether to use EnumChildWindows or not depends on what you want. I don't know what kind of app you're writing so I can't tell you.

That was the first thing i mentioned. I said i was writing an app similar to Spy++ and that i needed to get every window on the system.
But i guess the terminology Windows uses is a bit ambiguous. When i said "windows", i meant all controls. So yes, i do want to get buttons, tab ctrls, ect as well as windows that have a title bar.

Quote:
One other detail is there are cases when a window is what is called "owned" but is not a child. It's a window that has a non-null parent but doesn't have it's WS_CHILD bit set. I'm not sure if you would need to call EnumChildWindows to get owned windows or not.

Hmm, i see. MSDN doesn't say whether EnumChildWindows gets those such windows, i guess i'll just have to do some testing to find out.

I think i go with enumerating all processes and threads using the code in the link jwezorek provided, then getting all windows of each thread using EnumThreadWindows, then getting their children with EnumChildWindows. It's a long-winded approach but it should find all windows as no window would ever be created without an owning thread. Anyway, i am going to show the process and thread for each window like Spy++ et. al. do, so i will get them during the enumeration process.

Share this post


Link to post
Share on other sites
jwezorek    2663
Quote:
Original post by XTAL256
But i guess the terminology Windows uses is a bit ambiguous. When i said "windows", i meant all controls.

Yeah, the trouble with "Everything is a window" is that when you want to talk about what are commonly thought of as windows there isn't a good word. Non-child windows is what they are but that just sounds stupid. ... You can't call them parent windows because they might not have any children. Anyway, whatever...

Quote:
Original post by XTAL256
Hmm, i see. MSDN doesn't say whether EnumChildWindows gets those such windows, i guess i'll just have to do some testing to find out.

I don't think owned windows will be a problem. They will probably show up like any other non-child window.

Share this post


Link to post
Share on other sites
Codeka    1239
Quote:
Original post by jwezorek
Quote:
Original post by XTAL256
But i guess the terminology Windows uses is a bit ambiguous. When i said "windows", i meant all controls.

Yeah, the trouble with "Everything is a window" is that when you want to talk about what are commonly thought of as windows there isn't a good word. Non-child windows is what they are but that just sounds stupid. ... You can't call them parent windows because they might not have any children. Anyway, whatever...
The usual word is "top-level window".

I'm pretty sure a simple EnumWindows will provide the same information as enumerating processes then windows (at least in the absence of high-integrity windows - such as windows running under an administrator account, etc - but then there's not much you can about those anyway).

Share this post


Link to post
Share on other sites
XTAL256    106
Quote:
Original post by jwezorek
Quote:
Original post by XTAL256
But i guess the terminology Windows uses is a bit ambiguous. When i said "windows", i meant all controls.

Yeah, the trouble with "Everything is a window" is that when you want to talk about what are commonly thought of as windows there isn't a good word. Non-child windows is what they are but that just sounds stupid. ... You can't call them parent windows because they might not have any children. Anyway, whatever...

Actually, i believe anything that is not a top-level, title-bar kind of window is called a "control". Although i don't like that name much either.
But things like Spy++ don't make any distinction between "windows" and "controls" since they are all of type HWND.

As for what method to use, i did some testing and found that the per-thread method and the desktop-children methods give me the same number of windows. And enumerating desktop children is certainly faster and easier than the thread method, so i guess i'll use that.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this