Billie Dee
12/20/2010 10:46:00 PM
On Dec 20, 1:56 pm, "Mike Williams" <M...@WhiskyAndCoke.com> wrote:
> "Billie Dee" <billie...@gmail.com> wrote in message
>
> news:3162897b-3e3a-4d72-93bd-6257449fc1a1@m11g2000vbs.googlegroups.com...
>
> > I using the PrintDialog to choose the printer. Unfortunately,
> > no matter what the user selects - the output always goes
> > to tray 1. We put colored paper in tray 2 for special
> > documents. Programmatically I cannot get the application
> > to print to a different tray. Yes - I can print Work, Excel,
> > etc to the second tray. I just cannot do it programmatically.
> > Any assistance is greatly appreciated.
>
> Presumably you are using the VB Printer Object and its native printing and
> drawing methods to print your stuff but you haven't said which method you
> are using to show the PrintDialog nor which method you are using to set the
> printer and its properties from the user's selections. If you have written
> your code in such a way that it are relies on the dialog to change the
> printer that VB sees (and if you are using the VB Printer Object's native
> methods rather than using API functions to print to the hDC returned by the
> dialog) then generally it will see any change to the actual printer to be
> used but it will not see the properties which your user selects for that
> printer, and so it will not see any change your user makes to the desired
> paper bin. To overcome that problem you need to use additional code to
> transfer the properties selected by the user in the dialog to the VB Printer
> Object. There is a Micro$oft library which will do this for you (search
> Google for msdn vbprndlg.dll). Alternatively, if you would prefer not to use
> an additional library with your project then you can do the same job in
> straight VB code. Here is an example which is based on an earlier Micro$oft
> offering but which I have modified to account for some problems it had,
> including adding code to properly deal with long printer names.
>
> Mike
>
> Option Explicit
> Private Declare Function GetDeviceCaps Lib "gdi32" _
> (ByVal hdc As Long, ByVal nIndex As Long) As Long
> Private Declare Function PrintDialog Lib "comdlg32.dll" _
> Alias "PrintDlgA" (pPrintdlg As PRINTDLG_TYPE) As Long
> Private Declare Sub CopyMemory Lib "kernel32" Alias _
> "RtlMoveMemory" (hpvDest As Any, hpvSource As Any, _
> ByVal cbCopy As Long)
> Private Declare Function GlobalLock Lib "kernel32" _
> (ByVal hMem As Long) As Long
> Private Declare Function GlobalUnlock Lib "kernel32" _
> (ByVal hMem As Long) As Long
> Private Declare Function GlobalAlloc Lib "kernel32" _
> (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
> Private Declare Function GlobalFree Lib "kernel32" _
> (ByVal hMem As Long) As Long
> Private Declare Function SetBkMode Lib "gdi32" _
> (ByVal hdc As Long, ByVal nBkMode As Long) As Long
> Private Const CCHDEVICENAME = 32
> Private Const CCHFORMNAME = 32
> Private Const GMEM_MOVEABLE = &H2
> Private Const GMEM_ZEROINIT = &H40
> Private Const DM_DUPLEX = &H1000&
> Private Const DM_ORIENTATION = &H1&
> Private Const PD_PRINTSETUP = &H40
> Private Const PD_DISABLEPRINTTOFILE = &H80000
> Private Const PHYSICALOFFSETX As Long = 112
> Private Const PHYSICALOFFSETY As Long = 113
> Private Const OPAQUE = 0
> Private Const TRANSPARENT = 1
> Private Type PRINTDLG_TYPE
> lStructSize As Long
> hwndOwner As Long
> hDevMode As Long
> hDevNames As Long
> hdc As Long
> flags As Long
> nFromPage As Integer
> nToPage As Integer
> nMinPage As Integer
> nMaxPage As Integer
> nCopies As Integer
> hInstance As Long
> lCustData As Long
> lpfnPrintHook As Long
> lpfnSetupHook As Long
> lpPrintTemplateName As String
> lpSetupTemplateName As String
> hPrintTemplate As Long
> hSetupTemplate As Long
> End Type
> Private Type DEVNAMES_TYPE
> wDriverOffset As Integer
> wDeviceOffset As Integer
> wOutputOffset As Integer
> wDefault As Integer
> extra As String * 200
> End Type
> Private Type DEVMODE_TYPE
> dmDeviceName As String * CCHDEVICENAME
> 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 As String * CCHFORMNAME
> dmUnusedPadding As Integer
> dmBitsPerPel As Integer
> dmPelsWidth As Long
> dmPelsHeight As Long
> dmDisplayFlags As Long
> dmDisplayFrequency As Long
> dmICMMethod As Long
> dmICMIntent As Long
> dmMediaType As Long
> dmDitherType As Long
> dmReserved1 As Long
> dmReserved2 As Long
> dmPanningWidth As Long
> dmPanningHeight As Long
> End Type
> Private Sub SetPrinterOrigin(x As Single, y As Single)
> With Printer
> .ScaleLeft = .ScaleX(GetDeviceCaps _
> (.hdc, PHYSICALOFFSETX), _
> vbPixels, .ScaleMode) - x
> .ScaleTop = .ScaleY(GetDeviceCaps _
> (.hdc, PHYSICALOFFSETY), _
> vbPixels, .ScaleMode) - y
> .CurrentX = 0
> .CurrentY = 0
> End With
> End Sub
> Private Function SelectPrinter(frmOwner As Form, Optional _
> InitialPrinter As String, Optional _
> PrintFlags As Long = PD_PRINTSETUP) _
> As Boolean
> Dim LongPrinterName As String
> Dim PrintDlg As PRINTDLG_TYPE
> Dim DevMode As DEVMODE_TYPE
> Dim DevName As DEVNAMES_TYPE
> Dim lpDevMode As Long, lpDevName As Long
> Dim bReturn As Integer, OriginalPrinter As String
> Dim p1 As Printer, NewPrinterName As String
> PrintDlg.lStructSize = Len(PrintDlg)
> PrintDlg.hwndOwner = frmOwner.hWnd
> PrintDlg.flags = PrintFlags
> On Error Resume Next
> OriginalPrinter = Printer.DeviceName
> If Len(InitialPrinter) > 0 Then
> For Each p1 In Printers
> If InStr(1, p1.DeviceName, InitialPrinter, _
> vbTextCompare) > 0 Then
> Set Printer = p1
> Exit For
> End If
> Next
> End If
> DevMode.dmDeviceName = Printer.DeviceName
> DevMode.dmSize = Len(DevMode)
> DevMode.dmFields = DM_ORIENTATION
> DevMode.dmPaperWidth = Printer.Width
> DevMode.dmOrientation = Printer.Orientation
> DevMode.dmPaperSize = Printer.PaperSize
> On Error GoTo 0
> PrintDlg.hDevMode = GlobalAlloc(GMEM_MOVEABLE Or _
> GMEM_ZEROINIT, Len(DevMode))
> lpDevMode = GlobalLock(PrintDlg.hDevMode)
> If lpDevMode > 0 Then
> CopyMemory ByVal lpDevMode, DevMode, Len(DevMode)
> bReturn = GlobalUnlock(PrintDlg.hDevMode)
> End If
> With DevName
> .wDriverOffset = 8
> .wDeviceOffset = .wDriverOffset + 1 + Len _
> (Printer.DriverName)
> .wOutputOffset = .wDeviceOffset + 1 + Len(Printer.Port)
> .wDefault = 0
> End With
> With Printer
> DevName.extra = .DriverName & Chr(0) & _
> .DeviceName & Chr(0) & .Port & Chr(0)
> End With
> PrintDlg.hDevNames = GlobalAlloc(GMEM_MOVEABLE Or _
> GMEM_ZEROINIT, Len(DevName))
> lpDevName = GlobalLock(PrintDlg.hDevNames)
> If lpDevName > 0 Then
> CopyMemory ByVal lpDevName, DevName, Len(DevName)
> bReturn = GlobalUnlock(lpDevName)
> End If
> If PrintDialog(PrintDlg) <> 0 Then
> '
> ' Mike's amendment to handle long printer names
> CopyMemory DevName, ByVal lpDevName, Len(DevName)
> LongPrinterName = Mid$(DevName.extra, _
> DevName.wDeviceOffset - DevName.wDriverOffset + 1)
> LongPrinterName = Left$(LongPrinterName, _
> InStr(LongPrinterName, Chr$(0)) - 1)
> DoEvents ' allow dialog to remove itself from display
> Me.Refresh
> SelectPrinter = True
> lpDevName = GlobalLock(PrintDlg.hDevNames)
> CopyMemory DevName, ByVal lpDevName, 45
> bReturn = GlobalUnlock(lpDevName)
> GlobalFree PrintDlg.hDevNames
> lpDevMode = GlobalLock(PrintDlg.hDevMode)
> CopyMemory DevMode, ByVal lpDevMode, Len(DevMode)
> bReturn = GlobalUnlock(PrintDlg.hDevMode)
> GlobalFree PrintDlg.hDevMode
> NewPrinterName = UCase$(Left(DevMode.dmDeviceName, _
> InStr(DevMode.dmDeviceName, Chr$(0)) - 1))
> ' Code now handles long printer names properly
> If Printer.DeviceName <> _
> LongPrinterName Then
> For Each p1 In Printers
> If p1.DeviceName = _
> LongPrinterName Then
> Set Printer = p1
> End If
> Next
> End If
> On Error Resume Next
> ' Transfer settings from the Devmode structure to the
> ' VB printer object (this example just transfers some
> ' of them but you can of course use transfer more)
> Printer.Copies = DevMode.dmCopies
> Printer.Duplex = DevMode.dmDuplex
> Printer.Orientation = DevMode.dmOrientation
> Printer.PaperSize = DevMode.dmPaperSize
> Printer.PrintQuality = DevMode.dmPrintQuality
> Printer.ColorMode = DevMode.dmColor
> Printer.PaperBin = DevMode.dmDefaultSource
> SetBkMode Printer.hdc, TRANSPARENT
> '
> On Error GoTo 0
> Else
> SelectPrinter = False ' user cancelled
> For Each p1 In Printers
> If p1.DeviceName = OriginalPrinter Then
> Set Printer = p1
> Exit For
> End If
> Next
> GlobalFree PrintDlg.hDevNames
> GlobalFree PrintDlg.hDevMode
> End If
> End Function
> Private Sub Command1_Click()
> ' Note: Specifying Printer.DeviceName in the following
> ' line will start the dialog off with the default
> ' printer initially selected in the selection box, but
> ' you can use any other string you wish. For example,
> ' using "Epson" will cause the dialog to start with
> ' the first printer it finds with the word "Epson"
> ' in its device name.
> If SelectPrinter(Me, Printer.DeviceName) Then
> Printer.TrackDefault = False
> Printer.ScaleMode = vbInches
> ' set origin to top left corner of physical page
> ' (otherwise it would be the top left corner of
> ' the printable area, which is not the same)
> SetPrinterOrigin 0, 0
> Printer.CurrentX = 1: Printer.CurrentY = 1
> Printer.Print "Hello World"
> Printer.EndDoc
> End If
> End Sub
Thank you both for responding. I'm using VS2005 VB. And, yes, I'm
using the vanilla PrintDialog and expecting it to be smart enough to
acknowledge a tray selection. I tried adding the DLL - but no matter
what I did I could not get the PrintDlg object to initialize. I tried
adding Mike's code. (very readable btw) but there were too many
inconsistencies to straighten out quickly. I assume it's a different
flavor of VB. I have a direction now - and any additional nudges will
be appreciated. I hate it when code makes me feel stupid.