| Tenouk | Home | SDI Serialization 4 | MDI Serialization 1 | Download | Site Index |


 

 

 

 

 

 

Module 11d:

Serialization: Reading and Writing Documents—SDI Applications 5

 

 

 

 

 

 

 

This is a continuation from the previous module... 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. CMymfc17View Class

  2. Testing the MYMFC17 Application

  3. Explorer Launch and Drag and Drop

  4. Program Registration

  5. Double-Clicking on a Document

  6. Enabling Drag and Drop

  7. Program Startup Parameters

  8. Experimenting with Explorer Launch and Drag and Drop

 

 

CMymfc17View

 

The code for the CMymfc17View class comes from the previous module. Listing 7 shows the code.

 

MYMFC17VIEW.H

// Mymfc17View.h : interface of the CMymfc17View class

//

//////////////////////////////////////////////////////////////////////

 

#if !defined(AFX_MYMFC17VIEW_H__4D011049_7E1C_11D0_8FE0_00C04FC2A0C2__INCLUDED_)

#define AFX_MYMFC17VIEW_H__4D011049_7E1C_11D0_8FE0_00C04FC2A0C2__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

class CMymfc17View : public CFormView

{

protected:

    POSITION      m_position; // current position in document list

    CStudentList* m_pList;    // copied from document

 

protected: // create from serialization only

    CMymfc17View();

    DECLARE_DYNCREATE(CMymfc17View)

 

public:

    //{{AFX_DATA(CMymfc17View)

    enum { IDD = IDD_MYMFC17_FORM };

    int     m_nGrade;

    CString m_strName;

    //}}AFX_DATA

 

// Attributes

public:

    CMymfc17Doc* GetDocument();

 

// Operations

public:

 

// Overrides

    // ClassWizard generated virtual function overrides

    //{{AFX_VIRTUAL(CMymfc17View)

    public:

    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

    protected:

    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support

    virtual void OnInitialUpdate(); // called first time after construct

    virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);

    //}}AFX_VIRTUAL

 

// Implementation

public:

    virtual ~CMymfc17View();

#ifdef _DEBUG

    virtual void AssertValid() const;

    virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

    virtual void ClearEntry();

    virtual void InsertEntry(POSITION position);

    virtual void GetEntry(POSITION position);

 

// Generated message map functions

protected:

    //{{AFX_MSG(CMymfc17View)

    afx_msg void OnClear();

    afx_msg void OnStudentHome();

    afx_msg void OnStudentEnd();

    afx_msg void OnStudentPrev();

    afx_msg void OnStudentNext();

    afx_msg void OnStudentIns();

    afx_msg void OnStudentDel();

    afx_msg void OnUpdateStudentHome(CCmdUI* pCmdUI);

    afx_msg void OnUpdateStudentEnd(CCmdUI* pCmdUI);

    afx_msg void OnUpdateStudentDel(CCmdUI* pCmdUI);

    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()

};

 

#ifndef _DEBUG  // debug version in Mymfc17View.cpp

inline CMymfc17Doc* CMymfc17View::GetDocument()

   { return (CMymfc17Doc*)m_pDocument; }

#endif

 

//////////////////////////////////////////////////////////////////////

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations

// immediately before the previous line.

 

#endif // !defined(AFX_MYMFC17VIEW_H__4D011049_7E1C_11D0_8FE0_00C04FC2A0C2__INCLUDED_)

 

 

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MYMFC17VIEW.CPP

// Mymfc17View.cpp : implementation of the CMymfc17View class

//

 

#include "stdafx.h"

#include "mymfc17.h"

 

#include "Mymfc17Doc.h"

#include "Mymfc17View.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[ ] = __FILE__ ;

#endif

 

//////////////////////////////////////////////////////////////////////

// CMymfc17View

 

IMPLEMENT_DYNCREATE(CMymfc17View, CFormView)

BEGIN_MESSAGE_MAP(CMymfc17View, CFormView)

    //{{AFX_MSG_MAP(CMymfc17View)

    ON_BN_CLICKED(IDC_CLEAR, OnClear)

    ON_COMMAND(ID_STUDENT_HOME, OnStudentHome)

    ON_COMMAND(ID_STUDENT_END, OnStudentEnd)

    ON_COMMAND(ID_STUDENT_PREV, OnStudentPrev)

    ON_COMMAND(ID_STUDENT_NEXT, OnStudentNext)

    ON_COMMAND(ID_STUDENT_INS, OnStudentIns)

    ON_COMMAND(ID_STUDENT_DEL, OnStudentDel)

    ON_UPDATE_COMMAND_UI(ID_STUDENT_HOME, OnUpdateStudentHome)

    ON_UPDATE_COMMAND_UI(ID_STUDENT_END, OnUpdateStudentEnd)

    ON_UPDATE_COMMAND_UI(ID_STUDENT_PREV, OnUpdateStudentHome)

    ON_UPDATE_COMMAND_UI(ID_STUDENT_NEXT, OnUpdateStudentEnd)

    ON_UPDATE_COMMAND_UI(ID_STUDENT_DEL, OnUpdateStudentDel)

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

//////////////////////////////////////////////////////////////////////

// CMymfc17View construction/destruction

 

CMymfc17View::CMymfc17View() : CFormView(CMymfc17View::IDD)

{

    TRACE("Entering CMymfc17View constructor\n");

    //{{AFX_DATA_INIT(CMymfc17View)

    m_nGrade = 0;

    m_strName = _T("");

    //}}AFX_DATA_INIT

    m_position = NULL;

}

 

CMymfc17View::~CMymfc17View()

{     }

 

void CMymfc17View::DoDataExchange(CDataExchange* pDX)

{

    CFormView::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CMymfc17View)

    DDX_Text(pDX, IDC_GRADE, m_nGrade);

    DDV_MinMaxInt(pDX, m_nGrade, 0, 100);

    DDX_Text(pDX, IDC_NAME, m_strName);

    DDV_MaxChars(pDX, m_strName, 20);

    //}}AFX_DATA_MAP

}

BOOL CMymfc17View::PreCreateWindow(CREATESTRUCT& cs)

{

    // TODO: Modify the Window class or styles here by modifying

    //  the CREATESTRUCT cs

    return CFormView::PreCreateWindow(cs);

}

 

void CMymfc17View::OnInitialUpdate()

{

    TRACE("Entering CMymfc17View::OnInitialUpdate\n");

    m_pList = GetDocument()->GetList();

    CFormView::OnInitialUpdate();

}

 

//////////////////////////////////////////////////////////////////////

// CMymfc17View diagnostics

 

#ifdef _DEBUG

void CMymfc17View::AssertValid() const

{

    CFormView::AssertValid();

}

 

void CMymfc17View::Dump(CDumpContext& dc) const

{

    CFormView::Dump(dc);

}

 

CMymfc17Doc* CMymfc17View::GetDocument() // non-debug version is inline

{

    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMymfc17Doc)));

    return (CMymfc17Doc*)m_pDocument;

}

#endif //_DEBUG

 

//////////////////////////////////////////////////////////////////////

// CMymfc17View message handlers

 

void CMymfc17View::OnClear()

{

    TRACE("Entering CMymfc17View::OnClear\n");

    ClearEntry();

}

 

void CMymfc17View::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)

{

    // called by OnInitialUpdate and by UpdateAllViews

    TRACE("Entering CMymfc17View::OnUpdate\n");

    m_position = m_pList->GetHeadPosition();

    GetEntry(m_position); // initial data for view

}

 

void CMymfc17View::OnStudentHome()

{

    TRACE("Entering CMymfc17View::OnStudentHome\n");

    // need to deal with list empty condition

    if (!m_pList->IsEmpty()) {

        m_position = m_pList->GetHeadPosition();

        GetEntry(m_position);

    }

}

 

void CMymfc17View::OnStudentEnd()

{

    TRACE("Entering CMymfc17View::OnStudentEnd\n");

    if (!m_pList->IsEmpty()) {

        m_position = m_pList->GetTailPosition();

        GetEntry(m_position);

    }

}

 

void CMymfc17View::OnStudentPrev()

{

    POSITION pos;

    TRACE("Entering CMymfc17View::OnStudentPrev\n");

    if ((pos = m_position) != NULL) {

        m_pList->GetPrev(pos);

        if (pos) {

            GetEntry(pos);

      m_position = pos;

        }

    }

}

 

void CMymfc17View::OnStudentNext()

{

    POSITION pos;

    TRACE("Entering CMymfc17View::OnStudentNext\n");

    if ((pos = m_position) != NULL) {

        m_pList->GetNext(pos);

        if (pos) {

            GetEntry(pos);

            m_position = pos;

        }

    }

}

void CMymfc17View::OnStudentIns()

{

    TRACE("Entering CMymfc17View::OnStudentIns\n");

    InsertEntry(m_position);

    GetDocument()->SetModifiedFlag();

    GetDocument()->UpdateAllViews(this);

}

 

void CMymfc17View::OnStudentDel()

{

    // deletes current entry and positions to next one or head

    POSITION pos;

    TRACE("Entering CMymfc17View::OnStudentDel\n");

    if ((pos = m_position) != NULL) {

        m_pList->GetNext(pos);

        if (pos == NULL) {

            pos = m_pList->GetHeadPosition();

            TRACE("GetHeadPos = %ld\n", pos);

            if (pos == m_position) {

                pos = NULL;

            }

        }

        GetEntry(pos);

        CStudent* ps = m_pList->GetAt(m_position);

        m_pList->RemoveAt(m_position);

        delete ps;

        m_position = pos;

        GetDocument()->SetModifiedFlag();

        GetDocument()->UpdateAllViews(this);

    }

}

 

void CMymfc17View::OnUpdateStudentHome(CCmdUI* pCmdUI)

{

    // called during idle processing and when Student menu drops down

    POSITION pos;

    // enables button if list not empty and not at home already

    pos = m_pList->GetHeadPosition();

    pCmdUI->Enable((m_position != NULL) && (pos != m_position));

}

 

void CMymfc17View::OnUpdateStudentEnd(CCmdUI* pCmdUI)

{

    // called during idle processing and when Student menu drops down

    POSITION pos;

    // enables button if list not empty and not at end already

    pos = m_pList->GetTailPosition();

    pCmdUI->Enable((m_position != NULL) && (pos != m_position));

}

 

void CMymfc17View::OnUpdateStudentDel(CCmdUI* pCmdUI)

{

    // called during idle processing and when Student menu drops down

    pCmdUI->Enable(m_position != NULL);

}

 

void CMymfc17View::GetEntry(POSITION position)

{

    if (position) {

        CStudent* pStudent = m_pList->GetAt(position);

        m_strName = pStudent->m_strName;

        m_nGrade = pStudent->m_nGrade;

    }

    else {

        ClearEntry();

    }

    UpdateData(FALSE);

}

 

void CMymfc17View::InsertEntry(POSITION position)

{

    if (UpdateData(TRUE)) {

        // UpdateData returns FALSE if it detects a user error

        CStudent* pStudent = new CStudent;

        pStudent->m_strName = m_strName;

        pStudent->m_nGrade = m_nGrade;

        m_position = m_pList->InsertAfter(m_position, pStudent);

    }

}

 

void CMymfc17View::ClearEntry()

{

    m_strName = "";

    m_nGrade = 0;

    UpdateData(FALSE);

    ((CDialog*) this)->GotoDlgCtrl(GetDlgItem(IDC_NAME));

}

 

 

 

 

 

 

 

 

 

 

 

 

 

Listing 7: The CMymfc17View class listing.

 

Testing the MYMFC17 Application

 

Build the program and start it from the debugger, and then test it by typing some data and saving it on disk with the filename Test.myext. You don't need to type the .myext.

 

MYMFC17 program output in action.

 

Figure 24: MYMFC17 program output in action.

 

MYMFC17 Save menu in action, saving some data.

 

Figure 25: MYMFC17 Save menu in action, saving some data.

 

Save dialog, prompting the file name.

 

Figure 26: Save dialog, prompting the file name.

 

Exit the program, and then restart it and open the file you saved. Did the data you typed come back? Take a look at the Debug window and observe the sequence of function calls. Is the following sequence produced when you start the application and open the file?

...

Entering CMymfc17Doc constructor

...

Entering CMymfc17View constructor

Entering CMymfc17Doc::OnNewDocument

Entering CMymfc17Doc::DeleteContents

Entering CMymfc17View::OnInitialUpdate

Entering CMymfc17View::OnUpdate

Entering CMainFrame::ActivateFrame

...

Entering CMymfc17Doc::OnOpenDocument

Entering CMymfc17Doc::DeleteContents

Entering CMymfc17Doc::Serialize

Entering CMymfc17Doc::Serialize

Entering CMymfc17Doc::Serialize

 

Entering CMymfc17View::OnInitialUpdate

Entering CMymfc17View::OnUpdate

Entering CMainFrame::ActivateFrame

...

The thread 0xB30 has exited with code 0 (0x0).

The program 'F:\mfcproject\mymfc17\Debug\mymfc17.exe' has exited with code 0 (0x0).

Explorer launch and Drag and Drop

 

In the past, PC users were accustomed to starting up a program and then selecting a disk file (sometimes called a document) that contained data the program understood. Many MS-DOS-based programs worked this way. The old Windows Program Manager improved things by allowing the user to double-click on a program icon instead of typing a program name. Meanwhile, Apple Macintosh users were double-clicking on a document icon; the Macintosh operating system figured out which program to run. While Windows Explorer still lets users double-click on a program, it also lets users double-click on a document icon to run the document's program. But how does Explorer know which program to run? Explorer uses the Windows Registry to make the connection between document and program. The link starts with the filename extension that you typed into AppWizard, but as you'll see, there's more to it than that. Once the association is made, users can launch your program by double-clicking on its document icon or by dragging the icon from Explorer to a running instance of your program. In addition, users can drag the icon to a printer, and your program will print it.

 

Program Registration

 

In Module 9, you saw how MFC applications store data in the Windows Registry by calling SetRegistryKey() from the InitInstance() function. Independent of this SetRegistryKey() call, your program can write file association information in a different part of the Registry on startup. To activate this feature, you must type in the filename extension when you create the application with AppWizard. (Use the Advanced button in AppWizard Step 4.) After you do that, AppWizard adds the extension as a substring in your template string and adds the following line in your InitInstance() function:

 

RegisterShellFileTypes(TRUE);

 

 

Listing 8.

 

Now your program adds two items to the Registry. Under the HKEY_CLASSES_ROOT top-level key, it adds a subkey and a data string as shown here for the MYMFC17 example:

 

.myext = Mymfc17.Document

 

Registry information for MYMFC17 project.

 

Figure 27: Registry information for MYMFC17 project.

 

The data item is the file type ID that AppWizard has chosen for you. Mymfc17.Document, in turn, is the key for finding the program itself. The Registry entries for Mymfc17.Document, also beneath HKEY_CLASSES_ROOT, are shown here.

 

Another Registry information for MYMFC17.

 

Figure 28: Another Registry information for MYMFC17.

 

Notice that the Registry contains the full pathname of the MYMFC17 program. Now Explorer can use the Registry to navigate from the extension to the file type ID to the actual program itself. After the extension is registered, Explorer finds the document's icon and displays it next to the filename, as shown here.

 

Icon and file extension.

Figure 29: Icon and file extension.

 

Double-Clicking on a Document

 

When the user double-clicks on a document icon, Explorer executes the associated SDI program, passing in the selected filename on the command line. You might notice that AppWizard generates a call to EnableShellOpen() in the application class InitInstance() function. This supports execution via DDE message, the technique used by the File Manager in Windows NT 3.51. Explorer can launch your SDI application without this call.

 

Enabling Drag and Drop

 

If you want your already-running program to open files dragged from Explorer, you must call the CWnd function DragAcceptFiles() for the application's main frame window. The application object's public data member m_pMainWnd points to the CFrameWnd (or CMDIFrameWnd) object. When the user drops a file anywhere inside the frame window, the window receives a WM_DROPFILES message, which triggers a call to FrameWnd::OnDropFiles. The following line in InitInstance(), generated by AppWizard, enables drag and drop:

 

m_pMainWnd->DragAcceptFiles();

 

 

Listing 9.

 

Program Startup Parameters

 

When you choose Run from the Start menu, or when you double-click the program directly in Explorer, there is no command-line parameter. The InitInstance() function processes the command line with calls to ParseCommandLine() and ProcessShellCommand(). If the command line contains something that looks like a filename, the program immediately loads that file. Thus, you create a Windows shortcut that can run your program with a specific document file.

 

Experimenting with Explorer Launch and Drag and Drop

 

Once you have built MYMFC17, you can try running it from Explorer. You must execute the program directly, however, in order to write the initial entries in the Registry. Be sure that you've saved at least one myext file to disk, and then exit MYMFC17. Start Explorer, and then open the \vcpp32\mymfc17 directory. Double-click on one of the myext files in the panel on the right. Your program should start with the selected file loaded. Now, with both MYMFC17 and Explorer open on the desktop, try dragging another file from Explorer to the MYMFC17 window. The program should open the new file just as if you had chosen File Open from the MYMFC17 menu.

You might also want to look at the MYMFC17 entries in the Registry. Run the Regedit program (possibly named Regedt32 in Windows NT), and expand the HKEY_CLASSES_ROOT key. Look under ".myext" and "Mymfc17.Document."

Also expand the HKEY_CURRENT_USER (or HKEY_USERS\.DEFAULT) key, and look under "Software." You should see a Recent File List under the subkey mymfc17.

 

Recent File List in Registry for MYMFC17 project.

 

Figure 30: Recent File List in Registry for MYMFC17 project.

 

The MYMFC17 program calls SetRegistryKey() with the string "Local AppWizard-Generated Applications", so the program name goes beneath the mymfc17 subkey.

 

 

 

 

Further reading and digging:

  1. MSDN MFC 7.0 class library online documentation.

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

  3. Porting & Migrating your older programs.

  4. MSDN Library

  5. DCOM at MSDN.

  6. COM+ at MSDN.

  7. COM at MSDN.

  8. Windows data type.

  9. Win32 programming Tutorial.

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

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

 

 

 

 

 


 

| Tenouk | Home | SDI Serialization 4 | MDI Serialization 1 | Download | Site Index |