HOWTO: Use Built-In Printing Features from a Rich Edit Control (129860)



The information in this article applies to:

  • Microsoft Platform Software Development Kit (SDK) 1.0

This article was previously published under Q129860

SUMMARY

The Rich Edit control contains built-in printing features that can be used to send formatted text to the printer with minimal effort from the programmer.

MORE INFORMATION

Printing from a Rich Edit control involves the use of the standard printing APIs and two Rich Edit control messages, EM_FORMATRANGE and EM_DISPLAYBAND. The EM_FORMATRANGE message can be used by itself or used in combination with the EM_DISPLAYBAND message. Included below at the end of this article is a code sample which demonstrates the usage of these messages.

EM_FORMATRANGE

This message is used to format the text for the printer DC and can optionally send the output to the printer.

The wParam parameter for this message is a Boolean value that indicates whether or not the text should be rendered (printed) to the printer. A zero value only formats the text, while a nonzero value formats the text and renders it to the printer.

The lParam parameter for this message is a pointer to the FORMATRANGE structure. This structure needs to be filled out before sending the message to the control.

FORMATRANGE Members

HDC hdc - Contains the device context (DC) to render to if the wParam parameter is nonzero. The output is actually sent to this DC.

HDC hdcTarget - Contains the device context to format for, which is usually the same as the hdc member but can be different. For example, if you create a print preview module, the hdc member is the DC of the window in which the output is viewed, and the hdcTarget member is the DC for the printer.

RECT rc - Contains the area to render to. This member contains the rectangle that the text is formatted to fit in, and subsequently printed in. It also contains the margins, room for headers and footers, and so forth. The rc.bottom member may be changed after the message is sent. If it is changed, it must indicate the largest rectangle that can fit within the bounds of the original rectangle and still contain the specified text without printing partial lines. It may be necessary to reset this value after each page is printed. These dimensions are given in TWIPS.

RECT rcPage - Contains the entire area of the rendering device. This area can be obtained using the GetDeviceCaps() function. These dimensions are given in TWIPS.

CHARRANGE chrg - Contains the range of characters to be printed. Set chrg.cpMin to 0 and chrg.cpMax to -1 to print all characters.

The return value from EM_FORMATRANGE is the index of the first character on the next page. If you are printing multiple pages, you should set chrg.cpMin to this value before the next EM_FORMATRANGE message is sent.

When printing is complete, this message must be sent to the control with wParam = 0 and lParam = NULL to free the information cache by the control.

EM_DISPLAYBAND

If you use 0 for the wParam parameter in the EM_FORMATRANGE message, then you can use the EM_DISPLAYBAND message to send the output to the printer.

The wParam parameter for this message is not used and should be 0.

The lParam parameter for this message is a pointer to a RECT structure. This RECT structure is the area to display to and is usually the same as the rc member of the FORMATRANGE structure used in the EM_FORMATRANGE message but can be different. For example, the rectangles are not the same if you are printing on a certain portion of a page or built-in margins are being used.

This message should only be used after a previous EM_FORMATRANGE message.

Sample Code

   void Print(HDC hPrinterDC, HWND hRTFWnd)
      {
      FORMATRANGE fr;
      int         nHorizRes = GetDeviceCaps(hPrinterDC, HORZRES),
                  nVertRes = GetDeviceCaps(hPrinterDC, VERTRES),
                  nLogPixelsX = GetDeviceCaps(hPrinterDC, LOGPIXELSX),
                  nLogPixelsY = GetDeviceCaps(hPrinterDC, LOGPIXELSY);
      LONG        lTextLength;   // Length of document.
      LONG        lTextPrinted;  // Amount of document printed.

      // Ensure the printer DC is in MM_TEXT mode.
      SetMapMode ( hPrinterDC, MM_TEXT );

      // Rendering to the same DC we are measuring.
      ZeroMemory(&fr, sizeof(fr));
      fr.hdc = fr.hdcTarget = hPrinterDC;

      // Set up the page.
      fr.rcPage.left     = fr.rcPage.top = 0;
      fr.rcPage.right    = (nHorizRes/nLogPixelsX) * 1440;
      fr.rcPage.bottom   = (nVertRes/nLogPixelsY) * 1440;

      // Set up 1" margins all around.
      fr.rc.left   = fr.rcPage.left + 1440;  // 1440 TWIPS = 1 inch.
      fr.rc.top    = fr.rcPage.top + 1440;
      fr.rc.right  = fr.rcPage.right - 1440;
      fr.rc.bottom = fr.rcPage.bottom - 1440;

      // Default the range of text to print as the entire document.
      fr.chrg.cpMin = 0;
      fr.chrg.cpMax = -1;

      // Set up the print job (standard printing stuff here).
      ZeroMemory(&di, sizeof(di));
      di.cbSize = sizeof(DOCINFO);
      if (*szFileName)
         di.lpszDocName = szFileName;
      else
         {
         di.lpszDocName = "(Untitled)";

         // Do not print to file.
         di.lpszOutput = NULL;
         }

      // Start the document.
      StartDoc(hPrinterDC, &di);

      // Find out real size of document in characters.
      lTextLength = SendMessage ( hRTFWnd, WM_GETTEXTLENGTH, 0, 0 );

      do
         {
         // Start the page.
         StartPage(hPrinterDC);

         // Print as much text as can fit on a page. The return value is
         // the index of the first character on the next page. Using TRUE
         // for the wParam parameter causes the text to be printed.

   #ifdef USE_BANDING

         lTextPrinted = SendMessage(hRTFWnd,
                                    EM_FORMATRANGE,
                                    FALSE,
                                    (LPARAM)&fr);
         SendMessage(hRTFWnd, EM_DISPLAYBAND, 0, (LPARAM)&fr.rc);

   #else

         lTextPrinted = SendMessage(hRTFWnd,
                                    EM_FORMATRANGE,
                                    TRUE,
                                    (LPARAM)&fr);

   #endif

         // Print last page.
         EndPage(hPrinterDC);

         // If there is more text to print, adjust the range of characters
         // to start printing at the first character of the next page.
            if (lTextPrinted < lTextLength)
            {
            fr.chrg.cpMin = lTextPrinted;
            fr.chrg.cpMax = -1;
            }
         }
      while (lTextPrinted < lTextLength);

      // Tell the control to release cached information.
      SendMessage(hRTFWnd, EM_FORMATRANGE, 0, (LPARAM)NULL);

      EndDoc (hPrinterDC);
      }
				

Modification Type:MinorLast Reviewed:7/8/2005
Keywords:kbCtrl kbhowto kbRichEdit KB129860