8

The scenario is that I have a list of window handles to top level windows and I want to shift them around so they are arranged in the z-order of my choosing. I started off by iterating the list (with the window I want to end up on top last), calling SetForegroundWindow on each one. This seemed to work some of the time but not always, improving a little when I paused slightly in between each call.

Is there a better way to do this?


Edit:

It looks like the BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos route is the way to go. However, I can't seem to get it to work with more than one window at a time. When I limit the window list to a single window, it works correctly. When the list has multiple windows, it only seems to get one of them. Here is pseudo code of what I'm doing:

HWND[] windows;
HWND lastWindowHandle = 0;
HDWP positionStructure = BeginDeferWindowPos(windows.length);

for (int i = 0; i < windows.length; i++)
{
    positionStructure = DeferWindowPos(positionStructure, windows[i], 
        lastWindowHandle, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}

EndDeferWindowPos(positionStructure);

I'm sure it's something small/obvious I'm missing here but I'm just not seeing it.

2 Answers 2

13

There is a special set of api's for setting window positions for multiple windows: BeginDeferWindowPos + DeferWindowPos + EndDeferWindowPos (SetWindowPos in a loop will also work of course, but it might have more flicker)

Sign up to request clarification or add additional context in comments.

3 Comments

+1: this is definitely the better route, especially if you're dealing with a large number of windows.
Thanks for the tip, this does seem like the right approach to take. See my edit of the question for the problem I'm running into with it.
@Greg Shackles: You probably want SWP_NOACTIVATE, and maybe SWP_ASYNCWINDOWPOS
5

You can use SetWindowPos to order your top-level windows.

// Hypothetical function to get an array of handles to top-level windows
// sorted with the window that's supposed to be topmost at the end of array.
HWND* windows = GetTopLevelWindowsInOrder();
int numWindows = GetTopLevelWindowCount();

for(int i = 0; i < numWindows; ++i)
{
    ::SetWindowPos(windows[i], HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}

4 Comments

Good call, I hadn't noticed that SetWindowPos also had a parameter for z-order. Do you know if this will suffer from the same timing problems I mentioned with SetForegroundWindow?
Try it and see if it performs better than SetForegroundWindow() :-)
I plan on it, I just can't do that until later. Will report back later with the results :)
SetForegoundWindow does more than change the Z-order. It "activates" the window, which has an effect on things like focus, which requires messages to go flying through the system, which is probably why the timing seemed critical. Use SetWindowPos as In Silico recommends, at least for the first n-1 windows. Depending on what you're trying to achieve, you may want to do SetWindowPos on the final window.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.