tags:

views:

69

answers:

2

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 pseudocode 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.

+3  A: 

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);
}
In silico
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?
Greg Shackles
Try it and see if it performs better than `SetForegroundWindow()` :-)
In silico
I plan on it, I just can't do that until later. Will report back later with the results :)
Greg Shackles
`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.
Adrian McCarthy
+4  A: 

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)

Anders
+1: this is definitely the better route, especially if you're dealing with a large number of windows.
Jerry Coffin
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
@Greg Shackles: You probably want SWP_NOACTIVATE, and maybe SWP_ASYNCWINDOWPOS
Anders
SWP_NOACTIVATE did the trick, thanks!
Greg Shackles