From: M Wade on
I have an application that printed multiple pages and I have a printer
(BROTHER 5370DW) that allows this. I select the printer using the
CommonDialog1.ShowPrinter command and then click on the printer
preferences to select two-sided printing. However, when the actual
printing takes place is does not print two-sided.

Is there something in VB print methods that would over-ride this option
or not allow it?

Marv
From: Shotgun Thom on
On Jun 15, 2:40 pm, M Wade <nowh...(a)columbus.rr.com> wrote:
> I have an application that printed multiple pages and I have a printer
> (BROTHER 5370DW) that allows this.  I select the printer using the
> CommonDialog1.ShowPrinter command and then click on the printer
> preferences to select two-sided printing.  However, when the actual
> printing takes place is does not  print  two-sided.
>
> Is there something in VB print methods that would over-ride  this option
> or not allow it?
>
> Marv

Hi Marv:

While the VB6 Printer Object has a duplex setting (Printer.Duplex) I
don't believe the CommonDialog has that property.

Sooo... you need to Apply the setting using your Brother Print Setup.
I know you think you are doing that now by clicking on the Printer
Preferences button... but unfortunately it doesn't get translated to
the print object or to common dialog.

The answer is to right click on the Brother printer icon in the print
dialog and choose Printer Preferences from the context menu that pops
up. You'll note in this option an "Apply":button magically appears in
the setup window. After you've set your options then click Apply,
then Ok. Now the duplex thing should work. You'll need to go back to
undo duplex when finished since that has now become the default. The
Apply button only appears when choosing Printing Preferences from the
context menu. It is not available if you just click the Preference
button.

The other way would be to create your own duplex option variable. A
value of 1 is simplex (singled sided), 2 is double sided horizontal
and 3 is double sided vertical.

Tom

From: Mike Williams on
"M Wade" <nowhere(a)columbus.rr.com> wrote in message
news:us2krNNDLHA.3492(a)TK2MSFTNGP02.phx.gbl...

> I have an application that printed multiple pages and
> I have a printer (BROTHER 5370DW) that allows this.
> I select the printer using the CommonDialog1.ShowPrinter
> command and then click on the printer preferences to select
> two-sided printing. However, when the actual printing
> takes place is does not print two-sided. Is there something
> in VB print methods that would over-ride this option or not allow it?

Under normal usage (from WinXP onwards) the CommonDialog Control changes
only the printer to be used and not any of its properties (although the user
can on most systems manually edit the properties in the dialog by right
clicking as suggested by Shotgun Thom, but in that case you need to
specifically advise your user to do something that he would not normally do
and those edits would "stick" beyond your own application and become the
default properties for all applications unless you asked your user to
specifically negate them afterwards, and for both of those reasons it is not
something I would advise).

If you want to change the VB Printer Object's properties to those selected
by the user in the CommonDialog then you need to transfer them from the
CommonDialog properties to the equivalent VB Printer Object properties.
However, the CommonDialog Control does not have a Duplex property and so you
cannot do that in this specific case. In any case, I would personally advise
against using the CommonDialog in the normal way anyway, because when the
user selects a printer in it then that printer becomes the user's new system
default printer (unless you set the PrinterDefault property to False, which
in most cases defeats the object altogether). This is not how most
applications behave. The best way is to allow your user to select the
desired printer and for that printer to be used only for your own VB
application, without it altering the user's system default printer or any of
its default properties.

Of all the available methods (of which there are many) the one I would
advise you to use is to display a printer dialog (using either the
CommonDialog Control or the equivalent API dialog) and ask it to return a DC
for you. Your VB application can then print to that returned DC safe in the
knowledge that the printer will be set up /exactly/ as the user has selected
in the printer dialog, including all of the sometimes rather esoteric
settings that certain specialist printers have and that are simply not
accessible by any other means (for example, the "use metallic gold ribbon"
setting on a Citizen Printiva printer, which is something that Windows
itself knows nothing about). That is by far the best method, and it is
essentially the method used by most professional applications. The problem
with this method of course is that you cannot effectively use it with the VB
Printer Object and so you will need to perform all your printing output
using the equivalent API printing methods. It is however what I would
advise.

If you woud prefer to stick with the VB Printer Object then there are other
methods you can use to display a dialog that returns more information for
you than does the CommonDialog Control, and that avoids the "printer
settings sticks as the default" problem and allows your use to select from
most of the common properties, including your own desired duplex printing
option. Your code can then transfer those settings to the VB printer Object
for printing.

There is a Micro$oft DLL that can help you to do this (from memory I think
it is called msvbprndlg.dll or something similar) but you can do the same
sort of thing without needing to package a DLL by using standard API dialog
calls, although you need to take account of the fact that some printers
(probably mostly network printers) have a device name that is longer than
the standard maximum 32 character length for dmDeviceName in the DEVMODE
structure and so you need to make sure that your code takes account of such
a possibility. As they say in all the best TV cookery programs, here's
something I prepared earlier (see below) ;-)

Printing is still an evolving thing of course, and so if this code does not
work for your specific printer then perhaps you might like to consider my
other suggestion (asking the printer dialog to return a DC for you and
printing to that DC using API printing methods, which will definitely work
as long as your printer driver is installed properly). If you have any
problems then post again, although I imagine that the following code will
probably do the trick for you (paste it into a VB Form):

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
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))
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












From: M Wade on
Mike,I much appreciate you response and that from Shotgun Thom. My use
of VB6 is almost totally for my own use and some I have developed for
churches and a privately owned travel agency, so I am not a professional
programmer. The specific program I am working on now is to catalog
books and being able to search by author's name,Book Series and Book
Title. If I print all of the entries it could go quite a few pages,
hence the desire to use the duplex capability of the printer which is a
network device.

I can easily change the printer setting before running the program and
reset it after the printing is done but I am interested enough to want
to try something within the program. At age 77 and long retired I have
the time to do that (hopefully).

I am not very clear on using APIs and haven't the foggiest idea what
the reference to DC is, but I am going to see if I can understand the
code you supplied.

Thanks again.

Marv





On 6/16/2010 12:52 PM, Mike Williams wrote:
> "M Wade"<nowhere(a)columbus.rr.com> wrote in message
> news:us2krNNDLHA.3492(a)TK2MSFTNGP02.phx.gbl...
>
>> I have an application that printed multiple pages and
>> I have a printer (BROTHER 5370DW) that allows this.
>> I select the printer using the CommonDialog1.ShowPrinter
>> command and then click on the printer preferences to select
>> two-sided printing. However, when the actual printing
>> takes place is does not print two-sided. Is there something
>> in VB print methods that would over-ride this option or not allow it?
>
> Under normal usage (from WinXP onwards) the CommonDialog Control changes
> only the printer to be used and not any of its properties (although the user
> can on most systems manually edit the properties in the dialog by right
> clicking as suggested by Shotgun Thom, but in that case you need to
> specifically advise your user to do something that he would not normally do
> and those edits would "stick" beyond your own application and become the
> default properties for all applications unless you asked your user to
> specifically negate them afterwards, and for both of those reasons it is not
> something I would advise).
>
> If you want to change the VB Printer Object's properties to those selected
> by the user in the CommonDialog then you need to transfer them from the
> CommonDialog properties to the equivalent VB Printer Object properties.
> However, the CommonDialog Control does not have a Duplex property and so you
> cannot do that in this specific case. In any case, I would personally advise
> against using the CommonDialog in the normal way anyway, because when the
> user selects a printer in it then that printer becomes the user's new system
> default printer (unless you set the PrinterDefault property to False, which
> in most cases defeats the object altogether). This is not how most
> applications behave. The best way is to allow your user to select the
> desired printer and for that printer to be used only for your own VB
> application, without it altering the user's system default printer or any of
> its default properties.
>
> Of all the available methods (of which there are many) the one I would
> advise you to use is to display a printer dialog (using either the
> CommonDialog Control or the equivalent API dialog) and ask it to return a DC
> for you. Your VB application can then print to that returned DC safe in the
> knowledge that the printer will be set up /exactly/ as the user has selected
> in the printer dialog, including all of the sometimes rather esoteric
> settings that certain specialist printers have and that are simply not
> accessible by any other means (for example, the "use metallic gold ribbon"
> setting on a Citizen Printiva printer, which is something that Windows
> itself knows nothing about). That is by far the best method, and it is
> essentially the method used by most professional applications. The problem
> with this method of course is that you cannot effectively use it with the VB
> Printer Object and so you will need to perform all your printing output
> using the equivalent API printing methods. It is however what I would
> advise.
>
> If you woud prefer to stick with the VB Printer Object then there are other
> methods you can use to display a dialog that returns more information for
> you than does the CommonDialog Control, and that avoids the "printer
> settings sticks as the default" problem and allows your use to select from
> most of the common properties, including your own desired duplex printing
> option. Your code can then transfer those settings to the VB printer Object
> for printing.
>
> There is a Micro$oft DLL that can help you to do this (from memory I think
> it is called msvbprndlg.dll or something similar) but you can do the same
> sort of thing without needing to package a DLL by using standard API dialog
> calls, although you need to take account of the fact that some printers
> (probably mostly network printers) have a device name that is longer than
> the standard maximum 32 character length for dmDeviceName in the DEVMODE
> structure and so you need to make sure that your code takes account of such
> a possibility. As they say in all the best TV cookery programs, here's
> something I prepared earlier (see below) ;-)
>
> Printing is still an evolving thing of course, and so if this code does not
> work for your specific printer then perhaps you might like to consider my
> other suggestion (asking the printer dialog to return a DC for you and
> printing to that DC using API printing methods, which will definitely work
> as long as your printer driver is installed properly). If you have any
> problems then post again, although I imagine that the following code will
> probably do the trick for you (paste it into a VB Form):
>
> 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
> 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))
> 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
>
>
>
>
>
>
>
>
>
>
>
>

From: M Wade on
Mike,I much appreciate you response and that from Shotgun Thom. My use
of VB6 is almost totally for my own use and some I have developed for
churches and a privately owned travel agency, so I am not a professional
programmer. The specific program I am working on now is to catalog
books and being able to search by author's name,Book Series and Book
Title. If I print all of the entries it could go quite a few pages,
hence the desire to use the duplex capability of the printer which is a
network device.

I can easily change the printer setting before running the program and
reset it after the printing is done but I am interested enough to want
to try something within the program. At age 77 and long retired I have
the time to do that (hopefully).

I am not very clear on using APIs and haven't the foggiest idea what
the reference to DC is, but I am going to see if I can understand the
code you supplied.

Thanks again.

Marv





On 6/16/2010 12:52 PM, Mike Williams wrote:
> "M Wade"<nowhere(a)columbus.rr.com> wrote in message
> news:us2krNNDLHA.3492(a)TK2MSFTNGP02.phx.gbl...
>
>> I have an application that printed multiple pages and
>> I have a printer (BROTHER 5370DW) that allows this.
>> I select the printer using the CommonDialog1.ShowPrinter
>> command and then click on the printer preferences to select
>> two-sided printing. However, when the actual printing
>> takes place is does not print two-sided. Is there something
>> in VB print methods that would over-ride this option or not allow it?
>
> Under normal usage (from WinXP onwards) the CommonDialog Control changes
> only the printer to be used and not any of its properties (although the user
> can on most systems manually edit the properties in the dialog by right
> clicking as suggested by Shotgun Thom, but in that case you need to
> specifically advise your user to do something that he would not normally do
> and those edits would "stick" beyond your own application and become the
> default properties for all applications unless you asked your user to
> specifically negate them afterwards, and for both of those reasons it is not
> something I would advise).
>
> If you want to change the VB Printer Object's properties to those selected
> by the user in the CommonDialog then you need to transfer them from the
> CommonDialog properties to the equivalent VB Printer Object properties.
> However, the CommonDialog Control does not have a Duplex property and so you
> cannot do that in this specific case. In any case, I would personally advise
> against using the CommonDialog in the normal way anyway, because when the
> user selects a printer in it then that printer becomes the user's new system
> default printer (unless you set the PrinterDefault property to False, which
> in most cases defeats the object altogether). This is not how most
> applications behave. The best way is to allow your user to select the
> desired printer and for that printer to be used only for your own VB
> application, without it altering the user's system default printer or any of
> its default properties.
>
> Of all the available methods (of which there are many) the one I would
> advise you to use is to display a printer dialog (using either the
> CommonDialog Control or the equivalent API dialog) and ask it to return a DC
> for you. Your VB application can then print to that returned DC safe in the
> knowledge that the printer will be set up /exactly/ as the user has selected
> in the printer dialog, including all of the sometimes rather esoteric
> settings that certain specialist printers have and that are simply not
> accessible by any other means (for example, the "use metallic gold ribbon"
> setting on a Citizen Printiva printer, which is something that Windows
> itself knows nothing about). That is by far the best method, and it is
> essentially the method used by most professional applications. The problem
> with this method of course is that you cannot effectively use it with the VB
> Printer Object and so you will need to perform all your printing output
> using the equivalent API printing methods. It is however what I would
> advise.
>
> If you woud prefer to stick with the VB Printer Object then there are other
> methods you can use to display a dialog that returns more information for
> you than does the CommonDialog Control, and that avoids the "printer
> settings sticks as the default" problem and allows your use to select from
> most of the common properties, including your own desired duplex printing
> option. Your code can then transfer those settings to the VB printer Object
> for printing.
>
> There is a Micro$oft DLL that can help you to do this (from memory I think
> it is called msvbprndlg.dll or something similar) but you can do the same
> sort of thing without needing to package a DLL by using standard API dialog
> calls, although you need to take account of the fact that some printers
> (probably mostly network printers) have a device name that is longer than
> the standard maximum 32 character length for dmDeviceName in the DEVMODE
> structure and so you need to make sure that your code takes account of such
> a possibility. As they say in all the best TV cookery programs, here's
> something I prepared earlier (see below) ;-)
>
> Printing is still an evolving thing of course, and so if this code does not
> work for your specific printer then perhaps you might like to consider my
> other suggestion (asking the printer dialog to return a DC for you and
> printing to that DC using API printing methods, which will definitely work
> as long as your printer driver is installed properly). If you have any
> problems then post again, although I imagine that the following code will
> probably do the trick for you (paste it into a VB Form):
>
> 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
> 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))
> 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
>
>
>
>
>
>
>
>
>
>
>
>