thank you for posting your solution. I am glad that you found a solution for your printing problems.
I owe you very much for your source code (especially the FTP File Exchanger from 05/20/2003 and several other programs. I learned a lot from it for my own FTP client Trex-FTP which transfers data between a PC and a huge IBM mainframe (T-rex). Especially the use of Win-API routines and your animation routines were implemented by me and make this program very fast and user friendly. Unfortunately this is no freeware because it was part of my job as a z/OS systems programmer and I was paid to develop this software. But of course I hope to give back some tricks and snippets of my own to the community.
I have still another (very complicated) solution for those who want to change the default settings of duplex or page orientation without displaying a print dialog. These settings remain intact even if you reboot your computer.
I developped this solution because I needed a possibility to print hundreds of PDF documents from within one application without the need to manually start the Acrobat reader and to load and print each document separately. The trick is to use the rather old Acrobat reader 4, which was the last version with (undocumented) switches to control it with batch commands for document name, printer port etc (via RunProgram()). Because you have no influence on the printer driver which is controlled by the Acrobat reader, you have no possibility to change the Acrobat reader's printer settings. Therefore I developped the following solution which changes the printer settings of a single printer permanently (not only for one single printout) until you change the setting again programmatically or manually via the print requester.
Code: Select all
;=============================================================================
; Change global default settings for a printer
;
; Source code example from Microsoft in VisualBASIC for Word:
; "HOWTO: Set Duplex Printing for Word Automation"
; http://support.microsoft.com/kb/230743/en-us
;=============================================================================
Enumeration
#WindowPrinterDefaultSettings
EndEnumeration
Enumeration
#ComboPrinterNames
#FrameDuplex
#OptionHorizontal
#OptionVertical
#FrameSimplexDuplex
#OptionSimplex
#OptionDuplex
#FrameOrientation
#OptionPortrait
#OptionLandscape
#ButtonChange
#ButtonCancel
EndEnumeration
DuplexMode.W
NewDuplexState.W
NewPageOrientation.W
NumInstalledPrinters.W
OldDuplexState.W
OldPageOrientation.W
PageOrientation.W
WindowEvent.L
NewList PrinterName.S()
Declare.L ChangePrinterDefaultSettings(PrinterName.S)
Declare.W GetInstalledPrinters()
NumInstalledPrinters = GetInstalledPrinters()
If NumInstalledPrinters = 0
MessageRequester("Error", "Sorry, no installed printers found!", #MB_ICONERROR)
End
EndIf
OpenWindow(#WindowPrinterDefaultSettings, 516, 412, 272, 347, "Change Printer Default Settings", #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered)
CreateGadgetList(WindowID(#WindowPrinterDefaultSettings))
ComboBoxGadget(#ComboPrinterNames, 50, 15, 170, 70)
Frame3DGadget(#FrameDuplex, 50, 212, 177, 63, "")
OptionGadget(#OptionHorizontal, 62, 224, 159, 24, "Short Edge")
OptionGadget(#OptionVertical, 62, 248, 159, 24, "Long Edge (Book format)")
ButtonGadget(#ButtonChange, 40, 306, 72, 24, "Change")
ButtonGadget(#ButtonCancel, 156, 306, 72, 24, "Cancel")
Frame3DGadget(#FrameSimplexDuplex, 17, 148, 236, 138, "Simplex or Duplex Print")
OptionGadget(#OptionSimplex, 32, 170, 210, 24, "Print only on one side of page (Simplex)")
OptionGadget(#OptionDuplex, 32, 194, 210, 24, "Print on both sides of page (Duplex)")
Frame3DGadget(#FrameOrientation, 80, 50, 104, 76, "Page Orientation")
OptionGadget(#OptionPortrait, 92, 70, 80, 20, "Portrait")
OptionGadget(#OptionLandscape, 92, 94, 80, 20, "Landscape")
PageOrientation = #DMORIENT_PORTRAIT
SetGadgetState(#OptionPortrait, #True)
DuplexMode = #DMDUP_SIMPLEX
SetGadgetState(#OptionSimplex, #True)
DisableGadget(#FrameDuplex, #True)
DisableGadget(#OptionHorizontal, #True)
DisableGadget(#OptionVertical, #True)
ForEach PrinterName()
AddGadgetItem(#ComboPrinterNames, -1, PrinterName())
Next
SetGadgetState(#ComboPrinterNames, 0)
Repeat
WindowEvent = WaitWindowEvent()
If WindowEvent = #PB_Event_Gadget
Select EventGadget()
Case #OptionPortrait
PageOrientation = #DMORIENT_PORTRAIT
Case #OptionLandscape
PageOrientation = #DMORIENT_LANDSCAPE
Case #OptionSimplex
DisableGadget(#FrameDuplex, #True)
DisableGadget(#OptionHorizontal, #True)
DisableGadget(#OptionVertical, #True)
Case #OptionDuplex
DisableGadget(#FrameDuplex, #False)
DisableGadget(#OptionHorizontal, #False)
DisableGadget(#OptionVertical, #False)
SetGadgetState(#OptionVertical, #True)
Case #ButtonChange
If GetGadgetState(#OptionSimplex) = #True
DuplexMode = #DMDUP_SIMPLEX
Else
If GetGadgetState(#OptionHorizontal) = #True
DuplexMode = #DMDUP_HORIZONTAL
Else
DuplexMode = #DMDUP_VERTICAL
EndIf
EndIf
If ChangePrinterDefaultSettings(GetGadgetText(#ComboPrinterNames)) = #True
MessageRequester("Printer Settings", "Printer: " + GetGadgetText(#ComboPrinterNames) + #CR$ + #CR$ + "Old Page Orientation: " + Str(OldPageOrientation) + #CR$ + "New Page Orientation: " + Str(NewPageOrientation) + #CR$ + "Old Duplex Setting: " + Str(OldDuplexState) + #CR$ + "New Duplex Setting: " + Str(NewDuplexState))
EndIf
Break
Case #ButtonCancel
Break
EndSelect
EndIf
Until WindowEvent = #PB_Event_CloseWindow
End
Procedure.L ChangePrinterDefaultSettings(PrinterName.S)
Shared DuplexMode.W
Shared NewDuplexState.W
Shared NewPageOrientation.W
Shared OldDuplexState.W
Shared OldPageOrientation.W
Shared PageOrientation.W
Shared PrinterName.S()
BufferSize.L
BytesRetrieved.L
*DEVMODEBuffer.DEVMODE
*DEVMODEBufferCopy.DEVMODE
DOCINFOStructure.DOCINFO
ErrorMsg.S
ModeFlag.L
PrintText.S
PRINTER_DEFAULTSStructure.PRINTER_DEFAULTS
*PRINTER_INFO_2Buffer.PRINTER_INFO_2
*PRINTER_INFO_2BufferCopy.PRINTER_INFO_2
PrinterHandle.L
Result.L
; ----- Get printer handle
PRINTER_DEFAULTSStructure\DesiredAccess = #STANDARD_RIGHTS_REQUIRED | #PRINTER_ACCESS_ADMINISTER | #PRINTER_ACCESS_USE
Result = OpenPrinter_(@PrinterName, @PrinterHandle, @PRINTER_DEFAULTSStructure)
If Result = #False Or PrinterHandle = 0
ErrorMsg = "Could not obtain printer handle!"
Result = #False
Goto CleanUp
EndIf
; ----- Get buffer size for DEVMODE structure
ModeFlag = 0
BufferSize = DocumentProperties_(0, PrinterHandle, @PrinterName, 0, 0, ModeFlag)
If BufferSize < 0 Or ModeFlag <> 0
ErrorMsg = "The size of the DEVMODE structure couldn't be obtained!"
Goto CleanUp
End
EndIf
; ----- Get memory buffer for DEVMODE structure
*DEVMODEBuffer = AllocateMemory(BufferSize)
If *DEVMODEBuffer = 0
ErrorMsg = "A memory request for the DEVMODE structure failed!"
Result = #False
Goto CleanUp
EndIf
; ----- Get memory buffer for copy of DEVMODE structure
*DEVMODEBufferCopy = AllocateMemory(BufferSize)
If *DEVMODEBufferCopy = 0
ErrorMsg = "A memory request for a copy of the DEVMODE structure failed!"
Result = #False
Goto CleanUp
EndIf
; ----- Generate DEVMODE structure
Result = DocumentProperties_(0, PrinterHandle, @PrinterName, *DEVMODEBuffer, 0, #DM_OUT_BUFFER)
If Result < 0
ErrorMsg = "The request for the DEVMODE structure failed!"
Result = #False
Goto CleanUp
EndIf
; ----- Copy DEVMODE structure
CopyMemory(*DEVMODEBuffer, *DEVMODEBufferCopy, BufferSize)
; ----- Does driver allow to activate duplex setting?
If *DEVMODEBufferCopy\dmFields & #DM_DUPLEX <> #DM_DUPLEX
ErrorMsg = "The duplex setting cannot be activated for this printer!"
Result = #False
Goto CleanUp
EndIf
; ----- Change page orientation in copy of DEVMODE structure
OldPageOrientation = *DEVMODEBufferCopy\dmOrientation
*DEVMODEBufferCopy\dmOrientation = PageOrientation
; ----- Change duplex setting in copy of DEVMODE structure
OldDuplexState = *DEVMODEBufferCopy\dmDuplex
*DEVMODEBufferCopy\dmDuplex = DuplexMode
; ----- Specify which parameters are to be changed
*DEVMODEBufferCopy\dmFields = #DM_ORIENTATION | #DM_DUPLEX
; ----- Overwrite DEVMODE structure with modified copy
CopyMemory(*DEVMODEBufferCopy, *DEVMODEBuffer, BufferSize)
; ----- Hand over the modified DEVMODE structure
Result = DocumentProperties_(0, PrinterHandle, @PrinterName, *DEVMODEBuffer, *DEVMODEBuffer, #DM_IN_BUFFER | #DM_OUT_BUFFER)
If Result <> #IDOK
ErrorMsg = "The hand over of the DEVMODE structure failed!"
Result = #False
Goto CleanUp
EndIf
; ----- Get buffer size for PRINTER_INFO_2-Struktur
BufferSize = 0
GetPrinter_(PrinterHandle, 2, 0, 0, @BufferSize)
If BufferSize = 0
ErrorMsg = "The size of the PRINTER_INFO_2 structure couldn't be obtained!"
Result = #False
Goto CleanUp
EndIf
BufferSize = BufferSize + 100
; ----- Get memory buffer for PRINTER_INFO_2 structure
*PRINTER_INFO_2Buffer = AllocateMemory(BufferSize)
If *PRINTER_INFO_2Buffer = 0
ErrorMsg = "A memory request for the PRINTER_INFO_2 structure failed!"
Result = #False
Goto CleanUp
EndIf
; ----- Get memory buffer for copy of PRINTER_INFO_2 structure
*PRINTER_INFO_2BufferCopy = AllocateMemory(BufferSize)
If *PRINTER_INFO_2BufferCopy = 0
ErrorMsg = "The memory request for a copy of the PRINTER_INFO_2 structure failed!"
Result = #False
Goto CleanUp
EndIf
; ----- Generate PRINTER_INFO_2 structure
Result = GetPrinter_(PrinterHandle, 2, *PRINTER_INFO_2Buffer, BufferSize, @BytesRetrieved)
If Result = 0
ErrorMsg = "The evaluation of printer settings failed!"
Goto CleanUp
EndIf
; ----- Copy PRINTER_INFO_2 structure
CopyMemory(*PRINTER_INFO_2Buffer, *PRINTER_INFO_2BufferCopy, BufferSize)
; ----- Change PRINTER_INFO_2 structure
*PRINTER_INFO_2BufferCopy\pDevMode = *DEVMODEBuffer
*PRINTER_INFO_2BufferCopy\pSecurityDescriptor = 0
; ----- Overwrite PRINTER_INFO_2 structure with modified copy
CopyMemory(*PRINTER_INFO_2BufferCopy, *PRINTER_INFO_2Buffer, BufferSize)
Result = SetPrinter_(PrinterHandle, 2, *PRINTER_INFO_2Buffer, 0)
If Result = 0
ErrorMsg = "The change of the printer settings failed!"
Else
Result = #True
EndIf
NewPageOrientation = *DEVMODEBuffer\dmOrientation
NewDuplexState = *DEVMODEBuffer\dmDuplex
; ----- Free printer handle and memory buffers
CleanUp:
If PrinterHandle <> 0
ClosePrinter_(PrinterHandle)
EndIf
If *DEVMODEBuffer <> 0
FreeMemory(*DEVMODEBuffer)
EndIf
If *DEVMODEBufferCopy <> 0
FreeMemory(*DEVMODEBufferCopy)
EndIf
If *PRINTER_INFO_2Buffer <> 0
FreeMemory(*PRINTER_INFO_2Buffer)
EndIf
If *PRINTER_INFO_2BufferCopy <> 0
FreeMemory(*PRINTER_INFO_2BufferCopy)
EndIf
If Result = #False
MessageRequester("Fehler", ErrorMsg, #MB_ICONERROR)
EndIf
ProcedureReturn Result
EndProcedure
Procedure.W GetInstalledPrinters()
Shared PrinterName.S()
BufferSize.L
PrinterName.S
TempString.S
TempStringLength.W
TempPrinter.S
ClearList(PrinterName())
BufferSize = 8192
TempPrinter = Space(1024)
*Buffer = GlobalAlloc_(#GMEM_FIXED | #GMEM_ZEROINIT, BufferSize)
If GetProfileString_("Devices", 0, "", *Buffer, BufferSize)
TempString = PeekS(*Buffer)
TempStringLength = Len(TempString)
While TempString <> ""
GetPrivateProfileString_("Devices", TempString, "", TempPrinter, 1024, "Win.Ini")
AddElement(PrinterName())
PrinterName() = TempString
TempString = PeekS(*Buffer + TempStringLength + 1)
TempStringLength = TempStringLength + Len(TempString) + 1
Wend
EndIf
GlobalFree_(*Buffer)
ProcedureReturn CountList(PrinterName())
EndProcedure
I hope someone will find some use in it. I have tested this example under WinNT SP6, Win2K Server and WinXP SP2. I had a very hard time until it was running
and there appear still to be some quirks in it, especially the duplex switching on 2 Hitachi DDP 70 still doesn't work correctly although the page orientation switching does. Other tested printers from HP, Lexmark and Brother worked...