Choosing special printer without Printer Dialog in Windows App

I try to select a special printer without chosing it from the Printer Dialog.
In my desktop app i need to print an invoice on the standard laserprinter, and a receipt on a pos thermal receipt printer.

Is there a way to save the the printersettings, including the printer itself, and to recall this before printing?

Yes. The user has to select the printer once, but then you can save the PrinterSetup.SetupString and restore it later without prompting the user.

dim ps as new PrinterSetup
ps.SetupString = SavedSetupString
dim g as graphics = OpenPrinter(ps)

thank you so much, Tim!

But i still have a problem…
In the PrinterSetup Dialog i can only choose the pagesize, orientation, margins etc. but not the printer itself.

Am i doing something wrong?

Which platform are you on?
On macOS at least you can pick the printer in the printer setup dialog.

Windows Desktop App

I found the same topic in the monkeybread-Forum with date 05/2012
http://www.monkeybreadsoftware.eu/listarchive-realbasic-nug/2012-05-25-3.shtml

So it seems to be a problem since several years…

Hi Tim,
You can do that with vbs (visual basic script).
You run a script to switch the default printer and later you switch it back.
You can do that without prompting the user.

You can use this code in XOJO :

  s.Mode = 0
  rpt.PrinterDialog = False
  s.Execute("cscript c:\\test\\prnmngr.vbs -t -p ""PDF""") // choose PDF as printer
  rpt.Print
  s.Execute("cscript c:\\test\\prnmngr.vbs -t -p """+App.defprinter+"""") // Switch back to the default printer
  // Klaar

In c:\test you have to put Prnmngr.vbs . You can download the scripts from the microsoft site. (Just Google)
In technet is also explained how to add and delete printers using vbs.

The Windows Functionality Suite provides printer switching behind the scenes. Github

See the SystemInformation module.

you can use WindowsDeviceModeMBS on Windows to edit the settings inside a SetupString:

http://www.monkeybreadsoftware.net/class-windowsdevicemodembs.shtml

[quote=290466:@Tim Hare]Yes. The user has to select the printer once, but then you can save the PrinterSetup.SetupString and restore it later without prompting the user.

dim ps as new PrinterSetup ps.SetupString = SavedSetupString dim g as graphics = OpenPrinter(ps) [/quote]

I don’t believe this works unless I am missing something. I don’t think the printer setup includes the actual printer, just the parameters for printing (page characteristics). If OpenPrinterSetupDialog is not called it simply prints to default printer, whatever that happens to be.

I hope I am wrong, because I actually need this functionality in my app I am currently working on. This is on Windows.

Fortunately, you are mistaken. The SetupString contains the printer as well. Since Vista/Windows 7, the dialog that Xojo uses was separated out into separate dialogs. We now use code like

dim ps as new PrinterSetup
dim g as graphics
if ps.PageSetupDialog then
   if isVistaOrGreater then
      g = OpenPrinterDialog(ps)
   end
   SavedSetupString = ps.SetupString
end

The actual code is a little more complex, of course, but you get a setupstring that will select both the printer and its properties without having to prompt again.

[quote=290560:@Tim Hare]Fortunately, you are mistaken. The SetupString contains the printer as well. Since Vista/Windows 7, the dialog that Xojo uses was separated out into separate dialogs. We now use code like

dim ps as new PrinterSetup
dim g as graphics
if ps.PageSetupDialog then
   if isVistaOrGreater then
      g = OpenPrinterDialog(ps)
   end
   SavedSetupString = ps.SetupString
end

The actual code is a little more complex, of course, but you get a setupstring that will select both the printer and its properties without having to prompt again.[/quote]

Tim,

Okay I am intrigued now and must be doing something wrong then. I previously gave up on this but based on the OP and your advice I tried it again. This is on Windows 10.

[code]
dim ps as new PrinterSetup
dim g as graphics
ps.SetupString = LabelPrinter

g = OpenPrinterDialog(ps)

If g <> Nil Then

LabelPrinter = ps.SetupString

Else
Msgbox “Error”
End If[/code]

If I do this and save the string then go into any other application and print to a different printer that printer now shows as the selected printer when the OpenPrinterDialog is initiated, even when passing the prior setup string. This leads me to believe the actual printer is not in the printer.setupstring.

What am a I missing here?

Once you have stored the setupstring. Use OpenPrinter, not OpenPrinterDialog.

I am… I actually have two buttons. The code to choose the printer is the code above. To print the label I am using:

[code] Dim ps As new PrinterSetup
ps.SetupString = LabelPrinter

Dim g As Graphics
g = OpenPrinter(ps)[/code]

If the printer is selected in any other application and printed two things occur:

  1. If I chose to print again, it prints to the printer last printed to in the other application, or my own for that matter.
  2. If I load the OpenPrinterDialog and pass the previous saved string it does not choose or honor the printer that is passed in the string.

This makes me think that there is something wrong with the passing of the string. Now I did look at the printer string and it does include the printer name, etc. but I cannot print to it without choosing the printer from the opendialog again…

I posted a sample project in this thread: https://forum.xojo.com/17453-openprinter-ps-does-not-preserve-printer-printersetup-selection

Try it out.

Thank you Tim, I appreciate it. I will give it a whirl and report back.

Okay, I might of found my issue (but I am still going to try Tim’s demo):

On Windows 10 > Settings > Devices > Printers & Scanners

There is setting:

“Let windows manage my default printer”
When turned on, the default printer is the last printer used.

By default it is turned on. I never knew this setting existed. :-(((

I’m glad I revisited this.

Thanks!

Thanks to everyone, special thanks to Tim…this answers my question!

[quote=290600:@Joseph Evert]On Windows 10 > Settings > Devices > Printers & Scanners

There is setting:

“Let windows manage my default printer”
When turned on, the default printer is the last printer used.[/quote]

You have to wonder who dreams these things up! A dynamic default printer is an oxymoron. Sheesh.

[quote=290593:@Tim Hare]I posted a sample project in this thread: https://forum.xojo.com/17453-openprinter-ps-does-not-preserve-printer-printersetup-selection

Try it out.[/quote]

Hi Tim,

I tried your sample project, thank you (your code below). The issue I see here is that when calling the PageSetupDialog the attributes for the page size and source always default and preload to the currently selected “default” printer properties (in Windows 10).

In your example if the page sizes for both printers happen to be the same, then it obviously works. In my case I have a label printer (1.1" x 3") and a laser printer (8.5" x 11"). If the label printer is selected as a default in windows then I have no option of selecting anything other than the label sizes available to the label printer in PageSetupDialog. If the laser is selected as the default printer then the reverse is true.

In your sample application you look to be calling the PageSetupDialog before the OpenPrinterDialog. So it looks like your only choices for page attributes is related to the current default printer, not what is or will be selected from the printer dialog. I might be missing something.

The only way I see the sample working is if both printers happen to use the same page setup preferences, which might be the case in many applications (8.5 x 11), but it doesn’t seem like a workable solution if the page size is different.

[code] dim ps as new PrinterSetup
dim f as FolderItem
dim txtin as TextInputStream
dim txtout as TextOutputStream
dim g as Graphics

f = GetFolderItem(“printer1.txt”)
if not f.exists then
if not ps.PageSetupDialog then return
g = OpenPrinterDialog(ps)
if g = nil then return
txtout = TextOutputStream.Create(f)
txtout.write ps.SetupString
else
txtin = TextInputStream.Open(f)
ps.SetupString = txtin.ReadAll
g = OpenPrinter(ps)
end

g.DrawString(“Printer 1”, 30, 30)
[/code]

You can simulate this behavior very easily, assuming you have two printers installed that have different page attributes. I’d try a regular printer and the Microsoft XPS or Microsoft Print to PDF printer. If you have a label printer that’s even better.

  1. Select one of the printers as the default in windows.
  2. Run your app.
  3. When the page setup dialog loads take note of the list of paper sizes in the drop down. You will note these will always be what is selected as the default printer, regardless of what is chosen in your app.

Your application WILL print to different printers, but the page setup cannot be set to anything other than the currently selected default printer.

Unless I am missing something, there seems to be an issue here with Xojo’s implementation of this. It may have been a Windows update that broke this but I do remember dealing with this back in Win7 (my memory may be failing). What we really need is a way to open the PageSetupDialog and pass a printer to it, so it can then show the available page sizes, sources and margins specific to the passed printer, not the “default” printer. The current implementation makes it impossible to print to different printers with different page sizes than the default printer. Unless of course you manual set the default prior to calling PageSetupDialog.

Please tell me I have overlooked something, I’d really like to get this working.

EDIT: I will mention that this new weird setting in windows that sets the default printer to the last one used actually improves the chance of this working, all you have to do is press your button twice and it will load the updated page attributes. I did notice a user in the other thread mentioned having to press it twice to get it to work, I suspect this is why.

Thanks Tim, any input appreciated!