Announcement

Collapse
No announcement yet.

Simple document printing problems

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Simple document printing problems

    Rightaway, I must mention that I have so far been unable to
    obtain a Petzold (or similar) book -- have had the Petzold one
    on order for months, but hus far no joy.

    The code below is a concoction, or cocktail, or borrowed snippets
    from bulletin board postings and the FILES &c.

    I have pasted in the relevant bits from the WinAPI help to make
    it a blow-by-blow story.

    It does not bomb our or hang: it simply does not work. I'm sure
    there is a twenty-line piece of code somewhere which will do the
    trick -- mine turns out a pristinely clean white page with
    nothing on it.

    The document to be printed is a ready created dialog (wDlg&),
    which I am attempting to get into a compatible bitmap and then
    print, but no dice.

    Can somebody help, please?
    '___________________________________________________________________________________________________________

    (This function is from a posting by Jozsef Hegyi in late August)

    Function GetPrinterDC () As Long

    Local pInfo5() As PRINTER_INFO_5,_
    dwNeeded As Long,_
    dwReturned As Long,_
    iUpper As Long,_
    pByte As Byte Ptr,_
    szNull As Asciiz*0

    pByte = VarPtr(szNull)
    Call EnumPrinters (%PRINTER_ENUM_LOCAL, ByVal %NULL, 5, @pByte, 0, dwNeeded, dwReturned)

    iUpper = dwNeeded\SizeOf(pInfo5(0))
    ReDim pInfo5(0: iUpper)
    pByte = VarPtr(pInfo5(0))
    If EnumPrinters (%PRINTER_ENUM_DEFAULT, ByVal %NULL, 5, @pByte, _
    (iUpper+1)*SizeOf(pInfo5(0)), dwNeeded, dwReturned) Then
    Function = CreateDC (ByVal %NULL, pInfo5(0)[email protected], ByVal %NULL, ByVal %NULL)
    Else
    Function = 0
    End If
    End Function
    '___________________________________________________________________________________________________________

    Sub PrintThisScreen

    Local pd As PRINTDLGAPI
    Local di As DOCINFO
    Local dn As Asciiz * 64
    Local hWnd As Long
    Local hDC As Long
    Local hBmp As Long
    Local hBmpDC As Long
    Local r As RECT
    Local x As Long
    Local y As Long
    Local bmp As Bitmap
    Local pDC As Long

    ' Create a normal DC And a memory DC For the dialog. The
    ' normal DC provides a "snapshot" of the screen contents. The
    ' memory DC keeps a copy of this "snapshot" in the associated
    ' bitmap.

    hWnd = wDlg& 'wDlg& contains the visible material to be printed)
    GetWindowRect hWnd, r
    hdcScreen& = GetDC(hWnd)

    'To store an image temporarily, your application must call CreateCompatibleDC to create
    'a DC that is compatible with the current window DC.

    hdcCompatible& = CreateCompatibleDC(hdcScreen&)

    'After you create a compatible DC, you create a bitmap with the appropriate dimensions
    'by calling the CreateCompatibleBitmap function and then select it into this device
    'context by calling the SelectObject function.
    ' Create a compatible bitmap For hdcScreen.

    hbmScreen& = CreateCompatibleBitmap(hdcScreen&, _
    GetDeviceCaps(hdcScreen&, %HORZRES), _
    GetDeviceCaps(hdcScreen&, %VERTRES))

    If hbmScreen& = 0 Then
    MsgBox("hbmScreen& is at zero")
    DeleteDC hdcScreen&
    Exit Sub
    End If

    ' Select the bitmap into the compatible DC.

    Call SelectObject(hdcCompatible&, hbmScreen&)

    'After the compatible device context is created and the appropriate bitmap has been
    'selected into it, you can capture the image.

    'The Win32 API provides the BitBlt function to capture images. This function
    'performs a bit block transfer - that is, it copies data from a source bitmap
    'into a destination bitmap.

    'Because it copies data from bitmaps, you'd expect that two arguments to this
    'function would be bitmap handles; however, this is not the case. Instead,
    'BitBlt receives handles that identify two device contexts and copies the
    'bitmap data from a bitmap selected into the source DC into a bitmap
    'selected into the target DC. In this case, the target DC is the compatible
    'DC, so when BitBlt completes the transfer, the image has been stored in memory.

    ' Copy data for the selected display into a
    ' bitmap that is selected into a compatible DC.

    ' Call ShowWindow (hwnd, %SW_HIDE)

    GetObject hbmScreen&, SizeOf(bmp), bmp

    Call BitBlt(hdcCompatible&, _
    0,0, _
    bmp.bmWidth, bmp.bmHeight, _
    hdcScreen&, _
    0,0, _
    %SRCCOPY)

    ' pd.lStructSize = SizeOf(pd)
    ' pd.Flags = %PD_NOSELECTION Or %PD_NOPAGENUMS Or %PD_USEDEVMODECOPIES Or %PD_RETURNDC
    ' pd.hWndOwner = hWnd '%HWND_DESKTOP

    pd.lStructSize = SizeOf(pd)
    pd.hDevMode = %Null '(Handle) %Null
    pd.hDevNames = %Null '(Handle) %Null
    pd.Flags = %PD_RETURNDC
    pd.hwndOwner = hwnd
    pd.hDC = %Null '(HDC) %Null
    pd.nFromPage = 1
    pd.nToPage = 1
    pd.nMinPage = 0
    pd.nMaxPage = 0
    pd.nCopies = 1
    pd.hInstance = %Null '(Handle) %Null
    ' pd.lCustData = 0L
    ' pd.lpfnPrintHook = (LPPRINTHOOKPROC) %Null
    ' pd.lpfnSetupHook = (LPSETUPHOOKPROC) %Null
    ' pd.lpPrintTemplateName = %Null '(%LPSTR) %Null
    ' pd.lpSetupTemplateName = %Null '(%LPSTR) %Null
    ' pd.hPrintTemplate = %Null '(Handle) %Null
    ' pd.hSetupTemplate = %Null '(Handle) %Null

    ' Display the Print Dialog box.

    ' PrintDlg(pd)

    If IsFalse PrintDlg(pd) Then
    Exit Sub
    End If
    ' hBmpDC=GetPrinterDC
    ' pDC = CreateCompatibleDC(hBmpDC)

    dn = "Printer Test"
    di.cbSize = SizeOf(di)
    di.lpszDocName = VarPtr(dn)

    If StartDoc(pd.hDC, di) > 0 Then
    If StartPage(pd.hDC) <= 0 Then
    DeleteDC hDC
    DeleteDC hBmpDC
    ' DeleteDC pd.hDC
    DeleteDC hdcScreen&
    Exit Sub
    End If

    hBmpDC=pd.hDC 'GetPrinterDC
    pDC = CreateCompatibleDC(hBmpDC)

    ' x = GetDeviceCaps(pd.hDC, %HORZRES)
    ' y = CLng((x / r.nRight) * r.nBottom)

    'To redisplay the image, call BitBlt a second time, specifying the compatible DC
    'as the source DC and a window (or printer) DC as the target DC.

    Call BitBlt(pDC, _
    0,0, _
    bmp.bmWidth, bmp.bmHeight, _
    hdcCompatible&, _
    0,0, _
    %SRCCOPY)

    If EndPage(pd.hDC) <= 0 Then
    DeleteDC hDC
    DeleteDC hBmpDC
    DeleteDC pd.hDC
    DeleteDC hdcScreen&
    Exit Sub
    End If
    End If

    EndDoc pd.hDC
    DeleteDC hDC
    DeleteDC hBmpDC
    DeleteDC pd.hDC
    DeleteDC hdcScreen&
    End Sub
    '___________________________________________________________________________________________________________

    ------------------

  • #2
    DienyduToit...

    From the sound of your request, I think this is what you are looking for...

    First you must edit your WIN32API.INC file and make sure the BITMAPINFO declaration matches the following...
    Code:
    TYPE BITMAPINFO
       bmiHeader AS BITMAPINFOHEADER
       bmiColors(256) AS RGBQUAD
    END TYPE
    Then you should be able to successfully run this code...
    Code:
    #COMPILE EXE
    #REGISTER NONE
    #INCLUDE "WIN32API.INC"
    #INCLUDE "COMDLG32.INC"
    
    
    GLOBAL hDlg      AS LONG
    GLOBAL BMPLeft   AS DOUBLE
    GLOBAL BMPTop    AS DOUBLE
    GLOBAL BMPWidth  AS DOUBLE
    GLOBAL BMPHeight AS DOUBLE
    
    
    FUNCTION SaveBMPFile() AS LONG
       LOCAL BMPFile       AS LONG
       LOCAL hBMPMem       AS LONG
       LOCAL hDC           AS LONG
       LOCAL hDCMem        AS LONG
       LOCAL BMPrc         AS RECT
       LOCAL BMP           AS BITMAP
       LOCAL BMPI          AS BITMAPINFO
       LOCAL BMPFileHeader AS BITMAPFILEHEADER
       LOCAL BMPInfoHeader AS BITMAPINFOHEADER
    
       GetWindowRect hDlg, BMPrc
    
       BMPI.bmiHeader.biSize = SIZEOF(BMPI.bmiHeader)
       BMPI.bmiHeader.biWidth = (BMPrc.nRight - BMPrc.nLeft)
       BMPI.bmiHeader.biHeight = (BMPrc.nBottom - BMPrc.nTop)
       BMPI.bmiHeader.biPlanes = 1
       BMPI.bmiHeader.biBitCount = 24
       BMPI.bmiHeader.biCompression = 0
    
       hDC = GetDC(0)
       hDCMem = CreateCompatibleDC (hDC)
       hBMPMem = CreateDIBSection(hDCMem, BMPI, 0, 0, 0, 0)
       GlobalLock hBMPMem
       SelectObject hDCMem, hBMPMem
       GetObject hBMPMem, SIZEOF(BMP), BMP
       BitBlt hDCMem, 0, 0, BMP.bmWidth, BMP.bmHeight, hDC, BMPrc.nLeft, BMPrc.nTop, %SRCCOPY
    
       BMPFileHeader.bfType = CVI("BMP")
       BMPFileHeader.bfSize = LEN(BMPFileHeader) + LEN(BMPInfoHeader) + BMP.bmWidthBytes * BMP.bmHeight
       BMPFileHeader.bfOffBits = 54
       BMPInfoHeader.biSize = 40
       BMPInfoHeader.biWidth = BMP.bmWidth
       BMPInfoHeader.biHeight = BMP.bmHeight
       BMPInfoHeader.biPlanes = 1
       BMPInfoHeader.biBitCount = 24
       BMPInfoHeader.biSizeImage = (BMP.bmWidthBytes * BMP.bmHeight) + 54
    
       BMPFile = FREEFILE
       OPEN "C:\TEMP.BMP" FOR OUTPUT AS #BMPFile
       PRINT #BMPFile, BMPFileHeader BMPInfoHeader PEEK$(BMP.bmBits, (BMP.bmWidthBytes * BMP.bmHeight));
       CLOSE #BMPFile
    
       ReleaseDC 0, hDC
       DeleteDC hDCMem
       GlobalUnlock hBMPMem
       DeleteObject hBMPMem
    END FUNCTION
    
    
    FUNCTION PrintBMPFile() AS LONG
       LOCAL X            AS LONG
       LOCAL Y            AS LONG
       LOCAL W            AS LONG
       LOCAL H            AS LONG
       LOCAL BMP          AS BITMAP
       LOCAL BMPI         AS BITMAPINFO
       LOCAL BMPMem       AS STRING
       LOCAL BMPMemPtr    AS LONG
       LOCAL BMPSize      AS LONG
       LOCAL hBMP         AS LONG
       LOCAL dcBMP        AS LONG
       LOCAL Copies       AS LONG
       LOCAL PDOptions    AS LONG
       LOCAL BMPPrinter   AS LONG
       LOCAL DocumentInfo AS DOCINFO
       LOCAL DocumentName AS ASCIIZ * 255
    
       Copies = 1
       PDOptions = %PD_COLLATE + %PD_HIDEPRINTTOFILE + %PD_NOSELECTION + %PD_PAGENUMS + %PD_RETURNDC
       PrinterDialog 0, PDOptions, BMPPrinter, Copies, 1, 1, 1, 1
       IF BMPPrinter THEN
          DocumentName = "C:\TEMP.BMP"
          DocumentInfo.lpszDocName = VARPTR(DocumentName)
          DocumentInfo.lpszOutput = 0
          StartDoc BMPPrinter, DocumentInfo
          FOR PrintLoop& = 1 TO Copies
             StartPage BMPPrinter
             X = GetDeviceCaps(BMPPrinter, %LOGPIXELSX) * BMPLeft
             Y = GetDeviceCaps(BMPPrinter, %LOGPIXELSY) * BMPTop
             W = GetDeviceCaps(BMPPrinter, %LOGPIXELSX) * BMPWidth
             H = GetDeviceCaps(BMPPrinter, %LOGPIXELSY) * BMPHeight
    
             hBMP = LoadImage(0, "C:\TEMP.BMP", %IMAGE_BITMAP, 0, 0, %LR_LOADFROMFILE)
    
             hDesktop& = GetDesktopWindow()
             dcWindow& = GetDC(hDesktop&)
             dcBMP = CreateCompatibleDC(dcWindow&)
             ReleaseDC hDesktop&, dcWindow&
             GetObject hBMP, LEN(BMP), BMP
    
             BMPI.bmiHeader.biSize = LEN(BMPI.bmiHeader)
             BMPI.bmiHeader.biWidth = BMP.bmWidth
             BMPI.bmiHeader.biHeight = BMP.bmHeight
             BMPI.bmiHeader.biPlanes = 1
             BMPI.bmiHeader.biBitCount = BMP.bmBitsPixel
             BMPI.bmiHeader.biCompression = 0
    
             BMPSize = BMPI.bmiHeader.biWidth
             BMPSize = (BMPSize + 1) * (BMPI.bmiHeader.biBitCount / 8)
             BMPSize = ((BMPSize + 3) / 4) * 4
             BMPSize = BMPSize * BMPI.bmiHeader.biHeight
             BMPMem = STRING$(BMPSize, CHR$(0))
    
             IF (BMP.bmWidth / BMP.bmHeight) > (W / H) THEN
                H = W * BMP.bmHeight / BMP.bmWidth
             ELSE
                W = H * BMP.bmWidth / BMP.bmHeight
             END IF
    
             BMPMemPtr = STRPTR(BMPMem)
    
             GetDIBits dcBMP, hBMP, 0, BMPI.bmiHeader.biHeight, BYVAL BMPMemPtr, BMPI, 0
    
             StretchDIBits BMPPrinter, X, Y, W, H, 0, 0, BMPI.bmiHeader.biWidth, _
                           BMPI.bmiHeader.biHeight, BYVAL BMPMemPtr, BMPI, 0, %SRCCOPY
    
             DeleteObject hBMP
             DeleteDC dcBMP
             BMPMem = ""
             EndPage BMPPrinter
          NEXT
          EndDoc BMPPrinter
          DeleteDC BMPPrinter
       END IF
    END FUNCTION
    
    
    CALLBACK FUNCTION DlgProc
       SELECT CASE CBCTL
       CASE 102
          SaveBMPFile
          PrintBMPFile
          KILL "C:\TEMP.BMP"
       END SELECT
    END FUNCTION
    
    
    FUNCTION PBMAIN
       BMPLeft   = 0.5  ' Where to print your dialog image... margins on paper (in inches)
       BMPTop    = 0.5
       BMPWidth  = 6.0  ' What size to print your dialog image (in inches)
       BMPHeight = 4.0
       DIALOG NEW 0, "My Dialog",,, 300, 200, %WS_SYSMENU TO hDlg
       CONTROL ADD LABEL, hDlg, 101, "Click OK to print a copy of this dialog...", 85, 60, 190, 12
       CONTROL ADD BUTTON, hDlg, 102, "OK", 130, 160, 40, 15
       DIALOG SHOW MODAL hDlg CALL DlgProc
    END FUNCTION
    Timm

    [This message has been edited by Timm Motl (edited September 30, 2000).]
    mailto:[email protected]
    Tsunami Record Manager

    Comment


    • #3
      DienyduToit...

      My first response to you gives an example of printing an image of a dialog by first
      writing it to a disk file (C:\TEMP.BMP) and then printing/deleting that file.

      This example will send the output to the printer without using a disk file. It still
      uses the Windows Print Dialog Box to let you select the number of copies to print.
      My next posting will contain an example that sends the dialog image directly to the
      current default printer without using the Windows Print Dialog Box.

      In all three of these examples, you must be sure that the BITMAPINFO declaration in
      your WIN32API.INC file matches the example I gave you in my first response.
      Code:
      #COMPILE EXE
      #REGISTER NONE
      #INCLUDE "WIN32API.INC"
      #INCLUDE "COMDLG32.INC"
      
      
      GLOBAL hDlg      AS LONG
      GLOBAL BMPLeft   AS DOUBLE
      GLOBAL BMPTop    AS DOUBLE
      GLOBAL BMPWidth  AS DOUBLE
      GLOBAL BMPHeight AS DOUBLE
      
      
      FUNCTION PrintDialog() AS LONG
         LOCAL X             AS LONG
         LOCAL Y             AS LONG
         LOCAL W             AS LONG
         LOCAL H             AS LONG
         LOCAL BMP           AS BITMAP
         LOCAL BMPI          AS BITMAPINFO
         LOCAL BMPrc         AS RECT
         LOCAL BMPMem        AS STRING
         LOCAL BMPMemPtr     AS LONG
         LOCAL BMPSize       AS LONG
         LOCAL hBMP          AS LONG
         LOCAL dcBMP         AS LONG
         LOCAL hDC           AS LONG
         LOCAL Copies        AS LONG
         LOCAL PDOptions     AS LONG
         LOCAL BMPPrinter    AS LONG
         LOCAL DocumentInfo  AS DOCINFO
         LOCAL DocumentName  AS ASCIIZ * 255
         Copies = 1
         PDOptions = %PD_COLLATE + %PD_HIDEPRINTTOFILE + %PD_NOSELECTION + %PD_PAGENUMS + %PD_RETURNDC
         PrinterDialog 0, PDOptions, BMPPrinter, Copies, 1, 1, 1, 1
         IF BMPPrinter THEN
            GetWindowText hDlg, DocumentName, 255
            DocumentInfo.lpszDocName = VARPTR(DocumentName)
            DocumentInfo.lpszOutput = 0
            StartDoc BMPPrinter, DocumentInfo
            FOR PrintLoop& = 1 TO Copies
               StartPage BMPPrinter
               X = GetDeviceCaps(BMPPrinter, %LOGPIXELSX) * BMPLeft
               Y = GetDeviceCaps(BMPPrinter, %LOGPIXELSY) * BMPTop
               W = GetDeviceCaps(BMPPrinter, %LOGPIXELSX) * BMPWidth
               H = GetDeviceCaps(BMPPrinter, %LOGPIXELSY) * BMPHeight
               GetWindowRect hDlg, BMPrc
               BMPI.bmiHeader.biSize = SIZEOF(BMPI.bmiHeader)
               BMPI.bmiHeader.biWidth = (BMPrc.nRight - BMPrc.nLeft)
               BMPI.bmiHeader.biHeight = (BMPrc.nBottom - BMPrc.nTop)
               BMPI.bmiHeader.biPlanes = 1
               BMPI.bmiHeader.biBitCount = 24
               BMPI.bmiHeader.biCompression = 0
               BMPSize = BMPI.bmiHeader.biWidth
               BMPSize = (BMPSize + 1) * (BMPI.bmiHeader.biBitCount / 8)
               BMPSize = ((BMPSize + 3) / 4) * 4
               BMPSize = BMPSize * BMPI.bmiHeader.biHeight
               BMPMem = STRING$(BMPSize, CHR$(0))
               BMPMemPtr = STRPTR(BMPMem)
               hDC = GetDC(0)
               dcBMP = CreateCompatibleDC(hDC)
               hBMP = CreateDIBSection(dcBMP, BMPI, 0, 0, 0, 0)
               GlobalLock hBMP
               SelectObject dcBMP, hBMP
               GetObject hBMP, SIZEOF(BMP), BMP
               BitBlt dcBMP, 0, 0, BMP.bmWidth, BMP.bmHeight, hDC, BMPrc.nLeft, BMPrc.nTop, %SRCCOPY
               IF (BMP.bmWidth / BMP.bmHeight) > (W / H) THEN
                  H = W * BMP.bmHeight / BMP.bmWidth
               ELSE
                  W = H * BMP.bmWidth / BMP.bmHeight
               END IF
               GetDIBits dcBMP, hBMP, 0, BMPI.bmiHeader.biHeight, BYVAL BMPMemPtr, BMPI, 0
               StretchDIBits BMPPrinter, X, Y, W, H, 0, 0, BMPI.bmiHeader.biWidth, _
                             BMPI.bmiHeader.biHeight, BYVAL BMPMemPtr, BMPI, 0, %SRCCOPY
               GlobalUnlock hBMP
               DeleteObject hBMP
               DeleteDC dcBMP
               ReleaseDC 0, hDC
               BMPMem = ""
               EndPage BMPPrinter
            NEXT
            EndDoc BMPPrinter
            DeleteDC BMPPrinter
         END IF
      END FUNCTION
      
      
      CALLBACK FUNCTION DlgProc
         SELECT CASE CBCTL
         CASE 102
            PrintDialog
         END SELECT
      END FUNCTION
      
      
      FUNCTION PBMAIN
         BMPLeft   = 0.5  ' Where to print your dialog image... margins on paper (in inches)
         BMPTop    = 0.5
         BMPWidth  = 6.0  ' What size to print your dialog image (in inches)
         BMPHeight = 4.0
         DIALOG NEW 0, "My Dialog",,, 300, 200, %WS_SYSMENU TO hDlg
         CONTROL ADD LABEL, hDlg, 101, "Click OK to print a copy of this dialog...", 85, 60, 190, 12
         CONTROL ADD BUTTON, hDlg, 102, "OK", 130, 160, 40, 15
         DIALOG SHOW MODAL hDlg CALL DlgProc
      END FUNCTION
      Timm

      [This message has been edited by Timm Motl (edited September 30, 2000).]
      mailto:[email protected]
      Tsunami Record Manager

      Comment


      • #4
        DienyduToit...

        Here's the example that prints directly to the default printer.
        Code:
        #COMPILE EXE
        #REGISTER NONE
        #INCLUDE "WIN32API.INC"
        #INCLUDE "COMDLG32.INC"
        
        
        GLOBAL hDlg      AS LONG
        GLOBAL BMPLeft   AS DOUBLE
        GLOBAL BMPTop    AS DOUBLE
        GLOBAL BMPWidth  AS DOUBLE
        GLOBAL BMPHeight AS DOUBLE
        
        
        FUNCTION PrintDialog() AS LONG
           LOCAL X             AS LONG
           LOCAL Y             AS LONG
           LOCAL W             AS LONG
           LOCAL H             AS LONG
           LOCAL BMP           AS BITMAP
           LOCAL BMPI          AS BITMAPINFO
           LOCAL BMPrc         AS RECT
           LOCAL BMPMem        AS STRING
           LOCAL BMPMemPtr     AS LONG
           LOCAL BMPSize       AS LONG
           LOCAL hBMP          AS LONG
           LOCAL dcBMP         AS LONG
           LOCAL hDC           AS LONG
           LOCAL Copies        AS LONG
           LOCAL PDOptions     AS LONG
           LOCAL BMPPrinter    AS LONG
           LOCAL DocumentInfo  AS DOCINFO
           LOCAL DocumentName  AS ASCIIZ * 255
           DIM PInfo5(0:2) AS PRINTER_INFO_5
           EnumPrinters %PRINTER_ENUM_DEFAULT, BYVAL %NULL, 5, BYVAL VARPTR(PInfo5(0)), SIZEOF(PInfo5(0)) * 3, Needed&, Returned&
           BMPPrinter = CreateDC(BYVAL %NULL, BYVAL PInfo5(0).pPrinterName, BYVAL %NULL, BYVAL %NULL)
           IF BMPPrinter THEN
              GetWindowText hDlg, DocumentName, 255
              DocumentInfo.lpszDocName = VARPTR(DocumentName)
              DocumentInfo.lpszOutput = 0
              StartDoc BMPPrinter, DocumentInfo
              StartPage BMPPrinter
              X = GetDeviceCaps(BMPPrinter, %LOGPIXELSX) * BMPLeft
              Y = GetDeviceCaps(BMPPrinter, %LOGPIXELSY) * BMPTop
              W = GetDeviceCaps(BMPPrinter, %LOGPIXELSX) * BMPWidth
              H = GetDeviceCaps(BMPPrinter, %LOGPIXELSY) * BMPHeight
              GetWindowRect hDlg, BMPrc
              BMPI.bmiHeader.biSize = SIZEOF(BMPI.bmiHeader)
              BMPI.bmiHeader.biWidth = (BMPrc.nRight - BMPrc.nLeft)
              BMPI.bmiHeader.biHeight = (BMPrc.nBottom - BMPrc.nTop)
              BMPI.bmiHeader.biPlanes = 1
              BMPI.bmiHeader.biBitCount = 24
              BMPI.bmiHeader.biCompression = 0
              BMPSize = BMPI.bmiHeader.biWidth
              BMPSize = (BMPSize + 1) * (BMPI.bmiHeader.biBitCount / 8)
              BMPSize = ((BMPSize + 3) / 4) * 4
              BMPSize = BMPSize * BMPI.bmiHeader.biHeight
              BMPMem = STRING$(BMPSize, CHR$(0))
              BMPMemPtr = STRPTR(BMPMem)
              hDC = GetDC(0)
              dcBMP = CreateCompatibleDC(hDC)
              hBMP = CreateDIBSection(dcBMP, BMPI, 0, 0, 0, 0)
              GlobalLock hBMP
              SelectObject dcBMP, hBMP
              GetObject hBMP, SIZEOF(BMP), BMP
              BitBlt dcBMP, 0, 0, BMP.bmWidth, BMP.bmHeight, hDC, BMPrc.nLeft, BMPrc.nTop, %SRCCOPY
              IF (BMP.bmWidth / BMP.bmHeight) > (W / H) THEN
                 H = W * BMP.bmHeight / BMP.bmWidth
              ELSE
                 W = H * BMP.bmWidth / BMP.bmHeight
              END IF
              GetDIBits dcBMP, hBMP, 0, BMPI.bmiHeader.biHeight, BYVAL BMPMemPtr, BMPI, 0
              StretchDIBits BMPPrinter, X, Y, W, H, 0, 0, BMPI.bmiHeader.biWidth, _
                            BMPI.bmiHeader.biHeight, BYVAL BMPMemPtr, BMPI, 0, %SRCCOPY
              GlobalUnlock hBMP
              DeleteObject hBMP
              DeleteDC dcBMP
              ReleaseDC 0, hDC
              BMPMem = ""
              EndPage BMPPrinter
              EndDoc BMPPrinter
              DeleteDC BMPPrinter
           END IF
        END FUNCTION
        
        
        CALLBACK FUNCTION DlgProc
           SELECT CASE CBCTL
           CASE 102
              PrintDialog
           END SELECT
        END FUNCTION
        
        
        FUNCTION PBMAIN
           BMPLeft   = 0.5  ' Where to print your dialog image... margins on paper (in inches)
           BMPTop    = 0.5
           BMPWidth  = 6.0  ' What size to print your dialog image (in inches)
           BMPHeight = 4.0
           DIALOG NEW 0, "My Dialog",,, 300, 200, %WS_SYSMENU TO hDlg
           CONTROL ADD LABEL, hDlg, 101, "Click OK to print a copy of this dialog...", 85, 60, 190, 12
           CONTROL ADD BUTTON, hDlg, 102, "OK", 130, 160, 40, 15
           DIALOG SHOW MODAL hDlg CALL DlgProc
        END FUNCTION
        Timm
        mailto:[email protected]
        Tsunami Record Manager

        Comment


        • #5
          Timm, thank you for all that time and trouble. This works as you
          said it would. I use your second option which is perfect for the
          purpose, giving the print dialog first (number of copies option
          etc.) and then print - in this case there is no purpose in saving
          the image to a disk file, but I can see that there will be uses
          for that one as well.

          In my present case, the dialog is larger than the screen,
          however. I have tried scaling down sizes and fonts
          proportionately so that the whole dialog would be visible, but
          this makes everthing too small -- the printed text gets to be
          distorted. The printed output is supposed to be portrait, 297mm
          deep by 210mm wide (A4) and this is not in line with screen
          proportions. The original dialog is virtually the same size as
          th A4 sheet and that prints perfectly -- but of course, only the
          visible part.

          Is there perhaps a way to create the bitmap for the visible
          portion, then update the dialog - or scroll it upwards - and then
          ADD this to the first bitmap before printing?

          Amazingly, browsing the Internet yesterday, I found a shop which
          DOES have the Petzold 5th edition, and promptly ordered
          (enormous price -- will read it in Debtors Prison).


          ------------------

          Comment


          • #6
            DienyduToit...

            The samples I posted use the GetWindowRect API call to determine the region to copy to the bitmap. This limits you to whatever is visible in the dialog. Maybe if you could more fully describe what your dialog contains that needs to be printed, there might be another way to approach it.

            Timm
            mailto:[email protected]
            Tsunami Record Manager

            Comment


            • #7
              Timm, the dialog is a simple document to be printed on an A4 size
              sheet. It is initially created by the application as a scrolling
              dialog and permits the user to edit certain areas of it. When the
              user opts to print it, the application creates a new dialog of
              the proportions of an A4 sheet and on this it places only labels,
              and fills these with the text contents of the original dialog
              (which may be single/multi line text boxes or labels). This
              second dialog has a few additional headings but is otherwise an
              exact replica of the first, except that it is only black and
              white (black text on a white background and containing ONLY
              labels). One such case is a very conventional letter, another is
              a workticket (job card, or whatever the term is) and there are
              also a number of ordinary reports. We stick to A4 (297 x 210 mm)
              as far as possible.

              The one I am testing with at present is the job card. Typically,
              more than half of this is visible on screen. Also, some of the
              labels are enclosed in 'boxes', which are additional labels with
              style %BLACKFRAME.

              Since receiving your code, I have experimented with the
              'save-bitmap-to-disk' as well to save TWO bitmaps for the upper
              and lower portions of the dialog (the second by setting the
              dialog loc to a negative y-value), and then trying to print both
              in one print call, but so far no success. It may be that one
              should create the black and white dialog twice, once for the top
              and then once more for the lower portion.

              As mentioned, I have now (for the third time) ordered the Petzold
              book, and MAY be third-time-lucky. If so, that might just make a
              world of difference to my 'hits' on this forum! Who knows, I may
              even become a contributor instead of perennial beginner ...




              ------------------

              Comment


              • #8
                DienyduToit...

                Unless there is some reason that you absolutely MUST copy the contents of one dialog to another dialog, then copy the second
                dialog's image to a bitmap and then print that bitmap, I would say you are going through a lot of hoops just to print something.

                It seems it would be much simpler to use ...
                Code:
                CONTROL GET TEXT hDlg, 100 TO TempText$
                ... to get the text out of each LABEL in your first dialog and then print it using code similar to the following ...
                Code:
                #COMPILE EXE
                #REGISTER NONE
                #INCLUDE "WIN32API.INC"
                
                
                FUNCTION MakeFont(BYVAL Font AS STRING, BYVAL PointSize AS LONG) AS LONG
                   LOCAL hDC AS LONG
                   LOCAL CyPixels AS LONG
                   hDC = GetDC(%HWND_DESKTOP)
                   CyPixels  = GetDeviceCaps(hDC, %LOGPIXELSY)
                   ReleaseDC %HWND_DESKTOP, hDC
                   PointSize = (PointSize * CyPixels) \ 72
                   FUNCTION = CreateFont(0 - PointSize, 0, 0, 0, %FW_NORMAL, 0, 0, 0, %ANSI_CHARSET,_
                              %OUT_TT_PRECIS, %CLIP_DEFAULT_PRECIS, %DEFAULT_QUALITY, %FF_DONTCARE, BYCOPY Font)
                END FUNCTION
                
                
                FUNCTION PrintSomething() AS LONG
                   LOCAL hDc AS LONG
                   LOCAL Di  AS DocInfo
                   LOCAL DocName  AS ASCIIZ * 32
                   LOCAL TempText AS ASCIIZ * 1024
                   LOCAL PInfo5() AS PRINTER_INFO_5
                   DIM PInfo5(0:2) AS PRINTER_INFO_5
                   EnumPrinters %PRINTER_ENUM_DEFAULT, BYVAL %NULL, 5, BYVAL VARPTR(PInfo5(0)), SIZEOF(PInfo5(0)) * 3, Needed&, Returned&
                   hDC = CreateDC(BYVAL %Null, BYVAL PInfo5(0).pPrinterName, BYVAL %Null, BYVAL %Null)
                   IF hDC THEN
                      DocName = "Test Print Job"
                      Di.lpszDocName = VARPTR(DocName)
                      Di.cbSize = SIZEOF(Di)
                      IF StartDoc(hDC, Di) THEN
                         SetBkMode hDc, %TRANSPARENT
                         StartPage hDC
                            ' Draw a box
                            Rectangle hDc, 0, 0, 1000, 70
                            ' Print some text inside that box
                            TempText = "This is a printer test..."
                            hFont& = MakeFont("MS Sans Serif", 30)
                               SelectObject hDc, hFont&
                               TextOut hDc, 30, 7, TempText, BYVAL LEN(TempText)
                            ' Print that same text in some different fonts
                            hFont& = MakeFont("Courier New", 30)
                               SelectObject hDc, hFont&
                               TextOut hDc, 30, 107, TempText, BYVAL LEN(TempText)
                            hFont& = MakeFont("Ariel Bold", 50)
                               SelectObject hDc, hFont&
                               TextOut hDc, 30, 200, TempText, BYVAL LEN(TempText)
                            hFont& = MakeFont("Courier New", 50)
                               SelectObject hDc, hFont&
                               TextOut hDc, 30, 325, UCASE$(TempText), BYVAL LEN(TempText)
                            ' Draw some lines
                            FOR LoopVal& = 1 TO 500 STEP 50
                               MoveToEx hDc, 30, 450 + LoopVal&, BYVAL %NULL
                               LineTo hDc, 1030, 450 + LoopVal&
                            NEXT
                         EndPage hDc
                         'StartPage hDC
                            ' If you had a second page, the print commands would go here...
                         'EndPage hDc
                         ' Etc...
                         ' Etc...
                         EndDoc hDc
                         TempText = ""
                         DeleteDC hDc
                      ELSE
                         DeleteDC hDC
                      END IF
                   END IF
                END FUNCTION
                
                
                CALLBACK FUNCTION DlgProc
                   SELECT CASE CBCTL
                   CASE 100
                      CALL PrintSomething
                   END SELECT
                END FUNCTION
                
                
                FUNCTION PBMAIN
                   LOCAL hDlg AS LONG
                   DIALOG NEW 0, "Printer Test",,, 200, 60, %WS_SYSMENU TO hDlg
                   CONTROL ADD BUTTON, hDlg, 100, "Print", 80, 15, 40, 14
                   DIALOG SHOW MODAL hDlg, CALL DlgProc
                END FUNCTION
                Timm

                [This message has been edited by Timm Motl (edited October 02, 2000).]
                mailto:[email protected]
                Tsunami Record Manager

                Comment


                • #9
                  Timm, your most recent posting provides the solution. It does
                  mean a bit more work, but it places one in complete control of
                  the printed result, and the print quality is noticably superior
                  to the bitmap print equivalent. True, I have a little problem
                  with rows of text which must be right-justified and vertically
                  right-aligned, but a solution will no doubt present itself.

                  Your previous posting (some or all!) are going to be used in
                  a number of cases where the print info. is always contained in a
                  single screen.

                  I do want to thank you for all the time and trouble -- it has
                  been (and will be) of tremendous help to me.


                  ------------------

                  Comment


                  • #10
                    DienyduToit...

                    You are right... it will be more work on your part, but as you said, you will have higher quality output and more control.
                    To print justified text, simply use the DrawText command instead of TextOut. Notice the addition of a variable named RC
                    that is DIMensioned AS RECT (rectangle structure) that holds the output boundries for the text you will be "drawing".

                    You should check out the DrawText command in the Win32 help file for more info on that.
                    Code:
                    #COMPILE EXE
                    #REGISTER NONE
                    #INCLUDE "WIN32API.INC"
                    
                    
                    FUNCTION MakeFont(BYVAL Font AS STRING, BYVAL PointSize AS LONG) AS LONG
                       LOCAL hDC AS LONG
                       LOCAL CyPixels AS LONG
                       hDC = GetDC(%HWND_DESKTOP)
                       CyPixels  = GetDeviceCaps(hDC, %LOGPIXELSY)
                       ReleaseDC %HWND_DESKTOP, hDC
                       PointSize = (PointSize * CyPixels) \ 72
                       FUNCTION = CreateFont(0 - PointSize, 0, 0, 0, %FW_NORMAL, 0, 0, 0, %ANSI_CHARSET,_
                                  %OUT_TT_PRECIS, %CLIP_DEFAULT_PRECIS, %DEFAULT_QUALITY, %FF_DONTCARE, BYCOPY Font)
                    END FUNCTION
                    
                    
                    FUNCTION PrintSomething() AS LONG
                       DIM RC AS RECT
                       LOCAL hDc AS LONG
                       LOCAL Di  AS DocInfo
                       LOCAL DocName  AS ASCIIZ * 32
                       LOCAL TempText AS ASCIIZ * 1024
                       LOCAL PInfo5() AS PRINTER_INFO_5
                       DIM PInfo5(0:2) AS PRINTER_INFO_5
                       EnumPrinters %PRINTER_ENUM_DEFAULT, BYVAL %NULL, 5, BYVAL VARPTR(PInfo5(0)), SIZEOF(PInfo5(0)) * 3, Needed&, Returned&
                       hDC = CreateDC(BYVAL %Null, BYVAL PInfo5(0).pPrinterName, BYVAL %Null, BYVAL %Null)
                       IF hDC THEN
                          DocName = "Test Print Job"
                          Di.lpszDocName = VARPTR(DocName)
                          Di.cbSize = SIZEOF(Di)
                          IF StartDoc(hDC, Di) THEN
                             SetBkMode hDc, %TRANSPARENT
                             StartPage hDC
                                TempText = "This is a printer test"
                                hFont& = MakeFont("MS Sans Serif", 30)
                                SelectObject hDc, hFont&
                                ' Draw a box
                                Rectangle hDc, 0, 0, 1000, 70
                                ' Define some text boundries that will fit inside the box
                                RC.nLeft = 10
                                RC.nTop = 10
                                RC.nRight = 990
                                RC.nBottom = 60
                                ' Print the text LEFT JUSTIFIED inside the boundries
                                DrawText hDC, TempText, LEN(TempText), RC, %DT_LEFT
                                ' Draw another box
                                Rectangle hDc, 0, 100, 1000, 170
                                ' Define some text boundries that will fit inside the box
                                RC.nLeft = 10
                                RC.nTop = 110
                                RC.nRight = 990
                                RC.nBottom = 160
                                ' Print the text HORIZONTALLY CENTERED inside the boundries
                                DrawText hDC, TempText, LEN(TempText), RC, %DT_CENTER
                                ' Draw another box
                                Rectangle hDc, 0, 200, 1000, 270
                                ' Define some text boundries that will fit inside the box
                                RC.nLeft = 10
                                RC.nTop = 210
                                RC.nRight = 990
                                RC.nBottom = 260
                                ' Print the text RIGHT JUSTIFIED inside the boundries
                                DrawText hDC, TempText, LEN(TempText), RC, %DT_RIGHT
                             EndPage hDc
                             EndDoc hDc
                             TempText = ""
                             DeleteDC hDc
                          ELSE
                             DeleteDC hDC
                          END IF
                       END IF
                    END FUNCTION
                    
                    
                    CALLBACK FUNCTION DlgProc
                       SELECT CASE CBCTL
                       CASE 100
                          CALL PrintSomething
                       END SELECT
                    END FUNCTION
                    
                    
                    FUNCTION PBMAIN
                       LOCAL hDlg AS LONG
                       DIALOG NEW 0, "Printer Test",,, 200, 60, %WS_SYSMENU TO hDlg
                       CONTROL ADD BUTTON, hDlg, 100, "Print", 80, 15, 40, 14
                       DIALOG SHOW MODAL hDlg, CALL DlgProc
                    END FUNCTION
                    Timm
                    mailto:[email protected]
                    Tsunami Record Manager

                    Comment


                    • #11
                      To easily position and justify text, check out SetTextAlign(), TextOut(), etc...


                      ------------------
                      Lance
                      PowerBASIC Support
                      mailto:[email protected][email protected]</A>
                      Lance
                      mailto:[email protected]

                      Comment


                      • #12
                        Timm, I wasn't REALLY expecting a further posting from you, but
                        it certainly solved the last problem beautifully (that mention of
                        a justification problem must have sounded very much like a broad
                        hint ... !).

                        No more hints, broad or otherwise -- I have a lift-off, thanks to
                        your help. I only wish I had a scanner so I could e-mail you an
                        example of what you have made possible: the most user-friendly,
                        practical, commonsense workticket (job card) for the printing
                        industry on the planet. Maybe on other planets as well. Our
                        quotation letter, cost summaries and many other reports will
                        obviously also benefit greatly from all this.

                        Thank you again.



                        ------------------

                        Comment


                        • #13
                          I notice that this bit ---

                          EndPage hDc
                          'StartPage hDC
                          ' If you had a second page, the print commands would go here...
                          'EndPage hDc
                          ' Etc...
                          ' Etc...
                          EndDoc hDc

                          --- doesn't seem to work.

                          At first, I had a string of fixed length print lines, which I fed
                          to the print hDC one by one in a While/wend loop. Within the loop
                          I then tested for "page full" and at that point simply put in an
                          EndPage and a StartPage, and continued. This hangs the machine,
                          and the system freezes, or otherwise the printer is "busy on
                          another task" or words to that effect.

                          Then I separated the long string into two which would each fit
                          into a page, and did them on separate While/wend loops, each
                          with its own StartDoc and EndDoc. Same result.

                          Finally, I did the first one-page string on its own, then EndPage
                          AND EndDoc, and repeated all the initial printer statements, like
                          this --

                          '(first string = first page. This prints out)
                          GoSub PrintCosts '(which While/wends until strings finished)
                          EndPage hDc
                          EndDoc hDc
                          DeleteDC hDc

                          If Len(rmn$)=0 Then EOJ 'the second string is present, so ...

                          ReDim PInfo5(0:2) As PRINTER_INFO_5

                          EnumPrinters %PRINTER_ENUM_DEFAULT, ByVal %NULL, 5, ByVal VarPtr(PInfo5(0)), SizeOf(PInfo5(0)) * 3, Needed&, Returned&
                          hDC = CreateDC(ByVal %Null, ByVal PInfo5(0).pPrinterName, ByVal %Null, ByVal %Null)
                          t$=rmn$
                          rmn$=""

                          If hDC Then
                          DocName = "Test Print Job"
                          Di.lpszDocName = VarPtr(DocName)
                          Di.cbSize = SizeOf(Di)
                          If StartDoc(hDC, Di) Then
                          SetBkMode hDc, %TRANSPARENT
                          StartPage hDC
                          GoSub HeadUpCosts 'second page does not print
                          GoSub PrintCosts 'instead, system hangs
                          End If
                          End If
                          If tp&<6290 Then
                          MoveToEx hDc, 300, tp&-20, ByVal %NULL
                          LineTo hDc, 4390, tp&-20
                          End If
                          End Select
                          EOJ:
                          EndPage hDc
                          EndDoc hDc
                          txt = ""
                          DeleteDC hDc
                          DeleteObject MainPen&
                          DeleteObject ThckPen&
                          DeleteObject WhitePen&
                          Else
                          DeleteDC hDC
                          DeleteObject MainPen&
                          DeleteObject ThckPen&
                          DeleteObject WhitePen&
                          End If
                          End If

                          STILL does the same! Is there something else to be added?


                          ------------------

                          Comment


                          • #14
                            DienyduToit...

                            In your last posting it sounded like you are using a long string made up of fixed length lines that need to be parsed and printed, and
                            that this long string contains more lines than you can fit on one printed page. Here's an example of how you could print a string made
                            up of 100 fixed length lines (25 characters each), "paging" after you've printed 40 lines on a page.
                            Code:
                            #COMPILE EXE
                            #REGISTER NONE
                            #INCLUDE "WIN32API.INC"
                            
                            
                            FUNCTION PrintSomething() AS LONG
                               LOCAL hDc AS LONG
                               LOCAL Di  AS DocInfo
                               LOCAL DocName  AS ASCIIZ * 32
                               LOCAL TempText AS ASCIIZ * 1024
                               LOCAL PInfo5() AS PRINTER_INFO_5
                               DIM PInfo5(0:2) AS PRINTER_INFO_5
                               '
                               ' Creating a long output string
                               PrintString$ = ""
                               FOR TempLoop& = 1 TO 100
                                  PrintString$ = PrintString$ + "This is line number:  " + RIGHT$(STR$(1000 + TempLoop&), 3)
                               NEXT
                               '
                               EnumPrinters %PRINTER_ENUM_DEFAULT, BYVAL %NULL, 5, BYVAL VARPTR(PInfo5(0)), SIZEOF(PInfo5(0)) * 3, Needed&, Returned&
                               hDC = CreateDC(BYVAL %Null, BYVAL PInfo5(0).pPrinterName, BYVAL %Null, BYVAL %Null)
                               IF hDC THEN
                                  DocName = "Test Print Job"
                                  Di.lpszDocName = VARPTR(DocName)
                                  Di.cbSize = SIZEOF(Di)
                                  IF StartDoc(hDC, Di) THEN
                                     JobLineCounter& = 0
                                     DO
                                        StartPage hDC
                                        PageLineCounter& = 0
                                        DO
                                           INCR PageLineCounter&
                                           ' Parse next line out of long string
                                           TempText = MID$(PrintString$, 1 + (JobLineCounter& * 25), 25)
                                           TextOut hDc, 100, PageLineCounter& * 70, TempText, BYVAL LEN(TempText)
                                           INCR JobLineCounter&
                                        LOOP WHILE PageLineCounter& < 40 AND JobLineCounter& < 100
                                        EndPage hDc
                                     LOOP WHILE JobLineCounter& < 100
                                     EndDoc hDc
                                     TempText = ""
                                     DeleteDC hDc
                                  ELSE
                                     DeleteDC hDC
                                  END IF
                               END IF
                               PrintString$ = ""
                            END FUNCTION
                            
                            
                            CALLBACK FUNCTION DlgProc
                               SELECT CASE CBCTL
                               CASE 100
                                  CALL PrintSomething
                               END SELECT
                            END FUNCTION
                            
                            
                            FUNCTION PBMAIN
                               LOCAL hDlg AS LONG
                               DIALOG NEW 0, "Printer Test",,, 200, 60, %WS_SYSMENU TO hDlg
                               CONTROL ADD BUTTON, hDlg, 100, "Print", 80, 15, 40, 14
                               DIALOG SHOW MODAL hDlg, CALL DlgProc
                            END FUNCTION
                            Timm
                            mailto:[email protected]
                            Tsunami Record Manager

                            Comment


                            • #15
                              Thank you, Timm. Picked up your new posting yesterday morning
                              (Sunday), but only got round to implementing it this pm. As
                              before, it works like a charm, despite adaptations to my own
                              printout. It looks like this ---

                              If hDC Then
                              DocName = "Cost summary"
                              Di.lpszDocName = VarPtr(DocName)
                              Di.cbSize = SizeOf(Di)
                              If StartDoc(hDC, Di) Then
                              SetBkMode hDc, %TRANSPARENT

                              Do
                              StartPage hDC
                              GoSub HeadUpCosts
                              tp&=tp&+130
                              SelectObject hDc, sFont&
                              Do
                              r$=Left$(t$,90)
                              t$=Right$(t$,Len(t$)-90)
                              i$=Left$(r$,10)
                              r$=Right$(r$,Len(r$)-10)
                              i$=Trim$(i$)
                              If Left$(i$,5)="Sect " Then i$="Sect"
                              x$=Left$(r$,23)
                              fds$=FullDescription(x$)
                              If Len(Trim$(fds$))=0 Then fds$=""
                              k$=""
                              GoSub Printcosts
                              Loop While tp& <= ep& And Len(t$) > 89 '6290
                              MoveToEx hDc, 300, tp&-20, ByVal %NULL
                              LineTo hDc, 4396, tp&-20
                              EndPage hDc
                              Loop While Len(t$) > 89
                              End If
                              EndDoc hDc
                              txt = ""
                              DeleteDC hDc
                              DeleteObject MainPen&
                              DeleteObject ThckPen&
                              DeleteObject WhitePen&

                              The HeadUpCosts starts each page, and the Gosub Printcosts is
                              quite a large chunk of code which is fed one line at a time, each
                              being identified as to its specific requirements. Thanks again!

                              ------------------

                              Comment

                              Working...
                              X