Tag Archives: MDI application

Double-click in MDI Client

It’s hard to believe that handling mouse double-clicks in MDI Client windows can be super useful, but I found this problem in a discussion forum. I presumed that it was not only for fun, so I tried to resolve it. First, I subclassed the MDI Client window in a CWnd-derived class. That is possible for a standard MFC project in this way:

But no success: WM_LBUTTONDBLCLK message handler is not called in CMDIClientWnd class. Then I tried to catch it in overridden PreTranslateMessage or even in a WH_MOUSE hook with the same result. Finally, I had a look using Spy++ tool. Bingo! The MDI Client (of predefined window class named “MdiClient“) has no CS_DBLCLKS style so it does not deal with mouse double-clicks.

MDIClient

MDIClient

All wat he have to do is to create the The MDI Client window with our own registered window class. This is possible by overriding CMDIFrameWnd::CreateClient.

Create a MDI client window which belongs to a window class having CS_DBLCLKS style

Handle MDI Client double-clicks in standard MFC applications

Once we have created the MDI Client window and subclassed it as shown above, can simply handle (for example) WM_LBUTTONDBLCLK in our CWnd-derived class.

Handle MDI Client double-clicks in Visual Studio or Office-style MFC applications

CMDIFrameWndEx uses its own CWnd-derived class for the MDI Client window, so we cannot use another one in  main frame class. However, this is not so big problem because we can now catch WM_LBUTTONDBLCLK in overridden PreTranslateMessage method.

Or, you can catch it in a WH_MOUSE hook, if think that can be more exciting. :)

Note that creating the MDI Client window in overridden CMDIFrameWnd::CreateClient cand be done in all cases in the same way.

Demo solution

Download: MDI client double-click samples.zip (196)
The sample Visual Studio solution contains two projects: one is a standard MDI application, and the other one is Office-style. Just enjoy of MDI Client double-clicks! :)

Resources and related articles

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:

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:

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.

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

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

 

Enumerate documents in MDI applications

To enumerate all open documents in MDI (Multiple Document Interface) MFC applications we can do the following:

  1. Use CWinApp::GetFirstDocTemplatePosition and CWinApp::GetNextDocTemplate to get application document templates.
  2. For each document template, use CDocTemplate::GetFirstDocPosition and CDocTemplate::GetNextDoc to get contained documents.

Getting documents list

Example using documents list

This example calls CMyMDIApp::GetAllDocuments to get a list of all open documents, then fill a combobox control with document titles.
Also, it keeps the document pointers in each item data for further use (e.g. the application can activate the selected document at user request).

Resources

See also