Serialization Using Streams

Data is transferred into or out of a rich edit control through streams. A stream is defined by an EDITSTREAM structure, which specifies a buffer and an application-defined callback function. In the RICHED sample, the user can open either a text (TXT) file or a rich text format (RTF) file. The data is read into the rich edit control through the EM_STREAMIN message. After receiving this message, the control repeatedly calls the application-defined callback function, EditStreamCallback, which transfers a portion of the data into the buffer each time. The dwCookie member of the EDITSTREAM structure is an application-defined value. The RICHED sample uses this member for storing the handle to the file opened by the OpenFile function. The EM_STREAMIN message allows either textual or RTF data to be read in by specifying SF_TEXT or SF_RTF in the wParam parameter.

BOOL OpenTheFile (HWND hWndRichEdit, int iAttrib, char *lpszFileName)
{
HFILE hFile;
OFSTRUCT of;
EDITSTREAM eStream;

if (hFile = OpenFile (lpszFileName, &of, OF_READ))
{
// dwCookie is an app-defined value that holds
// the handle to the file.
eStream.dwCookie = hFile;
eStream.pfnCallback = EditStreamCallback;
eStream.dwError = 0;
SendMessage (hWndRichEdit, EM_STREAMIN, (WPARAM)iAttrib,
(LPARAM)&eStream);

// Reset the dirty bit.
SendMessage (hWndRichEdit, EM_SETMODIFY, (WPARAM)TRUE, OL);

CloseHandle ((HANDLE)hFile);
return TRUE;
}
return FALSE;
}

DWORD CALLBACK EditStreamCallback (DWORD dwCookie,
LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
{
ReadFile ((HANDLE)dwCookie, pbBuff, cb, pcb, NULL);
if (*pcb < cb)
return 0; // file has been fully read in
else
return (DWORD) *pcb; // more to read
}

As you can see from the code on the following page, the RICHED sample offers two options for saving the contents of the rich edit control: save as a TXT file or save as an RTF file. The application sends the EM_STREAMOUT message to save the contents of the control. The control repeatedly writes to the buffer and then calls the application's callback function. For each call, this function saves the contents of the buffer.

BOOL SaveTheFile (HWND hWndRichEdit, int nID)
{
HFILE hFile;
OFSTRUCT of;
EDITSTREAM eStream;
char *lpszFileName;
int iAttrib;

if (nID == IDM_SAVETXT)
{
lpszFileName = "TEXTDOC.TXT";
iAttrib = SF_TEXT;
}
else
{
lpszFileName = "RTFDOC.RTF";
iAttrib = SF_RTF;
}
if (hFile = OpenFile (lpszFileName, &of, OF_CREATE))
{
eStream.dwCookie = hFile;
eStream.dwError = 0;
eStream.pfnCallback = SaveCallback;
SendMessage (hWndRichEdit, EM_STREAMOUT, (WPARAM)iAttrib,
(LPARAM)&eStream);

CloseHandle ((HANDLE)hFile);
return TRUE;
}
return FALSE;
}

DWORD CALLBACK SaveCallback (DWORD dwCookie,
LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
{
WriteFile ((HANDLE)dwCookie, pbBuff, cb, pcb, NULL);
return 0;
}

As Figure 5-6 shows, the options in the RICHED sample for reading in or saving data are limited to specifying the type of data (TXT or RTF). The sample furnishes the names of the sample files. To allow the user a choice of files to read in, you should use the common dialog boxes designed for opening and saving files. (You'll find detailed information about the common dialog boxes in Chapter 6.)

 

Figure 5-6.

The File menu in the RICHED sample.