| Tenouk C & C++ | MFC Home | SDI Serialization 5 | MDI Serialization 2 | Download | Site Index |


 

 

 

 

 

 

Module 12:

Serialization: Reading and Writing Documents—MDI Applications 1

 

 

 

 

 

Program examples compiled using Visual C++ 6.0 (MFC 6.0) compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this Tutorial are listed below. You can compare the standard C file I/O, standard C++ file I/O and Win32 directory, file and access controls with the MFC serialization. So many things lor! Similar but not same. Those links also given at the end of this tutorial.

  1. Reading and Writing Documents: MDI Applications

  2. The MDI Application

  3. A Typical MDI Application, MFC Style

  4. For Win32 Programmers

  5. The MDI Application Object

  6. The MDI Document Template Class

  7. The MDI Frame Window and the MDI Child Window

  8. The Main Frame and Document Template Resources

  9. Creating an Empty Document: The CWinApp::OnFileNew Function

  10. Creating an Additional View for an Existing Document

  11. Loading and Storing Documents

  12. Multiple Document Templates

  13. Explorer Launch and Drag and Drop

 

 

 

Reading and Writing Documents: MDI Applications

 

This module introduces the Microsoft Foundation Class (MFC) Library version 6.0 Multiple Document Interface (MDI) application and demonstrates how it reads and writes its document files. The MDI application appears to be the preferred MFC library program style. It's the AppWizard default, and most of the sample programs that come with Microsoft Visual C++ are MDI applications.

In this module, you'll learn the similarities and differences between Single Document Interface (SDI) and MDI applications and you'll learn how to convert an SDI application to an MDI application. Be sure you thoroughly understand the SDI application described in Module 11 before you attack the MDI application in this module.

 

The MDI Application

 

Before you look at the MFC library code for MDI applications, you should be familiar with the operation of Microsoft Windows MDI programs. Take a close look at Visual C++ now. It's an MDI application whose "multiple documents" are program source code files. Visual C++ is not the most typical MDI application, however, because it collects its documents into projects. It's better to examine Microsoft Word or, better yet, a real MFC library MDI application, the kind that AppWizard generates.

 

A Typical MDI Application, MFC Style

 

This module's example, MYMFC18, is an MDI version of MYMFC17. Run the MYMFC17 example to see an illustration of the SDI version after the user has selected a file. Now look at the MDI equivalent, as shown in Figure 1.

 

The MYMFC18 application with two files open and the Window menu shown.

 

Figure 1: The MYMFC18 application with two files open and the Window menu shown.

 

The user has two separate document files open, each in a separate MDI child window, but only one child window is active, the lower window, which lies on top of the other child window. The application has only one menu and one toolbar, and all commands are routed to the active child window. The main window's title bar reflects the name of the active child window's document file. The child window's minimize box allows the user to reduce the child window to an icon in the main window. The application's Window menu (shown in Figure 18-1) lets the user control the presentation through the following items.

 

Menu Item

Action

New Window

Opens as an additional child window for the selected document

Cascade

Arranges the existing windows in an overlapped pattern

Tile

Arranges the existing windows in a non-overlapped, tiled pattern

Arrange Icons

Arranges minimized windows in the frame window

(document names)

Selects the corresponding child window and brings it to the top

 

Table 1

 

If the user closes both child windows (and opens the File menu), the application looks like the Figure 2.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

------------------------------------------------------------------------------------------------------------

MYMFC18 with no child windows.

 

Figure 2: MYMFC18 with no child windows.

 

The File menu is different, most toolbar buttons are disabled, and the window caption does not show a filename. The only choices the user has are to start a new document or to open an existing document from disk. Figure 3 shows the application when it first starts up and a new document is created. The single child window has been maximized.

MYMFC18 with initial child window.

 

Figure 3: MYMFC18 with initial child window.

 

The single, empty child window has the default document name Mymfc11. This name is based on the Doc Type Name (Mymfc1) that you selected in the Advanced Options dialog after clicking the Advanced button in Step 4 of AppWizard. The first new file is Mymfc11, the second is Mymfc12, and so forth. The user normally chooses a different name when saving the document.

An MFC library MDI application, like many commercial MDI applications, starts up with a new, empty document. (Visual C++ is an exception.) If you want your application to start up with a blank frame, you can modify the argument to the ProcessShellCommand() call in the application class file, as shown in example MYMFC18.

 

For Win32 Programmers

 

Starting with version 3.0, Windows directly supports MDI applications. The MFC library builds on this Windows support to create an MDI environment that parallels the SDI environment. In a Win32 MDI application, a main application frame window contains the menu and a single client window. The client window manages various child windows that correspond to documents. The MDI client window has its own pre-registered window class (not to be confused with a C++ class) with a procedure that handles special messages such as WM_MDICASCADE and WM_MDITILE. An MDI child window procedure is similar to the window procedure for an SDI main window.

In the MFC library, the CMDIFrameWnd class encapsulates the functions of both the main frame window and the MDI client window. This class has message handlers for all the Windows MDI messages and thus can manage its child windows, which are represented by objects of class CMDIChildWnd.

 

The MDI Application Object

 

You're probably wondering how an MDI application works and what code makes it different from an SDI application. Actually, the startup sequences are pretty much the same. An application object of a class derived from class CWinApp has an overridden InitInstance() member function. This InitInstance() function is somewhat different from the SDI InitInstance() function, starting with the call to AddDocTemplate().

 

The MDI Document Template Class

 

The MDI template construction call in InitInstance() looks something like this:

 

CMultiDocTemplate* pDocTemplate;

pDocTemplate = new CMultiDocTemplate(

    IDR_MYMFC1TYPE,

    RUNTIME_CLASS(CMymfc18Doc),

    RUNTIME_CLASS(CChildFrame), // custom MDI child frame

    RUNTIME_CLASS(CMymfc18View));

AddDocTemplate(pDocTemplate);

 

 

Listing 1.

 

Unlike the SDI application you saw in Module 11, an MDI application can use multiple document types and allows the simultaneous existence of more than one document object. This is the essence of the MDI application. The single AddDocTemplate() call shown above permits the MDI application to support multiple child windows, each connected to a document object and a view object. It's also possible to have several child windows (and corresponding view objects) connected to the same document object. In this module, we'll start with only one view class and one document class. You'll see multiple view classes and multiple document classes in Module 14. When your application is running, the document template object maintains a list of active document objects that were created from the template. The CMultiDocTemplate() member functions GetFirstDocPosition() and GetNextDoc() allow you to iterate through the list. Use CDocument::GetDocTemplate to navigate from a document to its template.

 

The MDI Frame Windows and the MDI Child Window

 

The SDI examples had only one frame window class and only one frame window object. For SDI applications, AppWizard generated a class named CMainFrame, which was derived from the class CFrameWnd. An MDI application has two frame window classes and many frame objects, as shown in the table below. The MDI frame-view window relationship is shown in Figure 4.

 

Base Class

AppWizard-Generated Class

Number of Objects

Menu and Control Bars

Contains a View

Object Constructed

CMDIFrameWnd

CMainFrame

1 only

Yes

No

In application class's InitInstance() function

CMDIChildWnd

CChildFrame

1 per child window

No

Yes

By application framework when a new child window is opened.

 

Table 2.

 

The MDI frame-view window relationship.

 

Figure 4: The MDI frame-view window relationship.

 

 

In an SDI application, the CMainFrame object frames the application and contains the view object. In an MDI application, the two roles are separated. Now the CMainFrame object is explicitly constructed in InitInstance(), and the CChildFrame object contains the view. AppWizard generates the following code:

 

CMainFrame* pMainFrame = new CMainFrame;

if (!pMainFrame->LoadFrame(IDR_MAINFRAME))

    return FALSE;

m_pMainWnd = pMainFrame;

 

 

Listing 2.

 

Code calls ProcessShellCommand() to create child frame.

 

pMainFrame->ShowWindow(m_nCmdShow);

pMainFrame->UpdateWindow();

 

 

Listing 3.

 

The application framework can create the CChildFrame objects dynamically because the CChildFrame runtime class pointer is passed to the CMultiDocTemplate constructor. The MDI InitInstance() function sets the CWinApp data member m_pMainWnd to point to the application's main frame window. This means you can access m_pMainWnd through the global AfxGetApp() function anytime you need to get your application's main frame window.

 

The Main Frame and Document Template Resources

 

An MDI application (MYMFC18, as described later in this module) has two separate string and menu resources, identified by the IDR_MAINFRAME and IDR_MYMFC18TYPE constants. The first resource set goes with the empty main frame window; the second set goes with the occupied main frame window. Here are the two string resources with substrings broken out:

 

IDR_MAINFRAME

    "mymfc18"                   // application window caption

 

IDR_MYMFC18TYPE

    "\n"                        // (not used)

    "Mymfc1\n"                  // root for default document name

    "Mymfc1\n"                  // document type name

    "Mymfc1 Files (*.txe)\n"    // document type description and filter

    ".txe\n"                    // extension for documents of this type

    "Mymfc18.Document\n"        // Registry file type ID

    "Mymfc1 Document"           // Registry file type description

 

You can see this by double clicking the String Table in the ResourceView and the IDR_MYMFC1TYPE on the left window as shown below.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

String table.

 

Figure 5: String table.

 

String properties for IDR_MYMFC1TYPE.

 

Figure 6: String properties for IDR_MYMFC1TYPE.

 

The resource compiler won't accept the string concatenations as shown above. If you examine the mymfc18.rc file, you'll see the substrings combined in one long string. The application window caption comes from the IDR_MAINFRAME string. When a document is open, the document filename is appended. The last two substrings in the IDR_MYMFC18TYPE string support embedded launch and drag and drop.

 

Creating an Empty Document: The CWinApp::OnFileNew Function

 

The MDI InitInstance() function calls OnFileNew() (through ProcessShellCommand()), as did the SDI InitInstance() function. This time, however, the main frame window has already been created. OnFileNew(), through a call to the CMultiDocTemplate() function OpenDocumentFile(), now does the following:

 

  1. Constructs a document object but does not attempt to read data from disk.

  2. Constructs a child frame window object (of class CChildFrame). Also creates the child frame window but does not show it. In the main frame window, the IDR_MYMFC18TYPE menu replaces the IDR_MAINFRAME menu. IDR_MYMFC18TYPE also identifies an icon resource that is used when the child window is minimized within the frame.

  3. Constructs a view object. Also creates the view window but does not show it.

  4. Establishes connections among the document, the main frame, and view objects. Do not confuse these object connections with the class associations established by the call to AddDocTemplate().

  5. Calls the virtual OnNewDocument() member function for the document object.

  6. Calls the virtual OnInitialUpdate() member function for the view object.

  7. Calls the virtual ActivateFrame() member function for the child frame object to show the frame window and the view window.

 

The OnFileNew() function is also called in response to the File New menu command. In an MDI application, OnFileNew() performs exactly the same steps as it does when called from InitInstance(). Some functions listed above are not called directly by OpenDocumentFile() but are called indirectly through the application framework.

 

Creating an Additional View for an Existing Document

 

If you choose the New Window command from the Window menu, the application framework opens a new child window that is linked to the currently selected document. The associated CMDIFrameWnd() function, OnWindowNew(), does the following:

 

  1. Constructs a child frame object (of class CChildFrame). Also creates the child frame window but does not show it.

  2. Constructs a view object. Also creates the view window but does not show it.

  3. Establishes connections between the new view object and the existing document and main frame objects.

  4. Calls the virtual OnInitialUpdate() member function for the view object.

  5. Calls the virtual ActivateFrame() member function for the child frame object to show the frame window and the view window.

 

Loading and Storing Document

 

In MDI applications, documents are loaded and stored the same way as in SDI applications but with two important differences: a new document object is constructed each time a document file is loaded from disk, and the document object is destroyed when the child window is closed. Don't worry about clearing a document's contents before loading, but override the CDocument::DeleteContents function anyway to make the class portable to the SDI environment.

 

Multiple Document Templates

 

An MDI application can support multiple document templates through multiple calls to the AddDocTemplate() function. Each template can specify a different combination of document, view, and MDI child frame classes. When the user chooses New from the File menu of an application with multiple templates, the application framework displays a list box that allows the user to select a template by name as specified in the string resource (document type substring). Multiple AddDocTemplate() calls are not supported in SDI applications because the document, view, and frame objects are constructed once for the life of the application.

When your application is running, the application object keeps a list of active document template objects. The CWinApp member functions GetFirstDocTemplatePosition() and GetNextDocTemplate() allow you to iterate through the list of templates. These functions, together with the CDocTemplate() member functions GetFirstDocPosition() and GetNextDoc(), allow you to access all of the application's document objects. If you don't want the template list box, you can edit the File menu to add a New menu item for each document type. Code the command message handlers as shown below, using the document type substring from each template.

 

void CMyApp::OnFileNewStudent()

{

    OpenNewDocument("Studnt");

}

 

void CMyApp::OnFileNewTeacher()

{

    OpenNewDocument("Teachr");

}

 

Then add the OpenNewDocument() helper function as follows:

 

BOOL CMyApp::OpenNewDocument(const CString& strTarget)

{

    CString strDocName;

    CDocTemplate* pSelectedTemplate;

    POSITION pos = GetFirstDocTemplatePosition();

    while (pos != NULL)

    {

        pSelectedTemplate = (CDocTemplate*) GetNextDocTemplate(pos);

        ASSERT(pSelectedTemplate != NULL);

        ASSERT(pSelectedTemplate->IsKindOf(RUNTIME_CLASS(CDocTemplate)));

        pSelectedTemplate->GetDocString(strDocName, CDocTemplate::docName);

        if (strDocName == strTarget) { // from template's

                                       // string resource

            pSelectedTemplate->OpenDocumentFile(NULL);

            return TRUE;

        }

    }

    return FALSE;

}

 

Explorer Launch and Drag and Drop

 

When you double-click on a document icon for an MDI application in Windows Explorer, the application launches only if it was not running already; otherwise, a new child window opens in the running application for the document you selected. The EnableShellOpen() call in the application class InitInstance() function is necessary for this to work.

 

 

Listing 4.

 

Drag and drop works much the same way in an MDI application as it does in an SDI application. If you drag a file from Windows Explorer to your MDI main frame window, the program opens a new child frame (with associated document and view) just as if you'd chosen the File Open command. As with SDI applications, you must use the AppWizard Step 4 Advanced button to specify the filename extension.

 

 

Continue on next module...part 2.

 

 

 

 

Further reading and digging:

  1. Standard C File Input/Output.

  2. Standard C++ File Input/Output.

  3. Win32 File Input/Output: Module C, Module D and Module E.

  4. MSDN MFC 7.0 class library online documentation.

  5. MSDN MFC 9.0 class library online documentation - latest version.

  6. MSDN Library

  7. Windows data type.

  8. Win32 programming Tutorial.

  9. The best of C/C++, MFC, Windows and other related books.

  10. Unicode and Multibyte character set: Story and program examples.

 

 

 

 


 

| Tenouk C & C++ | MFC Home | SDI Serialization 5 | MDI Serialization 2 | Download | Site Index |