Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Demo: Initialize PrintDlg() for named printer

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

  • Demo: Initialize PrintDlg() for named printer

    Code:
    ' file: init_prtdlg.bas
    ' ----------------------------------------------------
    ' Initializing the PrtDlg() for a named printer
    ' Includes demo of enumerating available printers.
    ' ----------------------------------------------------
    ' Author: Michael Mattias Racine WI  9.21.04
    ' COMPILER: Pb/Win 7.02
    ' Use and distribution: Placed in public domain by author 9/21/04
    ' ---------------------------------------------------------------
    
    #COMPILE  EXE
    #REGISTER NONE
    #DEBUG    ERROR ON
    #DIM      ALL
    
    %I_AM_USING_DDOC_PRINT_AND_PREVIEW  =  0  ' if true, uses ddoc fuctions, else does the printer enum
    
    '=====[Windows API Header Files] ============================
    '  If you don't need all of the functionality supported by these APIs
    '  (and who does?), you can selectively turn off various modules by putting
    '  the following constants in your program BEFORE you #include "win32api.inc":
    '
    '  %NOGDI = 1     ' no GDI (Graphics Device Interface) functions
    '  %NOMMIDS = 1   ' no Multimedia ID definitions
    
    %NOMMIDS = 1
    #INCLUDE "WIN32API.INC"    ' DATE: May 9 2002. GDI required for COMDLG32.INC
    
    ' PrtDlg() functions and UDTs:
    #INCLUDE "COMDLG32.INC"
    
    
    ' Program-level equates
    %PRINTER_NAME_SIZE      = 128
    
    %ID_CB                  = 101    ' combobox with list of installed printers
    %ID_CALL_PRTDLG         = 102    ' button to call the dialog
    %ID_SEL_PRINTER         = 103    ' label to show what user selected regardless of how box was initialized
    %NODEFAULT_ITEMDATA     =   0    ' at which index the [No Default] entry is located
    
    
    ' ----------------------------------------------------------------------------------
    ' This function requires the ddoc Print And Preview Library.
     'If you ain't got that you can use any other method desired to load the list
    ' -----------------------------------------------------------------------------------
    #IF %I_AM_USING_DDOC_PRINT_AND_PREVIEW
    ' ddoc headers
    #INCLUDE "ddoc_p32.inc"
    FUNCTION LoadInstalledPrinters (szP() AS ASCIIZ * %PRINTER_NAME_SIZE) AS LONG
    
        LOCAL nPrinter AS LONG, I AS LONG
    
        nPRinter   = DpPrinterCount ()
    
        REDIM        szP(nPrinter)
        FOR I      = 1 TO nPrinter        ' load printers 1-n, printer 0 = "no Default"
            szP (I) =  dpgetPrinter (I)
        NEXT
    
    END FUNCTION
    
    #ELSE
    ' i.e., NOT using ddoc Print and Preview. We have to do this the long way...
    
    FUNCTION LoadInstalledPrinters (szP() AS ASCIIZ * %PRINTER_NAME_SIZE ) AS LONG
    
      LOCAL pInfo5()     AS PRINTER_INFO_5,_
            dwNeeded     AS LONG,_
            dwReturned   AS LONG,_
            pszName      AS ASCIIZ PTR,_
            pBuffer      AS DWORD,_
            dwEnumFlags  AS DWORD,_
            Z            AS LONG,_
            Level        AS LONG, _
            sBuffer      AS STRING
    
      Level        = 5&
      dwEnumFlags  = %PRINTER_ENUM_LOCAL  OR %PRINTER_ENUM_CONNECTIONS   ' << return all printers for this machine
      pszName      = %NULL              ' we do not send a name string since we want all
    
      ' ---------------------------------------------------------------------------------------------------------
      ' Get the size of the buffer needed for printer enumeration..
      ' This call will fail on insufficient buffer, but that's what we want it do...
      ' Note that dwNeeded is not just for the PRINTER_INFO_5 structures, it includes the space needed for the
      ' printer names pointed to by the pPrinterName members of the PRINTER_INFO_5 structures returned.
      ' You cannot size anything other than the buffer size required based on the value of dwNeeded;
      ' you have to use dwReturned when the enum succeeds to get the number of printers.
      ' ---------------------------------------------------------------------------------------------------------
      
      Z = EnumPrinters (dwEnumFlags, BYVAL pszName, Level, BYVAL %NULL, 0, dwNeeded, dwReturned)
    
      ' create needed buffer
      sBuffer         = STRING$(dwNeeded, 0)
    
      ' set buffer pointer, repeat enumeration
      pBuffer          = STRPTR (sBuffer)
      IF EnumPrinters    (dwEnumFlags, BYVAL pszName, Level, BYVAL pBuffer, dwNeeded, dwNeeded, dwReturned) THEN
         REDIM           szP   (dwReturned)              ' resize passed array to handle the correct number of printers.
         REDIM           PINFO5(dwReturned) AT pBuffer   ' set up to read the PRINTER_INFO5 structures at head of buffer
         FOR Z   = 1 TO dwReturned                       '
             szP(Z)  =  pInfo5(Z-1)[email protected]        ' put names returned in passed array
         NEXT
      ELSE
         MSGBOX "Enum Printers Failed", %MB_ICONHAND,"Oops!"
      END IF
    
    END FUNCTION
    
    #ENDIF  ' if using ddoc P & P
    
    ' -------------------------------------------------------------------'
    ' Call the prtDlg() Common Dialog, initializing for a named printer
    ' if one was passed
    ' -------------------------------------------------------------------'
    
    FUNCTION CallPrtDlg (BYVAL hWnd AS LONG, OPTIONAL szPrinterName AS ASCIIZ) AS STRING
    
      LOCAL GotPrinterName AS LONG, iRet AS LONG
      LOCAL pDevNames AS DEVNAMES PTR, hDevNames AS LONG
      LOCAL pDevMode  AS DEVMODE  PTR, hDevMode  AS LONG
      LOCAL psz       AS ASCIIZ   PTR, pDest     AS DWORD
      LOCAL PD        AS PRINTDLGAPI
      LOCAL szUsePrinterName AS ASCIIZ * %PRINTER_NAME_SIZE
    
     ' ==[End DIM, start code]====
    
    
      GotPrinterName         = ISTRUE(VARPTR(szPRinterName))   ' was the optional parameter passed?
    
      ' Initialize the PRINTDLGAPI structure, include a named printer if it was passed
      ' Although we only *need* to allocate the extra space if/when we get a printername, it costs nothing
      ' to allow for the space at all times
       hDevNames        = GlobalAlloc (%GMEM_MOVEABLE OR %GMEM_ZEROINIT, SIZEOF(@pDevNames) + %PRINTER_NAME_SIZE)
    
       IF hDevNames     = 0 THEN
                MSGBOX "GlobalAlloc of Devnames failed!"
                EXIT FUNCTION
       END IF
       hDevMode         = GlobalAlloc (%GMEM_MOVEABLE OR %GMEM_ZEROINIT, SIZEOF(@pDevMode))
       IF hDevMode = 0 THEN
            MSGBOX "GlobalAlloc of DevMode failed!"
            EXIT FUNCTION
       END IF
       ' --------------------------------------------
       '  SET COMMON ELEMENTS OF PRINTDLGAPI STRUCTURE
       ' --------------------------------------------
       PD.lStructSize               = SIZEOF(PD)
       PD.hWndOwner                 = hWnd
       PD.hDevMode                  = hDevMode
       PD.hDevNames                 = hDevNames
       PD.FLAGS                     = %PD_NOPAGENUMS OR %PD_USEDEVMODECOPIESANDCOLLATE
                                      ' any flags you may want can go here
    
      ' ---------------------------------------------------------------------------------------------
      ' INITIALIZE THE DIALOG BOX'S DEVICE NAME FOR NAMED PRINTER IF WE GOT ONE, or NULL IF WE DIDN'T
      ' ---------------------------------------------------------------------------------------------
       pDevNames                      = GlobalLock(PD.hDevNames)
       IF ISTRUE  GotPrinterName THEN
          @pDevnames.wDeviceOffset    = SIZEOF (@pDevNames)              ' name of printer to use immediately follows Devnames
          pDest                       = pDevnames + SIZEOF(@pDevNames)   ' point to area following DEVNAMES structure
          CopyMemory                    pDest, VARPTR(szPrinterName), lstrlen(szPrinterName)  ' copy printer name
       ELSE
          @pDevNames.wDeviceOffset    = %NULL
       END IF
       GlobalUnlock                     PD.hDevNames
      ' ------------------------------
      ' CALL THE PRINT DIALOG
      ' ------------------------------
       iRet          = PrintDlg(PD)
       IF ISTRUE iRet THEN              ' user Clicked OK (to something!)
       ' Get the name of the selected printer..
          IF PD.hDevNames <> 0 THEN
            pDevNames             = GlobalLock(PD.hDevNames)
            psz                   = pDevnames
            psz                   =  psz + @pDevnames.wDeviceOffset   ' add returned offset
            szUsePrinterName      = @psz   ' <<< user-friendly printer name, e.g., "HP Desk Jet 870"
            GlobalUnlock            PD.hDevnames
          ELSE
             MSGBOX "Can't get DevNames Handle in Print Routine", %MB_ICONERROR, "Print Subsystem Error"
            szUsePrinterName    = "ERROR"
          END IF
       ELSE     ' we did not get a printerName
           szUsePRinterName   =   "USER CANCELED WITHOUT SELECTING"
       END IF
    
      'Free the globals we alloc'ed
       GlobalFree PD.hDevNames
       GlobalFree PD.hDevMode
    
       FUNCTION = szUsePrinterName  ' return selected name (or error message for this demo)
    
    END FUNCTION
    
    
    ' What is this? I now *MUST* use the "CALLBACK FUNCTION" syntax , and *may not* use params?
    ' There's a behavior change from 6x for sure. (and maybe from 7.0?) (not documented in 7.02 help file as change)
    CALLBACK FUNCTION DlgProc ()
    
        LOCAL hWnd AS LONG, uMsg AS LONG, wParam AS LONG, lParam AS LONG
        LOCAL szPrinters() AS ASCIIZ * %PRINTER_NAME_SIZE, Z AS LONG, iIndex AS LONG
        LOCAL szSelPrinter AS ASCIIZ * %PRINTER_NAME_SIZE, iSel AS LONG
        LOCAL szText       AS ASCIIZ * %MAX_PATH
    
        ' set wndProc variables, since code was already writen before the "CALLBACK FUNCTION" thing was known...
        hWnd     =  CBHNDL
        uMsg     =  CBMSG
        wParam   =  CBWPARAM
        lParam   =  CBLPARAM
    
        SELECT CASE  AS LONG  uMSG
            CASE %WM_INITDIALOG
                ' load the "Use default" entry and the list of installed printers to combobox
                REDIM      szPrinters(0)    ' list loader will resize
                CALL       LoadInstalledPrinters (szPrinters ())    'load printers 1-n
                szPrinters (0)        =  "[No Default]"       ' set element zero
                FOR  Z  = 0 TO UBOUND (szPrinters,1)
                     iIndex = SendDlgItemMessage (hWnd, %ID_CB, %CB_ADDSTRING, 0, VARPTR(szPrinters(Z)))
                     ' set item data to row number so we can tell if a default printer is wanted
                     SendDlgItemMessage  hWnd, %ID_CB, %CB_SETITEMDATA, iIndex, Z
                NEXT
                ' pre-select the first entry in list
                SendDlgITemMessage   hWnd, %ID_CB, %CB_SETCURSEL, 0, 0
    
             CASE %WM_COMMAND
                SELECT CASE LOWRD(wParam)
                    CASE %ID_CALL_PRTDLG
                    ' erase selection from last call
                    szSelPrinter        =  ""
                    SetDlgItemText         hWnd, %ID_SEL_PRINTER, szSelPrinter
    
                    ' find currently selected printer
                    iSel  = SendDlgITemMessage (hWnd, %ID_CB, %CB_GETCURSEL, 0, 0)
                    IF iSel >= 0 THEN           ' something is selected
                        IF SendDlgItemMessage (hWnd, %ID_CB, %CB_GETITEMDATA,iSel,0) = %NODEFAULT_ITEMDATA THEN
                            ' call the initializer without a printer name
                            szSelPrinter =  CallPrtDlg (hwnd)
                        ELSE
                            SendDlgItemMessage  hWnd, %ID_CB, %CB_GETLBTEXT, iSel, BYVAL VARPTR (szText) ' get printer name
                            ' and call the initializer WITH a named printer
                            szSelPrinter = CallPrtDlg (hwnd, szText)
                        END IF
                        ' show the last results
                        SetDlgItemText       hWnd, %ID_SEL_PRINTER, szSelPrinter
    
                    ELSE
                        MSGBOX "No Printer Selected!"
                    END IF
    
                END SELECT   ' of control Id
    
          END SELECT
    
    
    END FUNCTION
    
    
    FUNCTION PBMAIN() AS LONG
        LOCAL hDLG AS LONG, cbStyle AS DWORD
    
        cbStyle      = %WS_VISIBLE OR %WS_CHILD OR %CBS_DROPDOWNLIST
    
        DIALOG NEW 0, "Initialized PrtDlg() Demo", 0, 0, 260, 170, _
            %DS_CENTER OR %WS_CAPTION OR %WS_SYSMENU OR %WS_VISIBLE , 0 TO hDlg
        ' Abort if the dialog could not be created
        IF hDlg = 0 THEN EXIT FUNCTION  ' Error occurred
    
        ' add our controls
        CONTROL ADD LABEL      , hDlg, -1, "Printer for which to initialize", 2, 12, 150, 14
        CONTROL ADD COMBOBOX   , hDlg, %ID_CB, ,2, 30, 200, 100, cbStyle
        CONTROL ADD BUTTON     , hDlg, %ID_CALL_PRTDLG, "Call PrtDlg", 110, 120, 40,14
        CONTROL ADD LABEL      , hDlg, -1, "Selected Printer",  2, 150,  60, 14
        CONTROL ADD LABEL      , hDlg, %ID_SEL_PRINTER, ""   , 80, 150, 160, 14
    
        DIALOG SHOW MODAL hDlg, CALL DlgProc()   ' must use 'CALLBACK FUNCTION' procedure header.
    
    
    END FUNCTION
    
    ' /// END OF FILE INIT_PRTDLG.BAS ///


    ------------------
    Michael Mattias
    Tal Systems Inc.
    Racine WI USA
    mailto:[email protected][email protected]</A>
    www.talsystems.com
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com
Working...
X