User Tools

Site Tools


development:net:wysiwyg_print_rtf

Adding wysiwyg printing ability to richtextbox

This allows you to print the contents of a RichTetBox in a WYSIWYG manner.

Create a new class that inherits RichTextBox and type in the code:

Imports System
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Drawing.Printing
 
Public Class RichTextBoxEx
    Inherits RichTextBox
    <StructLayout(LayoutKind.Sequential)> Private Structure STRUCT_RECT
        Public left As Int32
        Public top As Int32
        Public right As Int32
        Public bottom As Int32
    End Structure
 
    <StructLayout(LayoutKind.Sequential)> Private Structure STRUCT_CHARRANGE
        Public cpMin As Int32
        Public cpMax As Int32
    End Structure
 
    <StructLayout(LayoutKind.Sequential)> Private Structure STRUCT_FORMATRANGE
        Public hdc As IntPtr
        Public hdcTarget As IntPtr
        Public rc As STRUCT_RECT
        Public rcPage As STRUCT_RECT
        Public chrg As STRUCT_CHARRANGE
    End Structure
 
    <DllImport("user32.dll")> Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Int32, ByVal wParam As Int32, ByVal lParam As IntPtr) As Int32
    End Function
 
    Private Const WM_USER As Int32 = &H400&
    Private Const EM_FORMATRANGE As Int32 = WM_USER + 57
 
    Public Function FormatRange(ByVal measureOnly As Boolean, _
                                ByVal e As PrintPageEventArgs, _
                                ByVal charFrom As Integer, _
                                ByVal charTo As Integer) As Integer
 
        Dim cr As STRUCT_CHARRANGE
        cr.cpMin = charFrom
        cr.cpMax = charTo
 
        Dim rc As STRUCT_RECT
        rc.top = HundredthInchToTwips(e.MarginBounds.Top)
        rc.bottom = HundredthInchToTwips(e.MarginBounds.Bottom)
        rc.left = HundredthInchToTwips(e.MarginBounds.Left)
        rc.right = HundredthInchToTwips(e.MarginBounds.Right)
 
        Dim rcPage As STRUCT_RECT
        rcPage.top = HundredthInchToTwips(e.PageBounds.Top)
        rcPage.bottom = HundredthInchToTwips(e.PageBounds.Bottom)
        rcPage.left = HundredthInchToTwips(e.PageBounds.Left)
        rcPage.right = HundredthInchToTwips(e.PageBounds.Right)
 
        Dim hdc As IntPtr
        hdc = e.Graphics.GetHdc()
 
        Dim fr As STRUCT_FORMATRANGE
        fr.chrg = cr
        fr.hdc = hdc
        fr.hdcTarget = hdc
        fr.rc = rc
        fr.rcPage = rcPage
 
        Dim wParam As Int32
        If measureOnly Then
            wParam = 0
        Else
            wParam = 1
        End If
 
        Dim lParam As IntPtr
        lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fr))
        Marshal.StructureToPtr(fr, lParam, False)
 
        Dim res As Integer
        res = SendMessage(Handle, EM_FORMATRANGE, wParam, lParam)
 
        Marshal.FreeCoTaskMem(lParam)
 
        e.Graphics.ReleaseHdc(hdc)
 
        Return res
    End Function
 
    Private Function HundredthInchToTwips(ByVal n As Integer) As Int32
        Return Convert.ToInt32(n * 14.4)
    End Function
 
    Public Sub FormatRangeDone()
        Dim lParam As New IntPtr(0)
        SendMessage(Handle, EM_FORMATRANGE, 0, lParam)
    End Sub
 
    <StructLayout(LayoutKind.Sequential)> Private Structure STRUCT_CHARFORMAT
        Public cbSize As Integer
        Public dwMask As UInt32
        Public dwEffects As UInt32
        Public yHeight As Int32
        Public yOffset As Int32
        Public crTextColor As Int32
        Public bCharSet As Byte
        Public bPitchAndFamily As Byte
        <MarshalAs(UnmanagedType.ByValArray, SizeConst:=32)> _
        Public szFaceName As Char()
    End Structure
End Class

And use this code to do the actual printing:

Private Sub ToolPrint_Click(sender As System.Object, e As System.EventArgs) Handles ToolPrint.Click
Dim printDoc As New Printing.PrintDocument()
AddHandler printDoc.BeginPrint, AddressOf printDoc_BeginPrint
AddHandler printDoc.PrintPage, AddressOf printDoc_PrintPage
AddHandler printDoc.EndPrint, AddressOf printDoc_EndPrint
printDoc.Print()
End Sub
Private m_nFirstCharOnPage As Integer

Private Sub printDoc_BeginPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs)
m_nFirstCharOnPage = 0
End Sub

Private Sub printDoc_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)

m_nFirstCharOnPage = RTBe.FormatRange(False, e, m_nFirstCharOnPage, RTBe.TextLength)

If (m_nFirstCharOnPage &lt; RTBe.TextLength) Then
e.HasMorePages = True
Else
e.HasMorePages = False
End If
End Sub

Private Sub printDoc_EndPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs)
RTBe.FormatRangeDone()
End Sub
development/net/wysiwyg_print_rtf.txt · Last modified: 2017/11/23 10:47 by tplecko