Printer: How to get the device name

Just starting out? Need help? Post your questions and find answers here.
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Printer: How to get the device name

Post by Shardik »

IdeasVacuum wrote:Stumbled across your code for presetting a printer - works really well (minor tweaks to suit PB4.61). How do I make it work when compiling as Unicode?
In order to work in ASCII and Unicode mode you have to change Len() to StringByteLenght() and the fixed count of 1 for the string terminator to SizeOf(Character). So this code

Code: Select all

      TempString = PeekS(*Buffer + TempStringLength + 1)
      TempStringLength = TempStringLength + Len(TempString) + 1
has to be changed to

Code: Select all

      TempString = PeekS(*Buffer + TempStringLength + SizeOf(Character))
      TempStringLength = TempStringLength + StringByteLength(TempString) + SizeOf(Character)
For your conveniance I have adapted the whole code example for PB 4.61:

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
;=============================================================================

EnableExplicit

Enumeration
  #WindowPrinterDefaultSettings
EndEnumeration

Enumeration
  #ComboPrinterNames
  #FrameDuplex
  #OptionHorizontal
  #OptionVertical
  #FrameSimplexDuplex
  #OptionSimplex
  #OptionDuplex
  #FrameOrientation
  #OptionPortrait
  #OptionLandscape
  #ButtonChange
  #ButtonCancel
EndEnumeration

Define DuplexMode.I
Define NewDuplexState.I
Define NewPageOrientation.I
Define NumInstalledPrinters.I
Define OldDuplexState.I
Define OldPageOrientation.I
Define PageOrientation.I
Define WindowEvent.I

NewList PrinterName.S()

Declare.I ChangePrinterDefaultSettings(PrinterName.S)
Declare.I 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)
ComboBoxGadget(#ComboPrinterNames, 50, 15, 170, 20)
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.I ChangePrinterDefaultSettings(PrinterName.S)
  Shared DuplexMode.I
  Shared NewDuplexState.I
  Shared NewPageOrientation.I
  Shared OldDuplexState.I
  Shared OldPageOrientation.I
  Shared PageOrientation.I
  Shared PrinterName.S()

  Protected BufferSize.I
  Protected BytesRetrieved.I
  Protected *DEVMODEBuffer.DEVMODE
  Protected *DEVMODEBufferCopy.DEVMODE
  Protected DOCINFOStructure.DOCINFO
  Protected ErrorMsg.S
  Protected ModeFlag.I
  Protected PrintText.S
  Protected PRINTER_DEFAULTSStructure.PRINTER_DEFAULTS
  Protected *PRINTER_INFO_2Buffer.PRINTER_INFO_2
  Protected *PRINTER_INFO_2BufferCopy.PRINTER_INFO_2
  Protected PrinterHandle.I
  Protected Result.I

  ; ----- 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.I GetInstalledPrinters()
  Shared PrinterName.S()

  Protected *Buffer
  Protected BufferSize.I
  Protected PrinterName.S
  Protected TempString.S
  Protected TempStringLength.I
  Protected TempPrinter.S

  ClearList(PrinterName())

  BufferSize = 8192
  TempPrinter = Space(1024)

  *Buffer = AllocateMemory(BufferSize)

  If GetProfileString_("Devices", 0, "", *Buffer, BufferSize)
    TempString = PeekS(*Buffer)
    TempStringLength = StringByteLength(TempString)

    While TempString <> ""
      GetPrivateProfileString_("Devices", TempString, "", TempPrinter, 1024, "Win.Ini")
      AddElement(PrinterName())
      PrinterName() = TempString
      TempString = PeekS(*Buffer + TempStringLength + SizeOf(Character))
      TempStringLength = TempStringLength + StringByteLength(TempString) + SizeOf(Character)
    Wend
  EndIf

  FreeMemory(*Buffer)

  ProcedureReturn ListSize(PrinterName())
EndProcedure
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Printer: How to get the device name

Post by IdeasVacuum »

Ah that's excellent Shardik, thank you. I've been working too many hours of late, what little brain I have left is totally fried. :?
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Printer: How to get the device name

Post by IdeasVacuum »

Still trying to get the selected printer name (PrintDlg_()) when my app is compiled as unicode. The following works fine in ASCII mode, does not work at all if switched to unicode:

Code: Select all


iCharCnt.i = 1

CompilerIf(#PB_Compiler_Unicode = 1)

   iCharCnt = 2

CompilerEndIf

sPrinterName.s

PrintDlg.PRINTDLG
PrintDlg\lStructSize = SizeOf(PRINTDLG)
PrintDlg\hDevMode = 0
PrintDlg\hDevNames = 0
PrintDlg\Flags = #PD_ALLPAGES

If PrintDlg_(PrintDlg) <> #False

    *DEVNAMES.DEVNAMES = GlobalLock_(PrintDlg\hDevNames)

    While (i < 64) And (PeekC(*DEVNAMES + *DEVNAMES\wDeviceOffset + i) <> 0)

           sPrinterName = sPrinterName + Chr(PeekC(*DEVNAMES + *DEVNAMES\wDeviceOffset + i))

                      i = i + iCharCnt
    Wend

    Debug sPrinterName

    GlobalUnlock_(PrintDlg\hDevNames)

EndIf

GlobalFree_(PrintDlg\hDevNames)
End
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Printer: How to get the device name

Post by netmaestro »

You can give this a try, it works here:

Code: Select all

Procedure.s GetDefaultPrinterName() ; netmaestro 2012
  Protected sPrinterName.s, PrintDlg.PRINTDLG, *DEVNAMES.DEVNAMES
  With PrintDlg
    \lStructSize = SizeOf(PRINTDLG)
    \Flags = #PD_RETURNDEFAULT ; This suppresses the dialog coming up
  EndWith
  PrintDlg_(PrintDlg)
  *DEVNAMES = GlobalLock_(PrintDlg\hDevNames)
  sPrinterName = PeekS(*DEVNAMES + (*DEVNAMES\wDeviceOffset * SizeOf(Character))) ; wDeviceOffset is in characters, not bytes
  GlobalUnlock_(PrintDlg\hDevNames)
  GlobalFree_(PrintDlg\hDevNames)
  ProcedureReturn sPrinterName
EndProcedure

MessageRequester("Default Printer Name:", GetDefaultPrinterName())

BERESHEIT
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Printer: How to get the device name

Post by IdeasVacuum »

That works a treat Netmaestro, thank you! 8)

To get the currently selected printer name instead of the default printer name, change:

\Flags = #PD_RETURNDEFAULT

to

\Flags = #PD_ALLPAGES (or no flags. Obviously the dialog must be displayed for the User to select the printer if the default will not be used).
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
Post Reply