What’s the difference between HWND_TOP and HWND_TOPMOST?


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 issue from a historical perspective in the hopes that looking at it from a different direction may improve understanding.

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: HWND_TOP brings the window to the top of the Z-order.

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 DeferWindowPos (or one of its moral equivalents) with HWND_TOPMOST as the hWndInsertAfter. To make a window non-topmost, use HWND_NOTOPMOST.

As a result of the introduction of "topmost" windows, HWND_TOP now brings the window "as high in the Z-order as possible without violating the rule that topmost windows always appear above non-topmost windows". What does this mean in practice?

  • If a window is topmost, then HWND_TOP puts it at the very top of the Z-order.
  • If a window is not topmost, then HWND_TOP puts it at the top of all non-topmost windows (i.e., just below the lowest topmost window, if any).

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)
  1. not today says:

    "the MSDN discussion"? Don’t you mean "the MSDN description"?

  2. Lewis Jones says:

    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.

  3. PatriotB says:

    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 :)

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

  5. Mike Jones says:

    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.

  6. Andrew Nonymous says:

    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 );

  7. Norman Diamond says:

    ignores the issue of owner and owned

    > windows. I left them out because they would

    > add a layer of complication that distracts

    Understood. But I thought passing a NULL as parent window handle was supposed to result in a non-owned window and should avoid that complication, but it doesn’t. In fact using MFC there were two calls which needed that NULLing and I did both but it didn’t help.

    > If a window is topmost, then HWND_TOP puts

    > it at the very top of the Z-order.

    That begs a "what if" question, to which we already know the answer, but there’s a corollary question. Why wasn’t the "topmost" design vetoed as impossible (with the reason "what if 2 windows tried it")?

  8. carlso says:

    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?

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

  10. carlso says:

    The part you describe does look wrong but I’m going to defer to the window manager team for a final decision

    In the MSDN documentation for SetWindowPos, notice that the paragraph following those "rules" is correct. But those "rules" don’t support what that paragraph is saying. My guess is that nobody works through the double-negative logic that those rules present, and they just read that following paragraph, and say, "yes, that’s correct."

    It’s funny… I’ve pointed this error out to various people at Microsoft over the years and they always say that the documentation is correct. I’m not sure why there’s such a strong reluctance to change it. I was starting to think that somebody way high up at Microsoft originally wrote it back in the day, and nobody wants to correct them ;-)

    Thanks Raymond!

  11. Neil says:

    carlso, you think you have trouble positioning and activating a window? I wish it were as easy to demote a window to be inactive…

  12. "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!

  13. WindFromSky@sina.com says:

    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.

  14. Yaron says:

    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.

  15. 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.)

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

  17. FYI: it’s the fith, and not the fourth :-P

  18. Dan McCarty says:

    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

Comments are closed.