Change printer tray from vb

Hi all,

I'm looking for a solution to do the following:

I have an ActiveX control, and the only thing this control does is to print a given html page (by url). To do this job, I'm using the WebBrowser control, with code like


Now the problem is that I would like (or, better to say, the clients would like;)) to select the exact printer tray to use.

What I see as a solution would be to find the default printer, and set its (imaginary) DefaultTray property to X, then to call the IE print function.

What do you think?

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

kerznerAuthor Commented:
Well, this works if you want to use the Printer object, and print something with it; however it does not affect the WebBrowser component's print function. What I'm looking for is maybe to change (and save!) the default printer's PaperBin before asking the WebBrowser to print.
kerznerAuthor Commented:
Well, I used the code from this page, and it worked perfectly!!!;EN-US;180645
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

kerznerAuthor Commented:
OK I will give the points to the first one who read this and submits any comment
you can delete the question by posting your comment here
kerznerAuthor Commented:
Thanks, I just did that.
Was looking for a delete/cancel button or something, but there wasn't such thing and I decided it's impossible to cancel a question.
kerznerAuthor Commented:
If one's curious of the code, here it is:
(It is compiled from several places, and can be used to permanently change printer settings, in my case Paper Orientation, but can be used for a wide range of other properties)


Option Explicit

' Constants for DeviceCapabilities
Private Const DC_BINS = 6
Private Const DC_BINNAMES = 12

' Printer Access Levels
Private Const PRINTER_ACCESS_USE As Long = &H8
Private Const STANDARD_RIGHTS_REQUIRED As Long = &HF0000
' Constants for DEVMODE.
Private Const CCHDEVICENAME = 32
Private Const CCHFORMNAME = 32

' Constants for DocumentProperties() call.
Private Const DM_MODIFY = 8
Private Const DM_COPY = 2

' Constants for Orientation.

' Constants for printer bin.
Private Const DMBIN_UPPER = 1
Private Const DMBIN_LOWER = 2

' Constants for DMFIELDS (which fields did you change?).
Private Const DM_ORIENTATION = &H1
Private Const DM_DEFAULTSOURCE = &H200

Private Type DOCINFO
   cbSize As Long
   lpszDocName As String
   lpszOutput As String
End Type

   pDataType As String
   pDevMode As Long
   DesiredAccess As Long
End Type

Private Type PRINTER_INFO_2
   pServerName As Long
   pPrinterName As Long
   pShareName As Long
   pPortName As Long
   pDriverName As Long
   pComment As Long
   pLocation As Long
   pDevMode As Long
   pSepFile As Long
   pPrintProcessor As Long
   pDataType As Long
   pParameters As Long
   pSecurityDescriptor As Long
   Attributes As Long
   Priority As Long
   DefaultPriority As Long
   StartTime As Long
   UntilTime As Long
   Status As Long
   cJobs As Long
   AveragePPM As Long
End Type

Private Type DEVMODE
   dmDeviceName(1 To CCHDEVICENAME) As Byte
   dmSpecVersion As Integer
   dmDriverVersion As Integer
   dmSize As Integer
   dmDriverExtra As Integer
   dmFields As Long
   dmOrientation As Integer
   dmPaperSize As Integer
   dmPaperLength As Integer
   dmPaperWidth As Integer
   dmScale As Integer
   dmCopies As Integer
   dmDefaultSource As Integer
   dmPrintQuality As Integer
   dmColor As Integer
   dmDuplex As Integer
   dmYResolution As Integer
   dmTTOption As Integer
   dmCollate As Integer
   dmFormName(1 To CCHFORMNAME) As Byte
   dmUnusedPadding As Integer
   dmBitsPerPel As Integer
   dmPelsWidth As Long
   dmPelsHeight As Long
   dmDisplayFlags As Long
   dmDisplayFrequency As Long
End Type

Private Declare Function OpenPrinter Lib "winspool.drv" Alias _
    "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As _
    Long, pDefault As Any) As Long

Private Declare Function ClosePrinter Lib "winspool.drv" _
    (ByVal hPrinter As Long) As Long

Private Declare Function GetPrinter Lib "winspool.drv" Alias _
    "GetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, _
   pPrinter As Any, ByVal cbBuf As Long, pcbNeeded As Long) As Long
Private Declare Function SetPrinter Lib "winspool.drv" Alias _
   "SetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, _
   pPrinter As Any, ByVal Command As Long) As Long
Private Declare Function DocumentProperties Lib "winspool.drv" _
    Alias "DocumentPropertiesA" (ByVal hwnd As Long, _
    ByVal hPrinter As Long, ByVal pDeviceName As String, _
    pDevModeOutput As Any, pDevModeInput As Any, _
    ByVal fMode As Long) As Long

Private Declare Function ResetDC Lib "gdi32" Alias "ResetDCA" _
    (ByVal hdc As Long, lpInitData As Any) As Long

Private Declare Function CreateDC Lib "gdi32" Alias "CreateDCA" _
    (ByVal lpDriverName As String, ByVal lpDeviceName As String, _
    ByVal lpOutput As Long, ByVal lpInitData As Long) As Long

Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) _
    As Long

Private Declare Function GetLastError Lib "KERNEL32" () As Long

Private Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" _
    (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)

Function SetPrinterPageSource(PrinterName As String, hPrtDc As Long, PaperSource As Long) As Boolean

   Dim nSize As Long           ' Size of array (used when reading DEVMODE and PRINTER_INFO_2)
   Dim pPrinterInfo2 As PRINTER_INFO_2 ' PRINTER_INFO_2 structure
   Dim pDevMode As DEVMODE             ' DEVMODE structure
   Dim hPrinter As Long        ' Handle to the printer
   Dim LastError As Long       ' Return value for GetLastError
   Dim bPrinterInfo2() As Byte ' The PRINTER_INFO_2 structure in binary format
   Dim bDevMode() As Byte      ' The DEVMODE structure in binary format

   pd.DesiredAccess = PRINTER_ALL_ACCESS
   ' Get a handle to the printer with full access - needed if we want to save our changes permanently
   If OpenPrinter(PrinterName, hPrinter, pd) Then

      ' Read PRINTER_INFO_2 as binary array
      GetPrinter hPrinter, 2&, 0&, 0&, nSize
      ReDim bPrinterInfo2(1 To nSize) As Byte
      GetPrinter hPrinter, 2, bPrinterInfo2(1), nSize, nSize
      ' Fill in the structure
      CopyMemory pPrinterInfo2, bPrinterInfo2(1), Len(pPrinterInfo2)

      ' Get the size of the DEVMODE, passing 0's at the end
      nSize = DocumentProperties(Me.hwnd, hPrinter, PrinterName, 0&, 0&, 0)

      ' Reserve memory for the actual size of the DEVMODE
      ReDim bDevMode(1 To nSize)

      ' Fill the DEVMODE as binary array
      DocumentProperties Me.hwnd, hPrinter, PrinterName, bDevMode(1), 0&, DM_OUT_BUFFER

      ' Copy the predefined portion of the DEVMODE.
      CopyMemory pDevMode, bDevMode(1), Len(pDevMode)

      ' Change the appropriate member in the DevMode.
      'pDevMode.dmDefaultSource = PaperSource
      pDevMode.dmOrientation = DMORIENT_LANDSCAPE

      ' Set the dmFields bit flag to indicate what you're changing.
      'pDevMode.dmFields = pDevMode.dmFields Or DM_DEFAULTSOURCE
      pDevMode.dmFields = pDevMode.dmFields Or DM_ORIENTATION

      ' Copy your changes back, then update DEVMODE.
      CopyMemory bDevMode(1), pDevMode, Len(pDevMode)
      DocumentProperties Me.hwnd, hPrinter, PrinterName, bDevMode(1), bDevMode(1), DM_IN_BUFFER Or DM_OUT_BUFFER

      ' Point PRINTER_INFO_2 at our modified DEVMODE
      pPrinterInfo2.pDevMode = VarPtr(bDevMode(1))
      ' Finally make our changes permanent
      SetPrinter hPrinter, 2, pPrinterInfo2, 0&
      ResetDC hPrtDc, bDevMode(1)   ' Reset the DEVMODE
      ' Close the handle when you're done with it.
      ClosePrinter hPrinter
      SetPrinterPageSource = True

      SetPrinterPageSource = False  ' Reset failed!
      LastError = GetLastError()
      MsgBox "Error setting printer bin. Error Code: " & LastError, vbExclamation, "Print Error"
   End If
End Function
kerznerAuthor Commented:
Oh, and to use the above routine, try for example

   Dim hPrintDC As Long: hPrintDC = CreateDC(Printer.DriverName, Printer.DeviceName, 0, 0)
   SetPrinterPageSource Printer.DeviceName, hPrintDC, SomeTrayNumber

you can get the tray/bin numbers for a printer by the following routine:

' Pass this to a multiline textbox...
Private Function GetPrinterBins(Prn As Printer) As String
   Dim PrinterBins As String
   Dim BinsCount As Long: BinsCount = DeviceCapabilities(Prn.DeviceName, Prn.Port, DC_BINS, ByVal vbNullString, 0)
   Dim BinNumbers() As Integer: ReDim BinNumbers(1 To BinsCount)
   Dim BinNames As String: BinNames = String(24 * BinsCount, 0)
   BinsCount = DeviceCapabilities(Prn.DeviceName, Prn.Port, DC_BINS, BinNumbers(1), 0)
   BinsCount = DeviceCapabilities(Prn.DeviceName, Prn.Port, DC_BINNAMES, ByVal BinNames, 0)
   PrinterBins = PrinterBins & Prn.DeviceName
   Dim BinString As String
   Dim nBin As Integer
   For nBin = 1 To BinsCount
      BinString = Mid(BinNames, 24 * (nBin - 1) + 1, 24)
      BinString = Left(BinString, InStr(1, BinString, Chr(0)) - 1)
      BinString = String(6 - Len(CStr(BinNumbers(nBin))), " ") & BinNumbers(nBin) & "  " & BinString
      PrinterBins = PrinterBins & vbCrLf & BinString
   GetPrinterBins = PrinterBins
End Function

where DeviceCapabilities is declared with:

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



Closed, 500 points refunded.
The Experts Exchange
Community Support Moderator of all Ages

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.