NSInternalInconsistencyException when using PrinterSetup.OpenPrinter in a thread

Hi there,

Using Xojo 2021r3.1 on macOS Monterey (12.6.4).

My desktop app crashes when performing the following within a thread.
g = PrinterSetup.OpenPrinter(ps)
The same operation works fine if executed within the main thread.

UnhandledException Event is not fired.
The console log shows the following:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSWindow drag regions should only be invalidated on the Main Thread!'

PrinterSetup is not available in console apps (even if the doc says it available in all project types) and can not run from a thread …
I need to print big batches of documents, some are sent to the printer, some are saved as PDF, others are generating PDFs sent as attachment by mail.

Is there a workaround ?
Is there a way to suppress the small window (small dialog saying “saving, processing page”) displayed
when printing which presumably causes the crash ?

Thanks for any help !

Regards,

Olivier

Some things don’t like to be run in a thread like loading html into a html viewer.

I use the following to work around this:

  • The code sets the html for a special window.
  • A property “isRunning” or something is set to true.
  • Then I have a loop waiting until “isRunning” is set to false.
  • The html viewer does i’s thing.
  • After the html viewer is finished it sends a notification to the calling code.
  • Which sets “isRunning” to false.

You shouldn’t try to do anything that interacts with the UI in a thread. It’s generally disallowed by the underlying OS, and usually throws a RuntimeException in Xojo, but it looks like you found a place where it’s not doing that.

2 Likes

Hi Beatrix,
Thanks.
I was thinking about something like this but I’m afraid it won’t be a solution because of the OS small window (“processing page”).
This dialog opens once PrinterSetup.OpenPrinter returns and is closed when the graphics is flushed to the printer or to the pdf file.
If I print 100 reports I’ll have 100 times the dialog opening in the desktop app while the use is doing something else.
Placing most of the code in a thread and waiting for the result won’t help as the dialog will reman open until the whole printing process is finished.
I’m not sure I’m making myself clear ;-).

Olivier

I’m well aware of this but I’m not really interacting with the UI, I’m just printing …
But PrinterSetup.OpenPrinter makes macOS displaying a small window, it’s a macOS window, not a Xojo one.

Why dont you save the printersetup and use this saved setting for printing in a thread? Showing 100 times an unneccessary dialog is not really helpful :wink:

This is exactly what I’m doing, the settings are in a database and that’s not the issue.
But for printing you need the “graphics” which is returned by PrinterSetup.OpenPrinter and OpenPrinter provoke the opening of a small window “processing page …”.
I don’t “need” this dialog but the OS shows it.

It doesn’t matter whose window it is.

I don’t see such a window - don’t know if printing process is too fast on my computer to show it or if it is printer specific. Could you test your app with another printer driver - e.g. laser instead of a ink printer or vice versa?

It’s not printer specific, I’ve 3 printers defined, inkjet, label and a POS ticket printer. Anyway the app crashes (no UnhandledException, but macOS console log) as soon as OpenPrinter is performed in a thread.

Correct. It’s the OS who needs it.

Have you read somewhere that this was even supported?
If it crashes in a thread, the logical answer would be to not do it that way. Not only UI things can be problematic in a thread.

Do you need to print pages as they come or is it ok to print them once you’ve received everything?
One option would be to have a timer that your thread runs and that timer would be responsible to the print function.

You should try OpenPrinter in the main thread and just use the obtained “g” in the processing thread and see if that helps. Maybe you should try some dumber printing job coordinator, as a thread firing the AddUserInterfaceUpdate() that fires a print one page event that does actually the job, one page only, one page at time, firing continuously until the end of job. Any dialog popping up at this step (the printing event) should not cause a crash.

A similar window is showing in my app:

Needs must. I have to load html in a thread.

I bet you could generate the html in a thread and then load it into the viewer in the main thread, but I’m not going to debate this with you. This is an issue with the underlying OS and not something that can be “fixed” by Xojo or in Xojo by way of a hack.

1 Like

I AM doing that. Anything else crashes really badly. The main thread just needs to talk to the other thread.

Thank you all @Beatrix_Willius, @Arnaud_N, @Rick_Araujo, @Thomas_Roemert, @Greg_O for trying to help. Unfortunately, the problem is the window showing up.
What I’m trying to do should be performed in a console app, but PrinterSetup is not available in console.
The desktop app is installed on multiple computers in each shop (there are multiple shops) and the batch printings are triggered by changes/new entries in a central web database. These changes can happen at any time, in any shop or via a web app and the documents are printed or saved as pdf (some of them send by email) depending on multiple parameters. Documents can be paper/A4, labels, tickets.

It’s not acceptable to have windows (even small) popping up at random time on a user desktop while he’s busy with customer sales or after sales operations.
So I need to find a way to perform batch printing without disturbing the user and without claiming all resources while generating documents.

Maybe I’ll try to create a small desktop app, launched by the main one, dedicated to printing, with a single window, minimized or not visible.
But this app must not gain focus when printing otherwise it will disturb the users.

I’ll post a message in Add-Ons forum because there may be a solution with MBS.

Thanks again.

That’s what I was going to suggest. It’s called an helper. You can even have one inside the main Xojo project, eliminating the need to create a separate app (but, in debug, helpers are replaced by a regular thread, so it won’t help while you debug; you can still make a separate app if this limitation is too problematic).

Traditional helper apps (separate from the main project), which can be desktop apps, can fairly have no window shown (just set AllowAutoQuit of the app class to true, in Windows, so the app won’t quit early).
On Mac, add the LSUIElement tag to the info.plist file, so that the app won’t show in the Dock nor show any menu bar.

In your case, though, just be prepared that the window-OS will always show, even in an helper (but I guess it’ll stay behind, if your app isn’t brought to the foreground).

Thanks Arnaud.
I know about helpers, my main desktop app has many helpers, console apps dealing with shop synchronisation, iOS devices synchronisation and reports.
All helpers are added into the app bundle before notarization, and started using shell.

I wonder if it’s possible to have a separate plist with LSUIElement for a new desktop app.
I’ll try.

Regards