Imports System.Runtime.InteropServices
Imports System.Drawing.Printing

' http://support.microsoft.com/kb/812425

Public Class PrintableRichTextBox
    Inherits RichTextBox

    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
        Public cpMax As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)>
    Private Structure FORMATRANGE
        Public hdc As IntPtr
        Public hdcTarget As IntPtr
        Public rc As RECT
        Public rcPage As RECT
        Public chrg As CHARRANGE
    End Structure

    Private Const WM_USER As Integer = &H400
    Private Const EM_FORMATRANGE = WM_USER + 57

    <DllImport("USER32.dll")>
    Private Shared Function SendMessage(hWnd As IntPtr, msg As Integer, wp As IntPtr, lp As IntPtr) As IntPtr

    End Function

    Public Function Print(charForm As Integer, charTo As Integer, e As PrintPageEventArgs)
        Dim rectToPrint As RECT
        rectToPrint.Top = CInt(e.MarginBounds.Top * anInch)
        rectToPrint.Bottom = CInt(e.MarginBounds.Bottom * anInch)
        rectToPrint.Left = CInt(e.MarginBounds.Left * anInch)
        rectToPrint.Right = CInt(e.MarginBounds.Right * anInch)

        Dim rectPage As RECT
        rectPage.Top = CInt(e.PageBounds.Top * anInch)
        rectPage.Bottom = CInt(e.PageBounds.Bottom * anInch)
        rectPage.Left = CInt(e.PageBounds.Left * anInch)
        rectPage.Right = CInt(e.PageBounds.Right * anInch)

        Dim hdc As IntPtr = e.Graphics.GetHdc()

        Dim fmtRange As FORMATRANGE
        fmtRange.chrg.cpMax = charTo
        fmtRange.chrg.cpMin = charForm
        fmtRange.hdc = hdc
        fmtRange.hdcTarget = hdc
        fmtRange.rc = rectToPrint
        fmtRange.rcPage = rectPage

        Dim res As IntPtr = IntPtr.Zero
        Dim wparam As IntPtr = IntPtr.Zero
        wparam = New IntPtr(1)

        Dim lparam As IntPtr = IntPtr.Zero
        lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange))
        Marshal.StructureToPtr(fmtRange, lparam, False)

        res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam)

        Marshal.FreeCoTaskMem(lparam)

        e.Graphics.ReleaseHdc(lparam)

        Return res.ToInt32()
    End Function
End Class
