English

Problem: Setting paper size and bin when printing maps

Description

Despite setting the paper size and paper bin on the Printer dialog box, the printout does not print at the desired settings. This applies as well when using the Visual Basic Printer object to set the PaperBin and PaperSize properties. This document includes sample code to create a custom printer dialog box using the DeviceCapabilities API function.

Cause

Sometimes the printer driver does not recognize the constants for the Printer Object's PaperBin and PaperSize properties. (See Microsoft Developer Network knowledge base article Q194789.)

Solution or Workaround

Enumerate the constants using the DeviceCapabilities API.

  1. Create a dialog box similar to the following (do not worry about the values for the controls):
    [O-Image] Dialog Window
    COMBOBOX CONTROLS:
    Name the ComboBox controls as follows:
    Printer Name: cbPrinter
    Page Size: cbSize
    Page Source: cbSource

    OPTION BUTTONS:
    The Option buttons should be a control array. Name both Option buttons for the orientation 'rbOrientation'. The Index property values for these Option buttons should be as follows:
    Portrait Option: 0
    Landscape Option: 1

    COMMAND BUTTONS:
    Name the Command controls as follows:
    OK Button: cmdOk
    Cancel Button: cmdCancel

    FORM:
    Set the following properties for the Form:
    Name: frmPrint
    Caption: Printer Setup
  2. Open the code window for the Form and paste in the following code in the General Declaration area of the code:

    Code:
    'This application is based on MSDN Article ID Q194789.

    Option Explicit

    'The DeviceCapabilities function retrieves the capabilities of a printer device driver.
    Private Declare Function DeviceCapabilities Lib "winspool.drv" _
    Alias "DeviceCapabilitiesA" (ByVal lpDeviceName As String, _
    ByVal lpPort As String, ByVal iIndex As Long, lpOutput As Any, _
    ByVal dev As Long) As Long

    Private Const DC_BINS = 6
    Private Const DC_BINNAMES = 12
    Private Const DC_PAPERNAMES = 16
    Private Const DC_PAPERS = 2
    Private Const DC_FIELDS = 1

  3. Create the following Sub routine to list the available paper sources for your printer:

    Code:
    Sub populatePaperSource()
    'If setting the PaperBin property of the Printer object fails to select the desired bin,
    'it might be because the printer driver does not recognize the value being assigned.
    'In this case, you need to use the constant to select the printer's upper bin.

    Dim dwbins As Long
    Dim ct As Long
    Dim nameslist As String
    Dim nextString As String

    cbSource.Clear

    ' Get count of bins supported by active printer.
    dwbins = DeviceCapabilities(Printer.DeviceName, Printer.Port, _
    DC_BINS, ByVal vbNullString, 0)

    If dwbins <> -1 Then
    nameslist = String(24 * dwbins, 0)
    ' Get bin names supported by active printer.
    dwbins = DeviceCapabilities(Printer.DeviceName, Printer.Port, _
    DC_BINNAMES, ByVal nameslist, 0)

    ' List available bin names.

    For ct = 1 To dwbins
    nextString = Mid(nameslist, 24 * (ct - 1) + 1, 24)
    nextString = Left(nextString, InStr(1, nextString, _
    Chr(0)) - 1)
    cbSource.AddItem nextString
    Next ct
    Else
    cbSource.AddItem "not applicable" ' (-1 for plotters.)
    End If

    cbSource.ListIndex = 0
    End Sub

  4. Add another Sub routine to list the available paper sizes:

    Code:
    Sub populatePaperSize()

    Dim lPaperCount As Long
    Dim lCounter As Long
    Dim sPaperNamesList As String
    Dim sNextString As String
    Dim sTextString As String

    cbSize.Clear

    ' Get count of paper names supported by active printer.
    lPaperCount = DeviceCapabilities(Printer.DeviceName, Printer.Port, _
    DC_PAPERNAMES, ByVal vbNullString, 0)

    sPaperNamesList = String(64 * lPaperCount, 0)

    ' Get paper names supported by active printer.
    lPaperCount = DeviceCapabilities(Printer.DeviceName, Printer.Port, _
    DC_PAPERNAMES, ByVal sPaperNamesList, 0)

    ' List available paper names.

    For lCounter = 1 To lPaperCount
    ' Get a paper name.
    sNextString = Mid(sPaperNamesList, _
    64 * (lCounter - 1) + 1, 64)
    sNextString = Left(sNextString, _
    InStr(1, sNextString, Chr(0)) - 1)
    cbSize.AddItem sNextString
    Next lCounter

    cbSize.ListIndex = 0

    End Sub

  5. In the Form's Load() event, list the available printers and call the Sub routines to populate the appropriate combo boxes with the available paper source and size options:

    Code:
    Private Sub Form_Load()
    'frmPrint.cmdPrinterProperties.Enabled = False

    Dim X As Printer

    'Populate combo box with available printers
    For Each X In Printers
    cbPrinter.AddItem X.DeviceName
    Next
    cbPrinter.ListIndex = 1
    rbOrientation(0).Value = True

    'Initialize Printer settings
    Set Printer = Printers(cbPrinter.ListIndex)
    Printer.Orientation = 1
    populatePaperSource
    populatePaperSize

    End Sub

  6. Add code to set the active printer to be the selected printer. Populate the paper source and paper size ComboBox controls so that they apply to the selected printer:

    Code:
    Private Sub cbPrinter_Click()
    Dim i As Integer
    i = cbPrinter.ListIndex
    Set Printer = Printers(i)

    populatePaperSource

    populatePaperSize
    End Sub

  7. Write code to unload the form if the user clicks the Cancel button:

    Code:
    Private Sub cmdCancel_Click()
    Unload Me
    End Sub

  8. Type in the following code for when the OK button is clicked:

    Code:
    Private Sub cmdOK_Click()

    'Set Orientation
    '================

    If rbOrientation(0).Value = True Then
    Printer.Orientation = 1
    Else
    Printer.Orientation = 2
    End If

    'Set Paper Size
    '================

    Dim lPaperCount As Long
    Dim iNumPaper() As Integer
    Dim iPaperSelected As Integer

    ' Get count of paper sizes supported by active printer.
    lPaperCount = DeviceCapabilities(Printer.DeviceName, Printer.Port, _
    DC_PAPERS, ByVal vbNullString, 0)

    ReDim iNumPaper(1 To lPaperCount)

    'Get papers supported
    lPaperCount = DeviceCapabilities(Printer.DeviceName, Printer.Port, _
    DC_PAPERS, iNumPaper(1), 0)
    iPaperSelected = cbSize.ListIndex + 1
    Printer.PaperSize = iNumPaper(iPaperSelected)
    'Set Paper Bin
    '================

    Dim dwbins As Long
    Dim numBin() As Integer
    Dim iBinSelected As Integer

    'Get count of bins supported
    dwbins = DeviceCapabilities(Printer.DeviceName, Printer.Port, _
    DC_BINS, ByVal vbNullString, 0)
    If dwbins <> -1 Then
    ReDim numBin(1 To dwbins)
    'Get bins supported
    dwbins = DeviceCapabilities(Printer.DeviceName, Printer.Port, _
    DC_BINS, numBin(1), 0)
    iBinSelected = cbSource.ListIndex + 1
    Printer.PaperBin = numBin(iBinSelected)
    End If
    MsgBox "Page Size: " & Format(Printer.Width / 1440, "#0.0") & _
    " x " & Format(Printer.Height / 1440, "#0.0")
    'Print Map
    '================
    Printer.Print
    frmMap.Map1.OutputMap Printer.hDC
    Printer.EndDoc
    End Sub

  9. Show this form (frmPrint) from another form, for example, frmMain:
    Code:
    Private Sub cmdPrint_Click()
    frmPrint.Show
    End Sub