Although the MDI specification has been around since Windows 2.0, at that time MDI applications were difficult to write and required some very intricate programming work. Since Windows 3.0, however, much of that work has already been done for you. That support, with some enhancements from Windows 95, has been carried over into Windows 98 and Microsoft Windows NT.
The main application window of an MDI program is conventional: it has a title bar, a menu, a sizing border, a system menu icon, and minimize/maximize/close buttons. The client area, however, is often called a "workspace" and is not directly used to display program output. This workspace contains zero or more child windows, each of which displays a document.
These child windows look much like normal application windows and much like the main application window of an MDI program. They too have a title bar, a sizing border, a system menu icon, minimize/maximize/close buttons, and possibly scroll bars. None of the document windows has a menu, however. The menu on the main application window applies to the document windows.
At any one time, only one document window is active (indicated by a highlighted title bar), and it appears in front of all the other document windows. All the document child windows are clipped to the workspace area and never appear outside the application window.
At first, MDI seems a fairly straightforward job for the Windows programmer. All you need to do is create a WS_CHILD window for each document, making the program's main application window the parent of the document window. But with a little exploration of existing MDI applications, you'll find some complications that require difficult code.
All of these aspects of MDI are supported in Windows 98. Some overhead is required of course (as will be shown in a sample program), but it isn't anywhere close to the amount of code you'd have to write to support all these features directly.
Some new terminology is necessary when approaching the Windows MDI support. The main application window is called the "frame window." Just as in a conventional Windows program, this is a window of the WS_OVERLAPPEDWINDOW style.
An MDI application also creates a "client window" based on the predefined window class MDICLIENT. The client window is created by a call to CreateWindow using this window class and the WS_CHILD style. The last argument to CreateWindow is a pointer to a small structure of type CLIENTCREATESTRUCT. This client window covers the client area of the frame window and is responsible for much of the MDI support. The color of this client window is the system color COLOR_APPWORKSPACE.
The document windows, as you've probably noticed, are called "child windows." You create these windows by initializing a structure of type MDICREATESTRUCT and sending the client window a WM_MDICREATE message with a pointer to this structure.
The document windows are children of the client window, which in turn is a child of the frame window. The parent-child hierarchy is shown in Figure 19-1.
Figure 19-1. The parent-child hierarchy of a Windows MDI application.
You need a window class (and window procedure) for the frame window and for each type of child window supported by the application. You don't need a window procedure for the client window because the window class is preregistered.
The MDI support of Windows 98 includes one window class, five functions, two data structures, and twelve messages. I've already mentioned the new window class, which is MDICLIENT, and the new data structures, CLIENTCREATESTRUCT and MDICREATESTRUCT. Two of the five functions replace DefWindowProc in MDI applications: rather than call DefWindowProc for all unprocessed messages, a frame window procedure calls DefFrameProc and a child window procedure calls DefMDIChildProc. Another function specific to MDI, TranslateMDISysAccel, is used in the same way as TranslateAccelerator, which I discussed in Chapter 10. The MDI support also includes ArrangeIconicWindows, but one of the special MDI messages makes this function unnecessary for MDI programs.
The fifth MDI function is called CreateMDIWindow. This allows the child window to be created in a separate thread of execution. This function is not required in a single-threaded program, which is what I'll be demonstrating.
In the sample program coming up, I'll demonstrate nine of the twelve MDI messages. (The other three are not normally required.) These messages begin with the prefix WM_MDI. A frame window sends these messages to the client window to perform an operation on a child window or to obtain information about a child window. (For example, a frame window sends a WM_MDICREATE message to a client window to create a child window.) The WM_MDIACTIVATE message is an exception: while a frame window can send this message to the client window to activate one of the child windows, the client window also sends the message to the child windows being activated and deactivated to inform them of this change.