Need Third Party RTF Control for VB6 Compatible with 98/2000/NT/XP

Posted on 2005-04-09
Last Modified: 2013-11-22
I have been using the Microsoft Rich Textbox Control 6.0 (Richtx32.ocx) for printing RTF files after replacing some text. I am running into some limitations such as support for page breaks and inverted text colors. I have found some third party controls that range in price from about $250 to $500. Does anyone have any recomendations? I only need to be able to load the control with a stream of RTF text and print it. Editing and displaying text is a nice-to-have but not a requirement. No other features such file conversions are required. Budget is tight so I would like to get something at the $250 mark or lower.

Question by:zorvek (Kevin Jones)
    LVL 22

    Accepted Solution

    Try Edanmos' free RichEdit at this Link: and . It may throw a Bad Implements error on first compile. Turn off Binary compatability, compile and then turn it back on and it should then work. Also make sure you are using Vb6 and at least ServicePack 5.
    Don't forget to download and register dependencies OleLib.tlb and OleLib2.Tlb.
    If you need any help with this let me know. I have been using it for over 2 years.
    LVL 81

    Author Comment

    by:zorvek (Kevin Jones)

    The control handles page breaks better than Richtx32.ocx but not still not correctly. An inserted page break does cause a new page to be started but the line counter is not reset so the control still puts an automatic page break in where it would have been had I not inserted the page break. In other words, if I have an RTF document that is one and a half pages long then without an inserted page break the control creates an automatic break two thirds down. If I insert a page break one third down then that page break causes a new page to be started but the control still generates a page break two thirds down the document. The end result is three pages versus two.

    Do you have a work-around that solves this problem?

    Another thing I noticed is that it does not support shaded table cells.

    LVL 22

    Expert Comment

    I looked at the code in Public Sub PrintRange() and I can see that they are building an array of pages without checking for embedded page breaks. I don't have a workaround for this but I suspect it could be done by modifying the code in PrintRange.
    LVL 81

    Author Comment

    by:zorvek (Kevin Jones)
    Given my innability to find a reasonable rtf printing tool I have decided to take a different path. I also needed to text stamp and print pdf documents and, since I have found a good solution in that department, have decided to convert my existing rtf documents to pdf and go from there.

    I'll accept the reference to Edanmos' free RichEdit since others may not have as stringent requirements as I do. I also will post the workaround I developed to handle page breaks. To handle manually inserted page breaks I use my own marker I insert into the rtf text:

    Private Type tRect
       Left As Long
       Top As Long
       Right As Long
       Bottom As Long
    End Type

    Private Type tCharRange
       cpMin As Long      ' First character of range (0 for start of doc)
       cpMax As Long      ' Last character of range (-1 for end of doc)
    End Type

    Private Type tFormatRange
       hdc As Long        ' Actual DC to draw on
       hdcTarget As Long  ' Target DC for determining text formatting
       rc As tRect        ' Region of the DC to draw to (in twips)
       rcPage As tRect    ' Region of the entire DC (page size) (in twips)
       chrg As tCharRange ' Range of text to draw (see above declaration)
    End Type

    Private Const WM_USER As Long = &H400
    Private Const EM_FORMATRANGE As Long = WM_USER + 57
    Private Const EM_SETTARGETDEVICE As Long = WM_USER + 72
    Private Const PHYSICALOFFSETX As Long = 112
    Private Const PHYSICALOFFSETY As Long = 113
    Private Const mPageBreakTag = "\_PageBreak_\"

    Private Declare Function GetDeviceCaps Lib "gdi32" ( _
       ByVal hdc As Long, ByVal nIndex As Long) As Long
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
       ByVal hwnd As Long, _
       ByVal msg As Long, ByVal wp As Long, _
       lp As Any) As Long
    Private Declare Function CreateDC Lib "gdi32" Alias "CreateDCA" ( _
       ByVal lpDriverName As String, _
       ByVal lpDeviceName As String, _
       ByVal lpOutput As Long, _
       ByVal lpInitData As Long) As Long

    Public Sub PrintRTF( _
       RTFText As String, _
       rtbPrint As RichTextBox, _
       LeftMarginInches As Single, _
       TopMarginInches As Single, _
       RightMarginInches As Single, _
       BottomMarginInches As Single)

    ' Prints RTFText to default printer using the provided RichTextBox control. The control must be created on an
    ' existing form. Include the Microsoft Rich Textbox Control to access.

       Dim LeftMarginTwips As Long
       Dim TopMarginTwips As Long
       Dim RightMarginTwips As Long
       Dim BottomMarginTwips As Long
       Dim LeftOffset As Long
       Dim TopOffset As Long
       Dim LeftMargin As Long
       Dim TopMargin As Long
       Dim RightMargin As Long
       Dim BottomMargin As Long
       Dim FormatRange As tFormatRange
       Dim DrawToRect As tRect
       Dim PageRect As tRect
       Dim TextLength As Long
       Dim NextPageCharPos As Long
       Dim NextPageBreakCharPos As Long
       Dim PageBreakTagFound As Boolean

       ' Start print job
       Printer.Print Space(1)
       Printer.ScaleMode = vbTwips
       ' Convert the margins from inches to twips
       LeftMarginTwips = Printer.ScaleX(LeftMarginInches, vbInches)
       TopMarginTwips = Printer.ScaleY(TopMarginInches, vbInches)
       RightMarginTwips = Printer.ScaleX(RightMarginInches, vbInches)
       BottomMarginTwips = Printer.ScaleY(BottomMarginInches, vbInches)

       ' Get offset to printable area
       LeftOffset = Printer.ScaleX(GetDeviceCaps(Printer.hdc, PHYSICALOFFSETX), vbPixels, vbTwips)
       TopOffset = Printer.ScaleY(GetDeviceCaps(Printer.hdc, PHYSICALOFFSETY), vbPixels, vbTwips)

       ' Calculate margins
       LeftMargin = LeftMarginTwips - LeftOffset
       TopMargin = TopMarginTwips - TopOffset
       RightMargin = (Printer.Width - RightMarginTwips) - LeftOffset
       BottomMargin = (Printer.Height - BottomMarginTwips) - TopOffset

       ' Set printable area rect
       PageRect.Left = 0
       PageRect.Top = 0
       PageRect.Right = Printer.ScaleWidth
       PageRect.Bottom = Printer.ScaleHeight

       ' Set rect in which to print which is relative to printable area
       DrawToRect.Left = LeftMargin
       DrawToRect.Top = TopMargin
       DrawToRect.Right = RightMargin
       DrawToRect.Bottom = BottomMargin

       ' Set up the print instructions
       FormatRange.hdc = Printer.hdc
       FormatRange.hdcTarget = Printer.hdc
       FormatRange.rc = DrawToRect
       FormatRange.rcPage = PageRect
       FormatRange.chrg.cpMin = 0
       FormatRange.chrg.cpMax = -1

       ' Get length of text in RTF control
       TextLength = Len(rtbPrint.Text)
       ' Print each page until done
          PageBreakTagFound = False
          NextPageBreakCharPos = InStr(FormatRange.chrg.cpMin + 1, rtbPrint.Text, mPageBreakTag)
          If NextPageBreakCharPos > 0 Then
             ' Inserted page break found
             PageBreakTagFound = True
             ' Instruct control to only print to that point
             FormatRange.chrg.cpMax = NextPageBreakCharPos - 1
             ' Move back over line feeds and carraige returns
             While Mid(rtbPrint.Text, FormatRange.chrg.cpMax + 1, 1) = vbCr Or Mid(rtbPrint.Text, FormatRange.chrg.cpMax + 1, 1) = vbLf
                FormatRange.chrg.cpMax = FormatRange.chrg.cpMax - 1
             ' Instruct control to print to end of document of page, whichever is first
             FormatRange.chrg.cpMax = -1
          End If
          ' Print the page by sending EM_FORMATRANGE message; Message returns next character position to print
          NextPageCharPos = SendMessage(rtbPrint.hwnd, EM_FORMATRANGE, True, FormatRange)
          ' If next character is beyond end of document then exit loop
          If NextPageCharPos >= TextLength Then Exit Do
          ' Next start is after inserted page break or after end of last printed page, whichever is first
          FormatRange.chrg.cpMin = IIf(PageBreakTagFound, NextPageBreakCharPos + Len(mPageBreakTag) - 1, NextPageCharPos)
          ' Skip any line feeds and carraige returns
          While Mid(rtbPrint.Text, FormatRange.chrg.cpMin + 1, 1) = vbCr Or Mid(rtbPrint.Text, FormatRange.chrg.cpMin + 1, 1) = vbLf
             FormatRange.chrg.cpMin = FormatRange.chrg.cpMin + 1
          ' Start new page
          ' Initialize hDC
          Printer.Print Space(1)
          FormatRange.hdc = Printer.hdc
          FormatRange.hdcTarget = Printer.hdc

       ' Commit job

       ' Free memory
       SendMessage rtbPrint.hwnd, EM_FORMATRANGE, False, ByVal CLng(0)

    End Sub


    Featured Post

    Maximize Your Threat Intelligence Reporting

    Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

    Join & Write a Comment

    Introduction While answering a recent question ( in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
    Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
    Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
    Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

    730 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    15 Experts available now in Live!

    Get 1:1 Help Now