Do you want to traverse all visible desktop windows, but with respect to z-order? Well, you might be able to do this via EnumDesktopWindows
, but I'm not too sure if this is enumerated in a specified z-order. Plus if you don't want to use a callback, maybe this approach isn't for you. Instead, the windows api has some functions built into it to iterate over windows with respect to z-order. However, there's not many examples of how to do this online, which has inspired the creation of this gist.
Getting the top-most window is really easy. First, you can just do something like:
//Window handle of the desktop
HWND desktopWindow = GetDesktopWindow();
//Get the top-most window in the desktop
HWND topMostWindow = GetTopWindow(desktopWindow);
Using the top-most window as a reference point, you can easily find the window which is the lowest z-order by using GetWindow(hwnd, GW_HWNDLAST)
. The GW_HWNDLAST
parameter indicates that we want the window whose z-index is the lowest. Similarly, we could specify GW_HWNDFIRST
to get the window whose z-index is the highest. So for example, you could use:
//Get the window with the lowest z-index, with regards to the top-most window
HWND window = GetWindow(window, GW_HWNDLAST);
GetWindow
is really useful because it allows you to go to the next/previous window in the z-order by specifying either GW_HWNDNEXT
(for the next window with a lower z-index) or GW_HWNDLAST
(for the next window with a higher z-index). Iteration is achieved by saving the result of GetWindow
into a variable, and then using that result to get the next window relative to the result. Here's an illustration of what I mean:
//Get the top-most window
HWND window = GetTopWindow(GetDesktopWindow());
//Find the window below this one, iteratively
window = GetWindow(window, GW_HWNDNEXT); // Maybe this is the window with z-index 5
window = GetWindow(window, GW_HWNDNEXT); // z-index 4
window = GetWindow(window, GW_HWNDNEXT); // z-index 3
window = GetWindow(window, GW_HWNDNEXT); // z-index 2
//etc..
So you can see how easy this would be to put into a loop, and just check whilst window
is not null, e.g. while(window = GetWindow(window, GW_HWNDNEXT)) { }
Putting together everything we've covered, this is really easy:
//Find the top-most window.
HWND window = GetTopWindow(GetDesktopWindow());
//Run from the highest z-order to the lowest by using GW_HWNDNEXT. We're using a do-while
//here because we don't want to skip the top-most window in this loop.
//..
do
{
//Your code here..
}
while (window = GetWindow(window, GW_HWNDNEXT));
For example, if you wanted to print out the titles of all 'visible' windows, here's some code to do that:
do
{
//Not visible? skip
if(!IsWindowVisible(window))
continue;
//Get the title of the window
char titleString[64];
GetWindowTextA(window, titleString, 64);
//Print it out
printf("%s\r\n", titleString, 64);
}
while (window = GetWindow(window, GW_HWNDNEXT));
This is a bit trickier, but still very much achievable. The only difference we really have to make is to replace GW_HWNDFIRST
with GW_HWNDLAST
, so that we start from the lowest z-index in the loop. We also need to use GW_HWNDPREV
instead of GW_HWNDNEXT
.
GW_HWNDPREV
is like GW_HWNDNEXT
, but instead of going to a lower z-value (top -> bottom-most), it goes to higher z-values (bottom -> top-most). It's basically just used to iterate over the windows in a reverse order. So, by modifying our code a bit, we can use something like:
//Find the top-most window. We need the Z-order to be
//relative to this
HWND window = GetTopWindow(GetDesktopWindow());
//Then, find the window with the lowest Z-order value (GW_HWNDLAST not GW_HWNDFIRST)
window = GetWindow(window, GW_HWNDLAST);
do
{
//Your code here
}
while (window = GetWindow(window, GW_HWNDPREV));
Both types of iteration (top -> bottom, bottom -> top) are listed as separate files in this gist.
Thank you so much