'===========================================================================
' Subject: RTF COMMON CONTROL FUNCTIONS       Date: 12-09-98 (14:35)       
'  Author: Don Dickinson                      Code: PBDLL                  
'  Origin: ddickinson@usinternet.com        Packet: PBDLL.ABC
'===========================================================================
'
'  RTFFUNCT.BAS
'
'  Rich Edit Common Control Function Wrappers for PB/DLL 5.
'
'     PrintRichTextBox     Prints the contents of a rich text box
'     SetRTFText           Fills a rich edit box from an rtf or text file
'     SaveRTFText          Saves the contents of a rich edit box as an RTF file
'
'  Last Revision:    Jan. 1998
'
'  Written by:       Don Dickinson
'                    ddickinson@usinternet.com
'                    http://ourworld.compuserve.com/homepages/ddickinson
'
'  This module is free for public use without acknowledging the
'  author - Don Dickinson. It is provided, as is, for use and abuse.
'  Use at your own risk. The author assumes no responsibility
'  for any effects or side-effects of using this code.
'
'  Requires WIN32API.INC
'
'  Function Forwards
'
DECLARE SUB PrintRichTextBox( hWnd AS LONG, hInst AS LONG, rtfEdit AS LONG, LM AS SINGLE, _
                              RM AS SINGLE, TM AS SINGLE, BM AS SINGLE )
DECLARE FUNCTION SetRTFText( rtfEdit AS LONG, _
                             sFileName AS STRING, iAttrib AS INTEGER ) AS INTEGER
DECLARE FUNCTION ReadStreamCallback( BYVAL dwCookie AS DWORD, _
                                     pbBuffer AS BYTE PTR, _
                                     BYVAL cb AS LONG, _
                                     pcb AS LONG ) AS DWORD
DECLARE FUNCTION SaveRTFText( rtfEdit AS LONG, sFileName AS STRING ) AS INTEGER
DECLARE FUNCTION WriteStreamCallback( BYVAL dwCookie AS DWORD, _
                                      pbBuffer AS BYTE PTR, _
                                      BYVAL cb AS LONG, _
                                      pcb AS LONG ) AS DWORD
'========================================================================================
SUB PrintRichTextBox( hWnd AS LONG, hInst AS LONG, rtfEdit AS LONG, LM AS SINGLE, _
                      RM AS SINGLE, TM AS SINGLE, BM AS SINGLE )
   '
   '  Purpose:
   '           Prints the contents of an RTF text box given it's handle, the
   '           calling program's handle(s), and the page margins.
   '
   '  Parameters:
   '           hWnd     = Parent window (used for print common dlg)
   '           hInst    = Instance of calling program
   '           rtfEdit  = Handle of rich edit control
   '           LM       = Left Margin in inches
   '           RM       = Right Margin in inches
   '           TM       = Top Margin in inches
   '           BM       = Bottom Margin in inches
   '
  DIM fr AS FORMATRANGE
  DIM rDocInfo AS DOCINFO
  DIM iTextOut AS LONG
  DIM iTextAmt AS LONG
  DIM pd AS PRINTDLGAPI
  DIM zString AS ASCIIZ * 200
  DIM iWidthTwips&
  DIM iHeightTwips&
   '- Setup the print common dialog
  pd.lStructSize = LEN( pd )
  pd.hwndOwner = hWnd
  pd.hDevMode = %NULL
  pd.hDevNames = %NULL
  pd.nFromPage = 0
  pd.nToPage = 0
  pd.nMinPage = 0
  pd.nMaxPage = 0
  pd.nCopies = 0
  pd.hInstance = hInst
  pd.Flags = %PD_RETURNDC OR %PD_NOPAGENUMS OR %PD_PRINTSETUP
  pd.lpfnSetupHook = %NULL
  pd.lpPrintSetupTemplateName = %NULL
  pd.lpfnPrintHook = %NULL
  pd.lpPrintTemplateName = %NULL

  IF PrintDlg( pd ) THEN
    SetCursor LoadCursor( %NULL, BYVAL %IDC_WAIT )
      '- Fill format range structure
      '
      '  NOTE:
      '     This gave me fits. I was looking at the book from
      '     Microsoft Press called Programming the Windows 95
      '     Iterface. It said (via example) that the
      '     Rectagle was defined in Pixels. This didn't work right.
      '     The SDK, however, said the measurements needed to be
      '     in Twips! This seems to work fine.
      '
      '
    fr.hdc = pd.hDC
    fr.hdcTarget = pd.hDC
    fr.chrg.cpMin = 0
    fr.chrg.cpMax = - 1
    fr.rc.nTop = TM * 1440
    fr.rcPage.nTop = fr.rc.nTop
    fr.rc.nLeft = LM * 1440
    fr.rcPage.nLeft = fr.rc.nLeft
      '- Get page dimensions in Twips
    iWidthTwips& = INT(( GetDeviceCaps( pd.hDC, %HORZRES ) / GetDeviceCaps( pd.hDC, %LOGPIXELSX )) * 1440 )
    iHeightTwips& = INT(( GetDeviceCaps( pd.hDC, %VERTRES ) / GetDeviceCaps( pd.hDC, %LOGPIXELSY )) * 1440 )
    fr.rc.nRight = iWidthTwips& - RM * 1440
    fr.rcPage.nRight = fr.rc.nRight
    fr.rc.nBottom = iHeightTwips& - BM * 1440
    fr.rcPage.nBottom = fr.rc.nBottom
      '- Fill rDocInfo structure
    rDocInfo.cbSize = LEN( rDocInfo )
    zString = "RTF Printer"
    rDocInfo.lpszDocName = VARPTR( zString )
    rDocInfo.lpszOutput = %NULL
      '- Here we go
    StartDoc pd.hDC, rDocInfo
    StartPage pd.hDC
      '- This does the printing. We send messages
      '  to the edit box telling it to format it's
      '  text to fit the Printer's DC.
      '
    iTextOut = 0
    iTextAmt = SendMessage( rtfEdit, %WM_GETTEXTLENGTH, 0, 0 )

    DO WHILE iTextOut < iTextAmt
      iTextOut = SendMessage( rtfEdit, %EM_FORMATRANGE, _
      1, VARPTR( fr ))
      IF iTextOut < iTextAmt THEN
        EndPage pd.hDC
        StartPage pd.hDC
        fr.chrg.cpMin = iTextOut
        fr.chrg.cpMax = - 1
      END IF
    LOOP

    SendMessage rtfEdit, %EM_FORMATRANGE, 1, %NULL
      '- Finish the printing.
    EndPage pd.hDC
    EndDoc pd.hDC
    DeleteDC pd.hDC
    SetCursor LoadCursor( %NULL, BYVAL %IDC_ARROW )
  ELSE
        ' MsgBox "Canceled !"
  END IF

END SUB
'========================================================================================
FUNCTION SetRTFText( rtfEdit AS LONG, sFileName AS STRING, iAttrib AS INTEGER ) AS INTEGER
   '
   '  Purpose:
   '           Loads an RTF control with the contents of an RTF file given
   '           the control's window handle and the name of the file.
   '
   '  Parameters:
   '           rtfEdit     =  Handle of a rich edit control
   '           sFileName   =  File name to read
   '           iAttrib     =  Either %SF_TEXT or %SF_RTF - specifies the
   '                          type of file to be read.
   '
   '  Returns:
   '           %True on success
   '           %False if failure
   '
  DIM hFile AS LONG
  DIM eStream AS EDITSTREAM
  DIM ofS AS OFSTRUCT
  ON ERROR RESUME NEXT
  hFile = FREEFILE
  OPEN sFileName FOR BINARY AS #hFile
  IF ERR THEN
        '- unable to open file
    FUNCTION = %False
  ELSE
    eStream.dwCookie = hFile
    eStream.pfnCallback = CODEPTR( ReadStreamCallback )
    eStream.dwError = 0
    SendMessage rtfEdit, %EM_STREAMIN, iAttrib, VARPTR( eStream )
      '- The text box is dirty now ...
    SendMessage rtfEdit, %EM_SETMODIFY, 1, 0
    CLOSE #hFile
    FUNCTION = %True
  END IF
END FUNCTION
'========================================================================================
FUNCTION ReadStreamCallback( BYVAL dwCookie AS DWORD, _
                             pbBuffer AS BYTE PTR, _
                             BYVAL cb AS LONG, _
                             pcb AS LONG ) AS DWORD
  DIM rOver AS OVERLAPPED
  DIM sInput AS STRING
  DIM iBuf AS LONG
  DIM iCopyLen AS LONG
   '- Find out if the amount requested is
   '  beyond the end of the file.
   '
  IF LOF( dwCookie ) - LOC( dwCookie ) < 0 THEN
    iCopyLen = LOF( dwCookie ) - LOC( dwCookie )
  ELSE
    iCopyLen = cb
  END IF
  sInput = SPACE$( iCopyLen )
   '- Incoming data
  GET #dwCookie,, sInput
  pcb = iCopyLen
   '- Yes, this is sort of slow, but
   '  I just whipped this together. You
   '  could use rtlCopyMemory to transfer
   '  the memory more quickly, but I can't
   '  remember it's syntax, so I'll use pointers.
   '
  FOR iBuf = 0 TO iCopyLen - 1
    @pbBuffer = ASC( MID$( sInput, iBuf + 1, 1 ))
    pbBuffer = pbBuffer + 1
  NEXT iBuf
   '- I always return 0. This if non-zero is returned,
   '  it indicates an error occured. For a "real-application"
   '  you probably want to check err for a read error
   '  during the Get operation.
   '
   '  The edit control itself will stop calling this call-back
   '  if one of the following occurs ...
   '
   '     1. Non-zero is returned
   '     2. zero returned in pcb
   '     3. pcb is less than cb upon return
   '     4. an error occurs transferring data into buffer (out
   '        of memory, etc.)
   '     5. rtf data is invalid.
   '     6. If the edit control is single line and a
   '        crlf pair is copied into the buffer.
   '
  FUNCTION = 0
END FUNCTION
'========================================================================================
FUNCTION SaveRTFText( rtfEdit AS LONG, sFileName AS STRING ) AS INTEGER
   '
   '  Purpose:
   '           Saves the contents of an RTF control to an RTF file given
   '           it's file name and the handle of the control.
   '
   '  Parameters:
   '           rtfEdit     = The handle of the RTF control
   '           sFileName   = The name of the output file.
   '
   '  Returns:
   '           %True if successful
   '           %False otherwise
   '
  DIM hFile AS LONG
  DIM eStream AS EDITSTREAM
  DIM ofS AS OFSTRUCT
  ON ERROR RESUME NEXT
  hFile = FREEFILE
  OPEN sFileName FOR BINARY AS #hFile
  IF ERR THEN
    FUNCTION = %False
  ELSE
    eStream.dwCookie = hFile
    eStream.dwError = 0
    eStream.pfnCallback = CODEPTR( WriteStreamCallback )
    SendMessage rtfEdit, %EM_STREAMOUT, %SF_RTF, VARPTR( eStream )
    FUNCTION = %True
  END IF
END FUNCTION
'========================================================================================
FUNCTION WriteStreamCallback( BYVAL dwCookie AS DWORD, _
                              pbBuffer AS BYTE PTR, _
                              BYVAL cb AS LONG, _
                              pcb AS LONG ) AS DWORD
  DIM sOutput AS STRING
  DIM i AS LONG
  DIM ptrBuffer AS BYTE PTR
  DIM ptrInput AS BYTE PTR
  sOutput = SPACE$( cb )
  ptrBuffer = STRPTR( sOutput )
  ptrInput = pbBuffer
  FOR i = 1 TO cb
    @ptrBuffer = @ptrInput
    INCR ptrBuffer
    INCR ptrInput
  NEXT i
  PUT #dwCookie,, sOutput
END FUNCTION
