Printing in a multi printer setup - best approach ?

Hey,

I need my app to print to different printers. The windows computer where it’ll be running will have probably three printers connected.

Two of them, label printers (80 mm wide paper), and one regular printer to print reports and other normal stuff.

I need to have a way to identify those printers and automatically choose where it will print, depending on the content. Specially in the case of the label printers, as this is a POS I can’t have the user select the printer, this has to be a automated process. Sometime It might be necessary to print to the two label printers.

I’ve read quite a bit in the forum that this seems to be a rather complex thing. I think I have two approaches, please correct me if I’m wrong.

  1. Change the default printer before every print job and print to the default printer. (and restore the original default printer after every print job)
  2. Get Xojo to print to a specific printer among the installed printers. For this I read I have to have (get beforehand) the PrinterSetup.SetupString for each printer, so this would involve some previous (one time) configuration, right ?

I am leaning torwards otion 2. Will this work ? Can someone point me to some code example ?

@Tim Hare posted an example project back in this thread (https://forum.xojo.com/35613-choosing-special-printer-without-printer-dialog-in-windows-app/2) but it doesn’t seem to be available now.

It’s not hard. MBS can do this easily. Look into the WindowsPrinterMBS class and the GetDefaultPrinter/SetDefaultPrinter functions. We do this in several applications were the user selects a printer for a specific job (i.e. regular reports or barcode printer) and change the DefaultPrinter to the printer of our choice and then set it back to the default so we’re a good citizen on their computers.

Thanks Robert… I am actually looking for a free solution… if there is none I will evaluate buying plugins…

Also… changing the default printer is fast and harmless ?

this is the result of hard work on this forum…
enjoy !

[code]Public Function SystemCountPrinters() as Integer
’ returns the number of defined printers on the running system

SystemScanPrinters
Return UBound(mPrinters)+1

End Function
[/code]

global in a module :

Public Property mPrinters() as PrinterDefinition
Structure PrinterDefinition
  printerName as string*80
  printerModel as string*50
  printerURI as string*127
End Structure

[code]Public Sub SystemScanPrinters()
ReDim mPrinters(-1)
dim p as PrinterDefinition

’ --------------------------------------------------------------------------------
’ search for the available printers on the host system
’ --------------------------------------------------------------------------------
dim myShell as new shell
#if TargetMacOS or TargetLinux
myShell.Execute “lpstat -p”
#Elseif TargetWindows
myShell.Execute “wmic printer get name,default”
#endif
dim result as String = myShell.Result
dim reslines() as String = result.ReadFields(EndOfLine)

for each line as String in reslines
#if TargetMacOS or TargetLinux
p.printerName = MotNumero(line,2)
mPrinters.Append p
#Elseif TargetWindows
p.printerName = MotNumero(line,2)
if p.printerName<>“Name” then
mPrinters.Append p
end if
#endif

next

’ --------------------------------------------------------------------------------
’ search for the printer model
’ --------------------------------------------------------------------------------

’ --------------------------------------------------------------------------------
’ search for the printer URI
’ --------------------------------------------------------------------------------

End Sub
[/code]

and the final one :

[code]Public Sub SystemSetDefaultPrinter(aPrinterName as String)
if UBound(mPrinters)<0 then
SystemScanPrinters
end if

if UBound(mPrinters)>=0 then
dim printer,foundPrinter as PrinterDefinition

' recherche l'imprimante
for each printer in mPrinters
  if printer.printerName = aPrinterName then
    foundPrinter = printer
    Exit For
  end if
next

if foundPrinter.printerName<>"" then
  dim myShell as new shell
    
  #if TargetMacOS or TargetLinux
    myShell.Execute "lpoptions -d "+aPrinterName
  #Elseif TargetWindows
    myShell.Execute "wmic printer where name='"+aPrinterName+"' call setdefaultprinter"
  #endif
else
  Alerte "SystemSetDefaultPrinter: Printer "+aPrinterName+" is unknown."
end if

Else
Alerte “SystemSetDefaultPrinter: No printer defined.”
end if

End Sub
[/code]

and I forgot this utility :

Public Function MotNumero(theString as string, theNumero as integer) as string
    return NthField(theString," ",theNumero)
End Function

Do not do that without asking the user, and informing them that it will change their system level default printer. This change affects other applications, not just yours! As Google used to say: don’t be evil.

To add another level of complexity on Win 10: If the user has “Let Windows manage my default printer” Checked in their printer settings, which I believe is the default, Windows will automatically switch the default printer to what is used most frequently. If you want to manage the printers in your app, make sure that user setting is unchecked.

these methods are intended to switch to another printer temporarly and set the default printer back again
typically print to a label printer, and then come back to the default printer.

The devil is preaching ??? :wink:

Wow… thanks Jean-Yves for your great post…

@Tim P : I understand that. But please consider this is a system that will ONLY be used in a POS. Nothing will be printed outside my app. No other software, no explorer, chrome, office, not even paint, or other apps. The user will only print the data that need from my app. That being said, after print, that default printer will be set again to the one that was set up BEFORE printing.

One more question : Does changing the default printer take time ? Can I assume this is a process that is in the ms range ?

Here’s a question/problem I must add… Can I print in parallel to more than one printer at the same time?

Thanks for your great contributions.

Changing the default printer to print is ‘hackish’. In other languages printer selection and printer settings can be changed directly from code without the need for a shell hack. I suppose if one new declares well enough a solution could be made using declares?

I agree with you, Neil, but there doesn’t seem to be a ‘proper’ way to do this…

Not in Xojo anyway :wink:

https://forum.xojo.com/conversation/post/374046

I’m reposting that old project here: https://www.dropbox.com/s/dgiregpldc9mkh9/twoprinters.xojo_binary_project?dl=1

Also, this project might be of interest (Windows only) wherein you can select the printer by name and send escape codes (think Zebra or Epson) directly: https://www.dropbox.com/s/2339n0uinee25tg/rawprint.rbp?dl=1

Thanks a lot, Tim

i’m working on a opensource class for printing on mac/windows, currently i manage to work with htmlviewer, next step, xojo reports… if you are interested, let me know, it’s currently on my gitlab private server

How this project works ? What exactly does ?

The first project allows you to select 2 printers, saves their printersetup strings and then allows you to print to each one without having to select them again.

The second project uses Windows declares to print in raw mode to a printer. It also allows you to select the printer by name. This bypasses Xojo’s printing scheme and talks directly to the printer.