Click here to Skip to main content
Click here to Skip to main content

How to Keep an MDI Window Always on Top

, 26 Jan 2009
Rate this:
Please Sign up or sign in to vote.
Making a single MDI child window stay always on top of the other MDI child windows.

Introduction

It is not possible to set a style (like WS_EX_TOPMOST) on an MDI child window so it stays on top of other MDI child windows. Instead, we have to mark a window to be the top most, and then manually bring that window to the top when another window is activated.

Microsoft has provided a nice article called How To Keep an MDI Window Always on Top (Q108315). But the solution(s) in the article are not implemented using the MFC framework.

Using the code

The sample code included in this article is just a standard Document / View MFC application created with the AppWizard. It has been modified so the newest View gets the status of being the top most. When changing to a different View, the View with the top most status will remain in front.

Modifications have only been made to CChildFrame, and they are very simple.

Implement a global variable to remember the MDI window with the top-most status:

HWND CChildFrame::m_TopWindow = NULL; // There can only be one top-most window

Handle the WM_WINDOWPOSCHANGED mesage:

The WM_WINDOWPOSCHANGED message is sent to a window, when it changes size, position, or z-order. It is only sent to the window being activated (not to the window losing focus).

BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
 //{{AFX_MSG_MAP(CChildFrame)
 ON_WM_WINDOWPOSCHANGED()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CChildFrame::OnWindowPosChanged(WINDOWPOS* lpwndpos)
{
 // This message-handler is sent to the window
 // being activated (Changing position, size or z-order)
 // Check if another window has the status of being top-most, instead of this one
 if (m_TopWindow!=NULL && m_TopWindow!=m_hWnd && ::IsWindow(m_TopWindow))
 {
  ::SetWindowPos(m_TopWindow, HWND_TOP, 0, 0, 0, 0, 
                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
 }
 CMDIChildWnd::OnWindowPosChanged(lpwndpos);
}

Reset the global variable when the top-most window closes:

When the top-most window is closed, we must reset the global variable so other windows will not try to bring it up front.

BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
 //{{AFX_MSG_MAP(CChildFrame)
 ON_WM_CLOSE()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CChildFrame::OnClose() 
{
 // Check if the top-most window is closing
 if (m_hWnd==m_TopWindow)
  m_TopWindow = NULL;
 CMDIChildWnd::OnClose();
}

Finally, we need to mark a window as being the top-most:

In this sample application, the newly opened window will get the status of being the top-most, and other existing windows will bring it to the front when they are activated.

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
 // TODO: Modify the Window class or styles here by modifying
 //  the CREATESTRUCT cs
 if( !CMDIChildWnd::PreCreateWindow(cs) )
     return FALSE;
 // The newly opened window will get the status of being the top-most
 m_TopWindow = m_hWnd;
 return TRUE;
}

Point of interest

There seems to be an unofficial way to make this happen with use of of the ::SetParent() function, which is used by many Visual Basic programs. Microsoft doesn't recommend doing this, as it creates a lot of unwanted sideeffects. PRB: SetParent Does Not Change Standard Forms into Child Windows (Q253814)

Instead of changing an MDI child window to be always on top, then one could also consider to make a modeless CDialog. Modeless dialogs can move out of the MDI mainframe, so if having a dual monitor solution, then one can place the dialog on the other screen.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Rolf Kristensen
Software Developer
Denmark Denmark
No Biography provided

Comments and Discussions

 
GeneralExcuse me Pinmembersk8er_boy28719-Jan-09 1:58 
GeneralRe: Excuse me PinmemberSnakefoot19-Jan-09 2:17 
GeneralRe: Excuse me Pinmembersk8er_boy28719-Jan-09 2:48 
GeneralRe: Excuse me PinmemberSnakefoot19-Jan-09 2:52 
GeneralRe: Excuse me Pinmembersk8er_boy28719-Jan-09 2:56 
GeneralRe: Excuse me PinmemberSnakefoot19-Jan-09 2:58 
GeneralRe: Excuse me Pinmembersk8er_boy28719-Jan-09 2:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 27 Jan 2009
Article Copyright 2009 by Rolf Kristensen
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid