Printing

A rich edit control can format its data to be suitable for use with devices such as displays and printers. Applications use the EM_FORMATRANGE message to tell the control how to format its contents. The FORMATRANGE structure used with this message specifies the range of text to format as well as the device context for the target device.

The RICHED sample supports printing through its Print command on the File menu. The sample uses the PrintDlg function to get the DC for the printer. It then fills out the FORMATRANGE structure with the DC, the rectangle to print, and the amount of data within the rectangle to print. The usual DOCINFO structure is filled out, and the rest is standard printing code.

void PrintTheContents (HWND hWndRichEdit)
{
FORMATRANGE fr;
DOCINFO docInfo;
LONG lTextOut, lTextAmt;
PRINTDLG pd;

// Initialize the PRINTDLG structure.
pd.lStructSize = sizeof (PRINTDLG);
pd.hwndOwner = hWndRichEdit;
pd.hDevMode = (HANDLE)NULL;
pd.hDevNames = (HANDLE)NULL;
pd.nFromPage = 0;
pd.nToPage = 0;
pd.nMinPage = 0;
pd.nMaxPage = 0;
pd.nCopies = 0;
pd.hInstance = (HANDLE)hInst;
pd.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION | PD_PRINTSETUP;
pd.lpfnSetupHook = (LPSETUPHOOKPROC)(FARPROC)NULL;
pd.lpSetupTemplateName = (LPTSTR)NULL;
pd.lpfnPrintHook = (LPPRINTHOOKPROC)(FARPROC)NULL;
pd.lpPrintTemplateName = (LPTSTR)NULL;

// Get the printer DC.
if (PrintDlg (&pd) == TRUE)
{
// Fill out the FORMATRANGE structure for the RTF output.
fr.hdc = fr.hdcTarget = pd.hDC; // HDC
fr.chrg.cpMin = 0; // print
fr.chrg.cpMax = -1; // entire contents
fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
fr.rc.right = fr.rcPage.right = GetDeviceCaps (pd.hDC, HORZRES);
fr.rc.bottom = fr.rcPage.bottom = GetDeviceCaps (pd.hDC, VERTRES);

// Fill out the DOCINFO structure.
docInfo.cbSize = sizeof (DOCINFO);
docInfo.lpszDocName = "(RTF Test)";
docInfo.lpszOutput = NULL;

// Be sure that the printer DC is in text mode.
SetMapMode (pd.hDC, MM_TEXT);

StartDoc (pd.hDC, &docInfo);
StartPage (pd.hDC);

lTextOut = 0;
lTextAmt = SendMessage (hWndRichEdit, WM_GETTEXTLENGTH, 0, 0);

while (lTextOut < lTextAmt)
{
lTextOut = SendMessage (hWndRichEdit, EM_FORMATRANGE, TRUE,
(LPARAM)&fr);

if (lTextOut < lTextAmt)
{
EndPage (pd.hDC);
StartPage (pd.hDC);
fr.chrg.cpMin = lTextOut;
fr.chrg.cpMax = -1;
}
}

// Reset the formatting of the rich edit control.
SendMessage (hWndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)NULL);

// Finish the document.
EndPage (pd.hDC);
EndDoc (pd.hDC);

// Delete the printer DC.
DeleteDC (pd.hDC);
}
}

An application can implement banding (that is, dividing the output into smaller parts in order to overcome printer buffer-size limitations) by using the EM_DISPLAYBAND message in concert with the EM_FORMATRANGE message. With the EM_SETTARGETDEVICE message, the application can also specify the target device for which the control will format its text. You'll find this message useful for WYSIWYG (What You See Is What You Get) formatting, in which an application positions text using the default printer's font metrics instead of the screen's font metrics.