Page 2 of 2

Re: Printer: How to get the device name

Posted: Mon Sep 10, 2012 9:54 am
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

Re: Printer: How to get the device name

Posted: Mon Sep 10, 2012 10:53 am
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. :?

Re: Printer: How to get the device name

Posted: Wed Sep 12, 2012 3:35 am
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

Re: Printer: How to get the device name

Posted: Thu Sep 13, 2012 8:01 pm
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())


Re: Printer: How to get the device name

Posted: Fri Sep 14, 2012 3:16 pm
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).