Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refresh printers in Java while application is running

Tags:

java

printing

As the title says, I would like to refresh the printers that are registered in the settings of the computer while my Java application is running. Normally, I can use PrinterJob.lookupPrintServices() to get the printers. However, these are only refreshed when restarting the application. I've read something on that lookupPrintServices() should be done in a new thread in order to get the printers. This however did not work, the list of printers remains the same. The following link shows that this problem should have been fixed in Java 5.0, am I doing something wrong?

Any help is much appreciated!

EDIT Added MWE.

public class MTPrinterTest extends Thread {
    public static void main(String[] args) {
        MTPrinterTest t1 = new MTPrinterTest();
        t1.start();

        try {
            System.in.read();
        } catch (Exception e){}

        MTPrinterTest t2 = new MTPrinterTest();
        t2.start();
    }
    public void run() {
        PrinterJob printerJob;
        PrintService[] printServices;

        printerJob = PrinterJob.getPrinterJob();
        printServices = printerJob.lookupPrintServices();
        System.out.println("Number of servies found: " + printServices.length);
        for (int i =0; i< printServices.length; i++)
            System.out.println("--> Available Printer " + i + ": " + printServices[i]);
        printerJob.printDialog(); 
    } 
}
like image 919
Robin Trietsch Avatar asked Feb 11 '15 13:02

Robin Trietsch


2 Answers

There is no need to restart the application in order to refresh the list of print services.

Here I found the solution:

/**
 * Printer list does not necessarily refresh if you change the list of 
 * printers within the O/S; you can run this to refresh if necessary.
 */
public static void refreshSystemPrinterList() {
    Class<?>[] classes = PrintServiceLookup.class.getDeclaredClasses();
    for (Class<?> clazz : classes) {
        if ("javax.print.PrintServiceLookup$Services".equals(clazz.getName())) {
            // sun.awt.AppContext.getAppContext().remove(clazz);
            // Use reflection to avoid "Access restriction" error message
            try {
                Class<?> acClass = Class.forName("sun.awt.AppContext");
                Object appContext = acClass.getMethod("getAppContext").invoke(null);
                acClass.getMethod("remove", Object.class).invoke(appContext, clazz);
            } catch (Exception e) {
            }
            break;
        }
    }
}

Basically, the static class PrintServiceLookup.Services maintains the list of print services. So, if you remove this class from the AppContext, you force PrintServiceLookup to create a new instance again. Thus, the list of print services gets refreshed.

like image 127
IvanRF Avatar answered Oct 05 '22 04:10

IvanRF


I have encountered the same problem before and after multiple tests, it seems like the printer list is snapshotted at the start of the Java application and can't be refreshed after that using java's lookupPrintServices().

What I did to solve that problem is call directly the Winspool API using JNA. If you intend to do so, the Winspool API is well documented by Microsoft : Winspool API documentation

Also, I described a part of my solution to a problem I had a few month ago in this question, it might help you understand JNA and the Winspool API.

like image 27
Padrus Avatar answered Oct 05 '22 02:10

Padrus