Custom MDI “More Windows” Dialog

Few words about MDI Window menu

In an MDI aplication, the Window menu contains items which alow selecting/activating one of the open documents. If the number of open documents exceeds 9, then Window menu is appended with a “More Windows…” item.

MDI Window Menu

 

If the user selects “More Windows…”, a “Select Window” dialog appears, in which all open documents are listed. Now, the user can select one to be activated.

Select Window Dialog

Let’s say we have to customize this dialog for adding more info (e.g. full path of documents) and other functions beside activating (e.g. close a document). This article gives the solution.

Behind the scenes

Should be not any problem if we know the “More Windows…” menu item ID: just have to handle the command and show our own dialog instead of the default one.Let’s begin digging!
In a first attempt, if have a look in AFXRES.H which defines MFC framework’s resource IDs, we can find these Window commands:

// Window commands
#define ID_WINDOW_NEW                   0xE130
#define ID_WINDOW_ARRANGE               0xE131
#define ID_WINDOW_CASCADE               0xE132
#define ID_WINDOW_TILE_HORZ             0xE133
#define ID_WINDOW_TILE_VERT             0xE134
#define ID_WINDOW_SPLIT                 0xE135
#ifndef RC_INVOKED      // code only
#define AFX_IDM_WINDOW_FIRST            0xE130
#define AFX_IDM_WINDOW_LAST             0xE13F
#define AFX_IDM_FIRST_MDICHILD          0xFF00  // window list starts here
#endif //!RC_INVOKED

Nothing yet about “More Windows…”, but AFX_IDM_FIRST_MDICHILD (commented with “window list starts here”) seems to be closer to what we need. Now, let’s dig deeper and do a search for AFX_IDM_FIRST_MDICHILD in the MFC source code:

BOOL CMDIFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)
{
   // ...
   ASSERT(AFX_IDM_FIRST_MDICHILD == 0xFF00);
   if (hWndCtrl == NULL && (LOWORD(wParam) & 0xf000) == 0xf000)
   {
      // menu or accelerator within range of MDI children
      // default frame proc will handle it
      DefWindowProc(WM_COMMAND, wParam, lParam);
      return TRUE;
   }
   // ...

It tells us that menu commands for activating MDI children (and can presume also the comand for “More Windows…”) are not handled in MFC framework, but in a default window procedure.

BOOL CMDIFrameWnd::CreateClient(LPCREATESTRUCT lpCreateStruct,
	CMenu* pWindowMenu)
{
   // ...
   CLIENTCREATESTRUCT ccs;
   // ...
   ccs.idFirstChild = AFX_IDM_FIRST_MDICHILD;
   // ...

This one tells us that first MDI child ID is set in idFirstChild member of CLIENTCREATESTRUCT, used when the MFC framework creates the MDI Client window.
Finally, taking a look in MSDN at CLIENTCREATESTRUCT documentation, we can note this:

idFirstChild
The child window identifier of the first MDI child window created. The system increments the identifier for each additional MDI child window the application creates, and reassigns identifiers when the application destroys a window to keep the range of identifiers contiguous. These identifiers are used in WM_COMMAND messages sent to the application’s MDI frame window when a child window is chosen from the window menu.

Conclusion

First command ID under MDI Window menu for activating documents has the value of idFirstChild member of CLIENTCREATESTRUCT structure used when creating the MDI Client window. In the MFC framework this value is AFX_IDM_FIRST_MDICHILD, defined in AFXRES.H. Each subsequent item has a value incremented by one. As long as MDI Window menu shows at most 9 documents/MDI children, then “More Windows…” menu item ID has the value AFX_IDM_FIRST_MDICHILD + 9. So, let’s handle it!

Handling “More Windows…” command

// MainFrm.h
// ...
#define APP_IDM_MOREWINDOWS (AFX_IDM_FIRST_MDICHILD + 9)

class CMainFrame : public CMDIFrameWnd
{
   // ...
   afx_msg void OnMoreWindows();
};
// MainFrm.cpp
// ...

BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
   // ...
   ON_COMMAND(APP_IDM_MOREWINDOWS, OnMoreWindows)
END_MESSAGE_MAP()
//...

void CMainFrame::OnMoreWindows()
{
   // "More Windows..." menu item has been selected.
   // Show our own custom "More Windows" dialog;
   CMoreWindowsDialog dlg;
   dlg.DoModal();
}

Demo application

The demo project atached here is a simple MDI application which shows a custom “More Windows” dialog having a list which contains, beside open document titles, the full path of documents. Also it has addditonal functions for closing the selected document and closing all documents.

Custom More Windows Dialog

Notes

  1. The attached project is intentionally made as simple as possible for demo purpose. You can improve it by making a custom “More Windows” dialog, according to your needs.
  2. CMoreWindowsDialog class implemented in demo project, gets a list of pointers to MDI document objects, like shown in a previous article: “Enumerate documents in MDI applications” (see the link, below). You may choose other ways, like for example, get a list of pointers to MDI child window objects.
  3. Someone with experience in working with MDI applications in raw-WinAPI, may know from starting the MDI Window menu issues described above. However, this article can demostrate that it is possible to discover Windows API backgrounds by digging into MFC framework source code.

Resources

See also

Downloads

 

1 thought on “Custom MDI “More Windows” Dialog”

Leave a Comment