This step-by-step article describes how to print the content
of a RichTextBox control. The RichTextBox control does not provide a method to print its content. However,
you can extend the RichTextBox class to use the EM_FORMATRANGE message. You can then send the
content of a RichTextBox to an output device, such as a printer.
To extend the RichTextBox class and use EM_FORMATRANGE to print the content of the RichTextBox control, follow these steps:
Use Microsoft Visual Basic .NET or Microsoft Visual Basic 2005 to create a new Class
Library project named RichTextBoxPrintCtrl.
By
default, Class1.vb is created.
Change the name of the Class1.vb file to
RichTextBoxPrintCtrl.vb.
In the Solution Explorer, right-click
References, and then click Add
Reference.
In the Add Reference dialog box, double-click System.Drawing.dll, and
then double-click System.Windows.Forms.dll.
To add references, click OK.
Delete the existing code in
RichTextBoxPrintCtrl.vb.
Copy the following code to
RichTextBoxPrintCtrl.vb:
Option Explicit On
Imports System
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Drawing.Printing
Namespace RichTextBoxPrintCtrl
Public Class RichTextBoxPrintCtrl
Inherits RichTextBox
' Convert the unit that is used by the .NET framework (1/100 inch)
' and the unit that is used by Win32 API calls (twips 1/1440 inch)
Private Const AnInch As Double = 14.4
<StructLayout(LayoutKind.Sequential)> _
Private Structure RECT
Public Left As Integer
Public Top As Integer
Public Right As Integer
Public Bottom As Integer
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure CHARRANGE
Public cpMin As Integer ' First character of range (0 for start of doc)
Public cpMax As Integer ' Last character of range (-1 for end of doc)
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure FORMATRANGE
Public hdc As IntPtr ' Actual DC to draw on
Public hdcTarget As IntPtr ' Target DC for determining text formatting
Public rc As Rect ' Region of the DC to draw to (in twips)
Public rcPage As Rect ' Region of the whole DC (page size) (in twips)
Public chrg As CHARRANGE ' Range of text to draw (see above declaration)
End Structure
Private Const WM_USER As Integer = &H400
Private Const EM_FORMATRANGE As Integer = WM_USER + 57
Private Declare Function SendMessage Lib "USER32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wp As IntPtr, ByVal lp As IntPtr) As IntPtr
' Render the contents of the RichTextBox for printing
' Return the last character printed + 1 (printing start from this point for next page)
Public Function Print(ByVal charFrom As Integer, ByVal charTo As Integer, ByVal e As PrintPageEventArgs) As Integer
' Mark starting and ending character
Dim cRange As CHARRANGE
cRange.cpMin = charFrom
cRange.cpMax = charTo
' Calculate the area to render and print
Dim rectToPrint As RECT
rectToPrint.Top = e.MarginBounds.Top * AnInch
rectToPrint.Bottom = e.MarginBounds.Bottom * AnInch
rectToPrint.Left = e.MarginBounds.Left * AnInch
rectToPrint.Right = e.MarginBounds.Right * AnInch
' Calculate the size of the page
Dim rectPage As RECT
rectPage.Top = e.PageBounds.Top * AnInch
rectPage.Bottom = e.PageBounds.Bottom * AnInch
rectPage.Left = e.PageBounds.Left * AnInch
rectPage.Right = e.PageBounds.Right * AnInch
Dim hdc As IntPtr = e.Graphics.GetHdc()
Dim fmtRange As FORMATRANGE
fmtRange.chrg = cRange ' Indicate character from to character to
fmtRange.hdc = hdc ' Use the same DC for measuring and rendering
fmtRange.hdcTarget = hdc ' Point at printer hDC
fmtRange.rc = rectToPrint ' Indicate the area on page to print
fmtRange.rcPage = rectPage ' Indicate whole size of page
Dim res As IntPtr = IntPtr.Zero
Dim wparam As IntPtr = IntPtr.Zero
wparam = New IntPtr(1)
' Move the pointer to the FORMATRANGE structure in memory
Dim lparam As IntPtr = IntPtr.Zero
lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange))
Marshal.StructureToPtr(fmtRange, lparam, False)
' Send the rendered data for printing
res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam)
' Free the block of memory allocated
Marshal.FreeCoTaskMem(lparam)
' Release the device context handle obtained by a previous call
e.Graphics.ReleaseHdc(hdc)
' Return last + 1 character printer
Return res.ToInt32()
End Function
End Class
End Namespace
To create RichTextBoxPrintCtrl.dll, click
Build Solution on the Build menu.
Create a new Windows Application project by using Visual
Basic .NET or Visual Basic 2005.
By default, Form1.vb is created.
From the Toolbox, drag a button onto Form1. Change the Name
to btnPageSetup, and change the Text to Page
Setup.
From the Toolbox, drag another button onto Form1. Change
the Name to btnPrintPreview, and change the Text to
Print Preview.
From the Toolbox, drag another button onto Form1. Change
the Name to btnPrint, and change the Text to
Print.
In the Toolbox, double-click PrintDialog,
double-click PrintPreviewDialog, double-click
PrintDocument, and then double-click
PageSetupDialog to add these controls to Form1.
Modify the Document property of PrintDialog1,
PrintPreviewDialog1, and PageSetupDialog1 to
PrintDocument1.
On the Tools menu, click Customize
Toolbox.
Click .NET Framework Components, click
Browse, click to select
RichTextBoxPrintCtrl.dll, and then click
OK.
From the Toolbox, drag
RichTextBoxPrintCtrl onto Form1.
In the Solution Explorer, right-click
Form1.vb, and then click View
Code.
Add the following code to Class Form1:
Private checkPrint As Integer
Private Sub PrintDocument1_BeginPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint
checkPrint = 0
End Sub
Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
' Print the content of the RichTextBox. Store the last character printed.
checkPrint = RichTextBoxPrintCtrl1.Print(checkPrint, RichTextBoxPrintCtrl1.TextLength, e)
' Look for more pages
If checkPrint < RichTextBoxPrintCtrl1.TextLength Then
e.HasMorePages = True
Else
e.HasMorePages = False
End If
End Sub
Private Sub btnPageSetup_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPageSetup.Click.Click
PageSetupDialog1.ShowDialog()
End Sub
Private Sub btnPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrint.Click
If PrintDialog1.ShowDialog() = DialogResult.OK Then
PrintDocument1.Print()
End If
End Sub
Private Sub btnPrintPreview_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrintPreview.Click
PrintPreviewDialog1.ShowDialog()
End Sub
To run the application, click Start on the
Debug menu.
Type text in
RichTextBoxPrintCtrl.
To set the page settings, click Page
Setup.
To see a preview of the page, click Print
Preview.
To print the content of the
RichTextBoxPrintCtrl, click Print.