Results 1 to 5 of 5

Thread: [RESOLVED] Modified printout from an RTB.

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2007
    Location
    Middletown, CT
    Posts
    948

    Resolved [RESOLVED] Modified printout from an RTB.

    Hey there everyone.

    This forum has always provided me amazing guidance and help, and I have all the faith that you guys will be able to figure this problem out again. I'm just beyond stumped.

    I was able to modify the RTB print function that's available all over the forum to print the text from a RTB. Unfortunately, I had to make the printout look slightly more professional, which required modifying the stable routine.

    Problem is, when a printout with a large number of pages prints, it does REALLY funky stuff. It doesn't do said funky stuff with a short printout (about 4 pages or so), but it does with a higher numbered one. I can't figure out where my inconsistancy lies. Can anyone help?

    See attachments for the before-I-messed-with-it-code and after, and the modified code below:
    Before: before.pdf
    After: after.pdf

    Notice that the "key" that the program looks for is the term "Container ". I plan to change the report slightly so that it doesn't break at awkward intervals, but here's an example of the screwy version:

    fixtest 6 (09-0189) BIGGER.pdf


    Ignore the first blank page - that's not part of the issue. It's just a result of messing with code as the sub was running. The problem becomes noticable on page 3, and becomes deathly obvious on page 5.


    Any ideas at all would be helpful. I've been trying to nail this issue for a week


    vb Code:
    1. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    2.    '
    3.    ' PrintRTF - Prints the contents of a RichTextBox control on the default printer using the
    4.    '            provided margins
    5.    '
    6.    ' RTF - A RichTextBox control to print
    7.    '
    8.    ' LeftMarginWidth - Width of desired left margin in twips
    9.    '
    10.    ' TopMarginHeight - Height of desired top margin in twips
    11.    '
    12.    ' RightMarginWidth - Width of desired right margin in twips
    13.    '
    14.    ' BottomMarginHeight - Height of desired bottom margin in twips
    15.    '
    16.    ' Notes - If you are also using WYSIWYG_RTF() on the provided RTF
    17.    '         parameter you should specify the same LeftMarginWidth and
    18.    '         RightMarginWidth that you used to call WYSIWYG_RTF()
    19.    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    20.    Public Sub PrintRTF(RTF As RichTextBox, LeftMarginWidth As Long, _
    21.       TopMarginHeight, RightMarginWidth, BottomMarginHeight)
    22.       Dim LeftOffset As Long, TopOffset As Long
    23.       Dim LeftMargin As Long, TopMargin As Long
    24.       Dim RightMargin As Long, BottomMargin As Long
    25.       Dim fr As FormatRange
    26.       Dim rcDrawTo As RECT
    27.       Dim rcPage As RECT
    28.       Dim TextLength As Long
    29.       Dim NextCharPosition As Long
    30.      
    31.       Dim vl_LastContainerPos_lng As Long
    32.       Dim vl_ContainerPos_lng As Long
    33.       Dim vl_PotentialPgBreakPos_lng As Long
    34.       Dim vl_CurrentPage_int As Integer
    35.       Dim r As Long
    36.  
    37.       ' Start a print job to get a valid Printer.hDC
    38.    On Error GoTo PrintRTF_Error
    39.    Stack.Push "PrintRTF"
    40.  
    41.       Printer.Print Space(1)
    42.       Printer.ScaleMode = vbTwips
    43.  
    44.       ' Get the offsett to the printable area on the page in twips
    45.       LeftOffset = Printer.ScaleX(GetDeviceCaps(Printer.hdc, _
    46.          PHYSICALOFFSETX), vbPixels, vbTwips)
    47.       TopOffset = Printer.ScaleY(GetDeviceCaps(Printer.hdc, _
    48.          PHYSICALOFFSETY), vbPixels, vbTwips)
    49.  
    50.       ' Calculate the Left, Top, Right, and Bottom margins
    51.       LeftMargin = LeftMarginWidth - LeftOffset
    52.       TopMargin = TopMarginHeight - TopOffset
    53.       RightMargin = (Printer.Width - RightMarginWidth) - LeftOffset
    54.       BottomMargin = (Printer.Height - BottomMarginHeight) - TopOffset
    55.  
    56.       ' Set printable area rect
    57.       rcPage.Left = 0
    58.       rcPage.Top = 0
    59.       rcPage.Right = Printer.ScaleWidth
    60.       rcPage.Bottom = Printer.ScaleHeight
    61.  
    62.       ' Set rect in which to print (relative to printable area)
    63.       rcDrawTo.Left = LeftMargin
    64.       rcDrawTo.Top = TopMargin
    65.       rcDrawTo.Right = RightMargin
    66.       rcDrawTo.Bottom = BottomMargin
    67.  
    68.       ' Set up the print instructions
    69.       fr.hdc = Printer.hdc   ' Use the same DC for measuring and rendering
    70.       fr.hdcTarget = Printer.hdc  ' Point at printer hDC
    71.       fr.rc = rcDrawTo            ' Indicate the area on page to draw to
    72.       fr.rcPage = rcPage          ' Indicate entire size of page
    73.       fr.chrg.cpMin = 0           ' Indicate start of text through
    74.       fr.chrg.cpMax = -1          ' end of the text
    75.    
    76.       ' Get length of text in RTF
    77.       TextLength = Len(RTF.Text)
    78.  
    79.     vl_CurrentPage_int = 0
    80.    
    81.         'This next bit of code is a bit confusing.
    82.         'It was used as an attempt to prevent "orphan" paragraphs. The page had to be divided
    83.         'into sections denoted by the ". Then, each page had to be rendered,
    84.         'the next break found, and the page break moved if necessary. Each page break was two parts:
    85.         'the cpMin parameter of the next page, and the cpMax parameter of the current page.
    86.         'Therefore, we had to go through the following steps:
    87.         '       -Rendering the page
    88.         '       -Determine if any CP_PAGEBREAKCHAR_STRs were present between this page and the next (half on this page)
    89.         '       -Adjsut the break if necessary
    90.                
    91.       ' Loop printing each page until done
    92.         Do
    93.        
    94.           'Increment the page counter to keep track of the current page
    95.           vl_CurrentPage_int = vl_CurrentPage_int + 1
    96.          
    97.          
    98.           'Render the page and record the "proposed" end
    99.            vl_PotentialPgBreakPos_lng = SendMessage( _
    100.                     RTF.hWnd, _
    101.                     EM_FORMATRANGE, _
    102.                     False, _
    103.                     fr)
    104.           'If the proposed printout is only one page long, no further processing needs to occur.
    105.           'We can determine if the printout is only one page long by testing if the potential page break position
    106.             'ís greater than the text length.
    107.            
    108.             If vl_PotentialPgBreakPos_lng < TextLength Then
    109.                 'In this case, there is definately more than one page, so the printout shouldn't have an issue.
    110.                 'We have to check if there is more than one page to avoid page breaks that are the only container on a page.
    111.                
    112.                 'See if there are any key characters in between the last position and the proposed page break
    113.                 'The easiest way to do this is to look for the key characters until the page is either reached or exceeded.
    114.                 'If one of those conditions are met, then set the new page break position.
    115.                 vl_LastContainerPos_lng = fr.chrg.cpMin + 1
    116.                 Do
    117.                       vl_ContainerPos_lng = InStr(vl_LastContainerPos_lng + 2, RTF.Text, CP_PAGEBREAKCHAR_STR, vbBinaryCompare)
    118.                      
    119.                       'There will only be a few situations following this instr operation:
    120.                      
    121.                       'The key characters will be found farther than the limit (result of instr >proposed limit)
    122.                       If vl_ContainerPos_lng >= vl_PotentialPgBreakPos_lng Then
    123.                             'ín which case', we just have to set the maximum to the previously found key character and exit the loop
    124.                             fr.chrg.cpMax = vl_LastContainerPos_lng - 1
    125.                             Exit Do
    126.                       ElseIf (vl_ContainerPos_lng = 0) And (vl_CurrentPage_int = 1) Then
    127.                           fr.chrg.cpMax = vl_LastContainerPos_lng - 1
    128.                           Exit Do
    129.                       'There will be no more instances of the key chracters after the page break, (result of instr = -1)
    130.                       ElseIf vl_ContainerPos_lng = 0 Then
    131.                             'in which case, the current stopping position is fine, and the loop can be exited.
    132.                             Exit Do
    133.                       'Or, there will be more searching to do
    134.                       Else
    135.                           vl_LastContainerPos_lng = vl_ContainerPos_lng
    136.                       End If
    137.                 Loop
    138.            
    139.             End If
    140.  
    141.          ' Print the page by sending EM_FORMATRANGE message
    142.          NextCharPosition = SendMessage(RTF.hWnd, _
    143.              EM_FORMATRANGE, True, fr)
    144.        
    145.          If NextCharPosition >= TextLength Then Exit Do  'If done then exit
    146.          
    147.          Printer.NewPage                  ' Move on to next page
    148.          Printer.Print Space(1) ' Re-initialize hDC
    149.          fr.hdc = Printer.hdc
    150.          fr.hdcTarget = Printer.hdc
    151.          fr.chrg.cpMin = NextCharPosition
    152.          fr.chrg.cpMax = -1
    153.       Loop
    154.  
    155.       ' Commit the print job
    156.       Printer.EndDoc
    157.  
    158.       ' Allow the RTF to free up memory
    159.       r = SendMessage(RTF.hWnd, EM_FORMATRANGE, False, ByVal _
    160. CLng(0))
    161.  
    162.    On Error GoTo 0
    163.    Stack.Pop
    164.    Exit Sub
    165.  
    166. PrintRTF_Error:
    167.  
    168. ErrHandler "Print", "Module", "PrintRTF", Erl
    169.    End Sub

  2. #2
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Modified printout from an RTB.

    It took me a while to get my head around the code enough, but I think I've found the issue - and a manual check with the ruler in my PDF viewer seems to validate my theory.

    You use SendMessage/EM_FORMATRANGE with fr to detect the printable size, do your checks and modify fr.chrg.cpMax, and then call SendMessage/EM_FORMATRANGE again to print... and repeat the whole thing as need.

    What seems to be missing is a reset of fr.chrg.cpMax, as presumably keeping the modified value will mean that you have effectively shrunk the page size.



    edit: oh pants! I just had another quick look, and I see you do reset it inside the loop!

    Maybe you also need to reset fr.rc and fr.rcPage ?

  3. #3

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2007
    Location
    Middletown, CT
    Posts
    948

    Re: Modified printout from an RTB.

    Yeah, it took me about a half hour to get a basic understanding of what the code did, and I'm still workin on how to properly modify it.

    Following your suggestion, I put a watch on fr and a breakpoint right after the second EM_FORMATRANGE call. Lo and bohold! The fr.rc.bottom parameter got smaller and smaller each time, eventually becoming 360. fr.rcPage didn't change at all. Since 360 twips is an intagable print size, I think we've got our problem solved.


    Upon testing. Things print beautifully. Thanks so much! What made you think of that?

    I'm also curious why the parameter changes. I notice that nowhere in the local MSDN does the EM_FORMATRANGE message mention ANYTHING about changing that parameter, but it seems to change with each pass. My guess is that the EM_FORMATRANGE function changes it to the actual print area, requiring me to say fr.rc = rcDrawTo at the end of each loop. Have you noticed this to be a trend with API messages? If so, I'll just get myself in the mindset to expect things like this more often.
    Last edited by drag0n_45; Nov 18th, 2009 at 09:17 AM.

  4. #4
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Modified printout from an RTB.

    A few API's modify the parameters you pass them, and if so it usually says so in the documentation on MSDN... but not in this case unfortunately (presumably because it is a message rather than an API).

    As the printed page length did appear to be decreasing, and your code was only altering rc in ways that wouldn't cause it, a modification by the API routine you were calling was the prime suspect.

  5. #5

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2007
    Location
    Middletown, CT
    Posts
    948

    Re: Modified printout from an RTB.

    Makes sense. thanks again! Another set of eyes is always helpful.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width