First, thanks to both ABBKlaus and Shardik for help, code and suggestions.
@Shardik
Your last code fails to duplex here on WinXPPro SP2 and my Brother
HL-5170DNLT printer. Otherwise it prints properly. Isn't Windows
frustrating? And, before you ask, the driver is configured correctly.
By using Shardik's code as modified by ABBKlaus I was able to find my
solution. Since that code only used the default printer, I then made the
changes ABBKlaus and Shardik discussed in my own code and it now
works for the default or a selected printer.
Here is the kicker, and now that I have found the problem it probably
seems obvious. (At least on my printers) You can't change the duplexing
mode mid print job. You can change the orientation and paper source
inside the print job, but not the duplexing mode.
Thanks to both of you for your help and suggestions.
Here is my code modifed and working:
Code: Select all
; PrintRequesterEX - modified Nov 09, 2006
; Modified from code example by Siegfried Rings with help
; from Edwin Knoppert, Shardik, Xombie, Sparkie, and ABBKlaus
; The following code is a test of:
; 1) Selecting the printer (or using the default printer) and starting a print job
; 2) Print a page from the upper tray in portrait mode
; 3) Print a page from the lower tray in landscape mode
; 4) Print two pages in duplex mode from the upper tray in portrait mode
#Window = 0
Pgm$="Printer mode testing" ; Title of this program's window
; Globals needed
Global *Ptr_DEVMODE.l
Global DocInf.DOCINFO
Global lpszDriver.s
Global PrintDlg.PRINTDLG
Global PrinterName$ = Space(260)
Global Msg.s
Procedure PrintRequesterEX(UseDefaultPrinter.l = 1)
; Determine the spooler name
Select OSVersion()
Case #PB_OS_Windows_98, #PB_OS_Windows_ME
lpszDriver.s = ""
Case #PB_OS_Windows_2000, #PB_OS_Windows_XP
lpszDriver.s = "WINSPOOL"
Default
lpszDriver = "WINSPOOL"
EndSelect
; --------------------------
; Create the print dialog the way I want it to look, or create it
; and bypass the display when set to use the default printer.
;
; Set the PRINTDLG structure to desired settings to modify the appearance of the Printer Dialog
PrintDlg\lStructSize = SizeOf(PRINTDLG)
PrintDlg\hwndOwner = WindowID(#Window)
PrintDlg\hDevMode = #Null
PrintDlg\hDevNames = #Null
PrintDlg\Flags = #PD_RETURNDC | #PD_ALLPAGES | #PD_HIDEPRINTTOFILE |#PD_NOSELECTION
PrintDlg\nFromPage = 0
PrintDlg\nToPage = 0
PrintDlg\nMinPage = 1
PrintDlg\nMaxPage = 1
PrintDlg\nCopies = 1
If UseDefaultPrinter
PrintDlg\Flags = PrintDlg\Flags | #PD_RETURNDEFAULT
EndIf
; --------------------------
; Call the modified Printer Dialog --
If PrintDlg_(PrintDlg)
*DEVNAMES.DEVNAMES = GlobalLock_(PrintDlg\hDevNames)
PrinterName$ = PeekS(*DEVNAMES + *DEVNAMES\wDeviceOffset)
GlobalUnlock_(PrintDlg\hDevNames)
Static PrinterHandle.l = 0
OpenPrinter_(Printername$,@PrinterHandle.l,0)
Buffersize.l = DocumentProperties_(0, Printerhandle, @PrinterName$, 0, 0, 0)
*Ptr_DEVMODE = AllocateMemory(Buffersize)
DocumentProperties_(0, Printerhandle, @PrinterName$, *Ptr_DEVMODE , 0, #DM_OUT_BUFFER)
ClosePrinter_(PrinterHandle)
ProcedureReturn #True
Else
Msg.s = "Printer selection result: "
If CommDlgExtendedError_() <> 0
Msg + "Error code: " + Str(CommDlgExtendedError_())
Else
Msg + "User cancelled"
EndIf
ProcedureReturn #False
EndIf
; --------------------------
EndProcedure
hWnd = OpenWindow(#Window, 0, 0, 490, 420,Pgm$, #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
If hWnd
CreateGadgetList(WindowID(0))
result = PrintRequesterEX(#True)
; The default to use the Default Printer
; UseDefaultPrinter = absent or #TRUE = automatically select the default printer,
; #FALSE = modified print requester dialog is used.
If result
; The printer was chosen, now make any modifications to the printer's defaults desired.
; Create a DEVMODE structure at the memory address returned by the printer selection.
*New_DEVMODE.DEVMODE=*Ptr_DEVMODE
; The structure dmFields member must have bit flags set for the fields to be modified, so set them.
*New_DEVMODE\dmFields|#DM_ORIENTATION | #DM_DEFAULTSOURCE | #DM_DUPLEX
; Put the desired setup in the appropriate members as defined in dmFields
*New_DevMode\dmOrientation = #DMORIENT_PORTRAIT ; Set to Portrait
*New_DevMode\dmDefaultsource = #DMBIN_UPPER ; Set to Upper Tray
*New_DEVMODE\dmDuplex = #DMDUP_SIMPLEX ; Set to Single Sided
; ; Show some printer setup information -------------------------------------
; ; Show printer information - useful while debugging
; Info.s = "Printername =" + #TAB$ +PrinterName$ + #LF$
; Info.s + "Copies =" + #TAB$ +Str(*New_DEVMODE\dmCopies) + #LF$
; Info.s + "FromPage =" + #TAB$ +Str(PrintDlg\nFromPage) + #LF$
; Info.s + "ToPage =" + #TAB$ +Str(PrintDlg\nToPage) + #LF$
; Info.s + "Quality =" + #TAB$ +Str(*New_DEVMODE\dmPrintQuality) + #LF$
; Info.s + "Color =" + #TAB$ +Str(*New_DEVMODE\dmColor) + #LF$
; Select *New_DEVMODE\dmOrientation
; Case #DMORIENT_PORTRAIT
; Orientation$ = "Portrait"
; Case #DMORIENT_LANDSCAPE
; Orientation$ = "Landscape"
; EndSelect
; Info.s + "Orientation =" + #TAB$ + Orientation$ + #LF$
; Select *New_DEVMODE\dmDefaultsource
; Case #DMBIN_UPPER
; Source$ = "Upper Tray"
; Case #DMBIN_LOWER
; Source$ = "Lower Tray"
; EndSelect
; Info.s + "Papersource =" + #TAB$ + Source$ + #LF$
; Select *New_DEVMODE\dmDuplex
; Case #DMDUP_SIMPLEX
; Duplex$ = "Single sided"
; Case #DMDUP_VERTICAL
; Duplex$ = "Front and back, long side"
; Case #DMDUP_HORIZONTAL
; Duplex$ = "Front and back, short side"
; Default
; Duplex$ = "Not available"
; EndSelect
; Info.s + "Duplex mode =" + #TAB$ + Duplex$ + #LF$
; MessageRequester("Info",Info,#MB_ICONINFORMATION)
; End
; ;---------------------------------------------------------------------------
If PrinterName$ > "" ; There is a valid printer selected.
If PrinterDC.l ; If the printer already opened, close it.
ClosePrinter_(PrinterDC)
PrinterDC = 0
EndIf
; Create a printer device context with the desired DEVMODE settings
PrinterDC = CreateDC_(@lpszDriver, PrinterName$, #Null, *Ptr_DEVMODE) ; Returns 0 if it fails
If PrinterDC ; The printer device context was created successfully.
; Create a DOCINFO struction to contain information about the document to be printed
DocInf\cbSize = SizeOf(DOCINFO)
DocInf\lpszDocName = @"Purebasic PrintRequesterEX Test" ; Store the document title
DocInf\lpszOutput = #Null ; Optionally use a pointer to a null-terminated Filename.ext string
; to send the printout to a file
; Eg. DocInf\lpszOutput = @"C:\TEST.TXT"
If StartDoc_(PrinterDC,@DocInf) ; The document was started successfully.
If StartPage_(PrinterDC) ; The page was created successfully.
Text$ = "Which way did this print? Should be Portrait from Upper Tray."
; Pass Col & Row (integers in DPI offset) to the TextOut API
TextOut_(PrinterDC, 300, 100, Text$, Len(Text$)) ; Returns 0 if fails
EndPage_(PrinterDC) ; Returns 0 if fails
EndIf
; ResetDC_ cannot be done inside a StartPage_. It will be ignored. You can
; ResetDC_ following an EndPage_ and before the next StartPage_.
; It should be handled this way for backwards compatibility with Win95, 98, ME.
; Set DEVMODE properties to Landscape and Lower Tray
*New_DevMode\dmOrientation = #DMORIENT_LANDSCAPE ; Set to Landscape
*New_DevMode\dmDefaultsource = #DMBIN_LOWER ; Set to Lower Tray
If ResetDC_(PrinterDC,*Ptr_DEVMODE) = PrinterDC ; Reset the printer's dc to new DEVMODE
If StartPage_(PrinterDC)
Text$ = "And where did this one print? Should be Landscape from Lower Tray"
TextOut_(PrinterDC, 60, 300,Text$,Len(Text$))
EndPage_(PrinterDC)
EndIf
Else
MessageRequester(Pgm$ + "Printer Reset","ResetDC_ failed.",#MB_ICONERROR)
EndIf
EndDoc_(PrinterDC) ; Returns 0 if fails
EndIf
; The dmDuplex setting cannot be changed mid document. So, lets start a new document
; after changing that setting.
; Set DEVMODE properties to Portrait from Upper Tray in Duplex mode.
*New_DEVMODE.DEVMODE=*Ptr_DEVMODE
*New_DEVMODE\dmFields|#DM_ORIENTATION | #DM_DEFAULTSOURCE | #DM_DUPLEX
*New_DevMode\dmOrientation = #DMORIENT_PORTRAIT ; Set to Portrait
*New_DevMode\dmDefaultsource = #DMBIN_UPPER ; Set to Upper Tray
*New_DEVMODE\dmDuplex = #DMDUP_VERTICAL ; Set to Duplex, long edge
If ResetDC_(PrinterDC,*Ptr_DEVMODE) = PrinterDC ; Reset the printer's dc to new DEVMODE
If StartDoc_(PrinterDC,@DocInf)
If StartPage_(PrinterDC)
Text$ = "And where did this one print? Should be Portrait from Upper Tray"
TextOut_(PrinterDC, 60, 300,Text$,Len(Text$))
EndPage_(PrinterDC)
EndIf
If StartPage_(PrinterDC)
Text$ = "And this should be on the back of the previous page (duplex)."
TextOut_(PrinterDC, 60, 300,Text$,Len(Text$))
EndPage_(PrinterDC)
EndIf
EndDoc_(PrinterDC)
EndIf
Else
MessageRequester(Pgm$ + "Printer Reset","ResetDC_ failed.",#MB_ICONERROR)
EndIf
EndIf
DeleteDC_(PrinterDC) ; Delete the printer's dc
Else
; The printer's device context could not be created. Windows may have already displayed a
; message describing the reason, or the DEVMODE is incorrectly configured. Windows does
; not directly return a failure code.
MessageRequester(Pgm$ + " Printer Open","The selected printer could not be opened for use.",#MB_ICONSTOP)
EndIf
Else
; The printer selection failed or was cancelled by the user. The reason was passed back from
; the PrintRequesterEX procedure in the global Msg.s
MessageRequester(Pgm$ + " Printer Selection",Msg,#MB_ICONSTOP)
EndIf
EndIf
End