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;
Handle the WM_WINDOWPOSCHANGED mesage:
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).
void CChildFrame::OnWindowPosChanged(WINDOWPOS* lpwndpos)
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);
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.
m_TopWindow = NULL;
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)
if( !CMDIChildWnd::PreCreateWindow(cs) )
m_TopWindow = m_hWnd;
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.