Serializing data in MFC / Visual C++

This post shows you how to utilize the built-in file handling capabilities that MFC has in order to serialize your data, that is, how to read from or write to a disk.

Using the MFC document object

One way is to use the MFC document object to do the serializing for you. This will be demonstrated by creating a simple SDI (single document interface) using the AppWizard.

Select File > New > Project and select the Visual C++ > MFC Application as the choice of installed template:

SerializeSDIexample1

In the Application Type, select Single Document:

SerializeSDIexample2

In the Advanced Features section, uncheck the Advanced frame panes:

SerializeSDIexample3

For this example, we will let the program accept and display input from the keyboard.

The first bit of coding is to store the characters that the user types in using a CString object, m_strData in the document class that is created in SerializeSDIexampleDoc.h:

class CSerializeSDIexampleDoc : public CDocument
{
protected: // create from serialization only
	CSerializeSDIexampleDoc();
	DECLARE_DYNCREATE(CSerializeSDIexampleDoc)

// Attributes
public:
	CString m_strData;
...

And initialise the value of m_strData in the document’s constructor:

CSerializeSDIexampleDoc::CSerializeSDIexampleDoc()
{
	m_strData = "";
}

We then write code to handle the WM_CHAR Windows messages that are received when the user inputs characters from the keyboard. You can either just write this code yourself, or use the ClassWizard.

To use the ClassWizard, right-click the project folder and select Class Wizard… Ensure the CSerializeSDIexampleView class name is selected. Select the Message tab and then select the ‘Add Handler…’ button.

SerializeSDIexample4

Then press Apply. Click Edit Code so that we can write code to store the characters the user types in. In addition this handler checks to see if the user has entered backspace, in which case it deletes the last character by shortening the string data member by 1:

void CSerializeSDIexampleView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: Add your message handler code here and/or call default
	CSerializeSDIexampleDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	if ( nChar == 8 )
	{
		int length = pDoc->m_strData.GetLength();
		CString str = pDoc->m_strData.Left( length - 1 );
		pDoc->m_strData = str;
	}
	else
	{
		CString str;
		str.Format( TEXT( "%c" ), nChar );
		pDoc->m_strData += str;
	}

	Invalidate();
	CView::OnChar(nChar, nRepCnt, nFlags);
}

Invalidate() is used to invalidate the view when the user types a new character.

We then add an message handler to display the new text string in OnDraw() method inside CSerializeSDIexampleView, which is automatically created.

Uncomment CDC* /*pDC*/ and add the code to display the text

void CSerializeSDIexampleView::OnDraw(CDC* pDC)
{
	CSerializeSDIexampleDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	
       if (!pDoc) return;

	pDC->TextOut( 0, 0, pDoc->m_strData );
}

Notice that the CSerializeSDIexampleDoc class already has a Serialize() method. This is where we serialize the m_strData string. Use the CArchive reference passed to it in the same as you would use std::cout or std::cin to read and write to the disk respectively:

void CSerializeSDIexampleDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		ar << m_strData;
	}
	else
	{
		ar >> m_strData;
	}
}

One last modification we make to the project is to let the application remember when the user has added more data to the m_strData object, so that when the user exits the application, before saving the changes, the application will prompt the user with a “Save changes to document” message.

In CSerializeSDIexampleView::OnChar indicate that the document has changed by setting the modified flag:

void CSerializeSDIexampleView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: Add your message handler code here and/or call default
	CSerializeSDIexampleDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	if ( nChar == 8 )
	{
		int length = pDoc->m_strData.GetLength();
		CString str = pDoc->m_strData.Left( length - 1 );
		pDoc->m_strData = str;
	}
	else
	{
		CString str;
		str.Format( TEXT( "%c" ), nChar );
		pDoc->m_strData += str;
	}
	Invalidate();
	pDoc->SetModifiedFlag();

	CView::OnChar(nChar, nRepCnt, nFlags);
}

Running the program, we can enter characters or delete them using the backspace:
SerializeSDIexample5

Now try closing the application without saving the text, so that you are prompted if you wish to save:

SerializeSDIexample6

Give the file a name and then save:

SerializeSDIexample7

Now restart the application, open the file Serialize1.txt in order to re-open:

SerializeSDIexample9

Download Visual Studio project from here:

Serializing data in MFC / Visual C++.

Related post:

Practical examples of using Boost serialization

Leave a Reply