Date: | November 21, 2005 / year-entry #356 |
Tags: | history |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20051121-10/?p=33263 |
Comments: | 19 |
Summary: | The special values HWND_TOP and HWND_TOPMOST have similar names but do completely different things when passed as the hWndInsertAfter parameter to the DeferWindowPos function (or its moral equivalents such as SetWindowPos). As a backgrounder, you should start off by reading the MSDN discussion, which is perfectly accurate as far as it goes. Here, I'll discuss... |
The special values Sibling windows are maintained in an order called the Z-order. (For the purpose of this discussion, top-level windows are also treated as siblings. In fact, it is the Z-order of top-level windows that most people think of when they say "Z-order".) The Z-order should be visualized as a vertical stack, with windows "above" or "below" siblings. Before Windows 3.0, the behavior was simple: Windows 3.0 added the concept of "topmost" windows. These are top-level windows that always remain "above" non-topmost windows. To make a window topmost, call As a result of the introduction of "topmost" windows,
Note: The above discussion completely ignores the issue of owner and owned windows. I left them out because they would add a layer of complication that distracts from the main topic. |
Comments (19)
Comments are closed. |
"the MSDN discussion"? Don’t you mean "the MSDN description"?
What I just to know is why on my 2k box, VS2003 will occasionally get "on top" of my taskbar, even though the taskbar is set to "Always Be On Top".
I gave up the auto-hide, cause I had to keep minimizing my VS windows to get to the start menu.
A similar problem to Lewis’s is when taskbar tooltips (e.g. the date) appear below the taskbar (behavior observed on XP). The problem comes out of nowhere and usually fixes itself after some time :)
I am using following interpretation:
Non-child windows in Windows live in two layers – non-topmost layer and topmost layer.
Placing "topmost" window on top places it on very top of everything. In the same way
placing "non-topmost" window on top places it on top of non-topmost layer. Non-topmost layer is by definition is under of topmost layer.
I don’t know why HWND_TOP never works for me.
I tried:
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
and
BringWindowToTop(hwnd);
To no avail.
I wrote some MFC(yechh) code that did it, a long time ago. IIRC the call to SetWindowPos was there because ModifyStyleEx didn’t check for toggling WS_EX_TOPMOST and do the right SetWindowPos call.
CAboutDlg about(this);
about.DoModal();
ModifyStyleEx (
// styles to remove
about.m_fTopMost ? 0 : WS_EX_TOPMOST,
// styles to add
about.m_fTopMost ? WS_EX_TOPMOST : 0,
// don’t call SetWindowPos
0 );
// CWnd ModifyStyleEx doesn’t do this call properly
SetWindowPos (
// new Z order
about.m_fTopMost ? &wndTopMost : &wndNoTopMost,
// new coords n/a
0,0,
// new size n/a
0,0,
// don’t use coords or size
SWP_NOMOVE | SWP_NOSIZE );
AfxGetApp()->WriteProfileInt ( "", "OnTop", about.m_fTopMost );
Raymond,
I’m sorry, but I have to take issue with your statement that the documentation for SetWindowPos/DeferWindowPos is "perfectly accurate." It’s been wrong for quite some time.
I’m referring to this section:
If neither the SWP_NOACTIVATE nor SWP_NOZORDER flag is specified (that is, when the application requests that a window be simultaneously activated and its position in the Z order changed), the value specified in hWndInsertAfter is used only in the following circumstances:
• Neither the HWND_TOPMOST nor HWND_NOTOPMOST flag is specified in hWndInsertAfter.
• The window identified by hWnd is not the active window.
How can this possibly be? Let’s try an example:
Say I have three top-level windows in my application that are in the following Z-order (from top-to-bottom): A, B, C. Window A is currently the active window.
According to the above rules, I can take window C (which agrees with rule 2 in that it is not an active window), and I can move window C underneath A (the current active window) and in the process make C the active window. So, given SetWindowPos(C, A, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE), which is in compliance with the above rules, I should end up with A, C, B, where C is the active window.
Go ahead and try it. IT DOES NOT WORK. What happens instead is that the hWndInsertAfter parameter is ignored and window C is brought to the top. (Hmmm… didn’t those rules say that is to be used in those circumstances?)
This part of the documentation has been incorrect for as long as I can remember. When you promote an inactive window to become new active window, you can only bring it to the top or topmost. Windows will not let you put it anywhere else.
The corrected rules should state:
If neither the SWP_NOACTIVATE nor SWP_NOZORDER flag is specified, the value specified in hWndInsertAfter is used only in the following circumstances:
• The HWND_TOPMOST or HWND_NOTOPMOST flag is specified in hWndInsertAfter.
– or –
• The window identified by hWnd is the active window.
Note that these corrected rules imply that if the window is already the active window (and you would like it to remain the active window), SetWindowPos() allows you to reposition it anywhere in the Z-order by omitting SWP_NOACTIVATE and SWP_NOZORDER.
In my example, calling SetWindowPos(A, B, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) works fine by placing the active window A under the inactive window B (and keeps window A as the active window).
Any chance of the docs getting corrected after all of these years?
My remark on the perfect accuracy was with respect to the discussion of the what HWND_TOP and HWND_TOPMOST mean, not to the rest of SetWindowPos.
The part you describe does look wrong but I’m going to defer to the window manager team for a final decision.
carlso, you think you have trouble positioning and activating a window? I wish it were as easy to demote a window to be inactive…
"VS2003 will occasionally get "on top" of my taskbar"
VS.NET does a lot of spooky things with windows…
Try this:
Be sure to have window animations enabled, start a maximized VS.NET (2003) and click the "Show Desktop"-icon in the Quick launch bar. Now click the taskbar window/button for VS.NET to restore it to its maximized position… during the animation you should see *another* VS.NET window beeing animated before the "real" window is maximized…
I truly, really hate the way VS.NET does something strange with its windows…it breaks XMouse!
The wired thing is :
when you have 2 TOPMOST windows in your app,
the windows will both lost TOPMOST flag,
and become NON-TOPMOST windows.
I wish there was a way to have two windows within your application be ontop of all other non-top windows in other applications and yet the top windows in your application maintain a z-order even when clicked.
A case in point, a media player that should "stay on top" containing a Play List element in a non-child window that should always be on top of the media player window, even when the media player window is clicked.
Yaron: Your wish was granted back in 1993. See the fourth thing every Win32 programmer should know. (I feel like Jensen Harris – people asking for features that already exist.)
I think what Yaron wants is a media player’s main window that is always on top of other apps, and the media player’s playlist is always on top of the main window.
i.e. he wants to have top most within an app and between apps.
FYI: it’s the fith, and not the fourth :-P
I know I’m catching this topic pretty late, but I’d just like to append this comment for the record (for other CE developers that come across this blog entry from a HWND_TOPMOST Google search).
Setting a topmost window in CE if you’re using the MFC framework is difficult to say the least. See this newsgroup post for more info: http://groups.google.com/group/microsoft.public.windowsce.platbuilder/msg/8c38be02059bb286?dmode=source
PingBack from http://bobobobo.wordpress.com/2008/02/09/windows-function-references/