0

I wrote this printing application, which is launched from Python27 on Windows 8.1 64-bit. My problem is that its a Kiosk in public location, when Python27 launch the Java then it has a windows command prompt with close icon (some users click the close icon on command prompt and job does not get completed)

Question: How to run this following code silently without any command prompt being exposed/popup in Kiosk?

import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.printing.PDFPageable;

public class JPrint {

  public static boolean saveFile(URL url, String file) throws IOException {
    boolean download_status = false;

    System.out.println("[OK] - 1");
    InputStream in = url.openStream();
    FileOutputStream fos = new FileOutputStream(new File(file));
    System.out.println("[OK] - 2");
    int length = -1;
    byte[] buffer = new byte[1024];

    while ((length = in.read(buffer)) > -1) {
        fos.write(buffer, 0, length);
    }
    fos.close();
    in.close();

    download_status = true;
    System.out.println("[OK] - 3");
    return download_status;
  }

  public static void main(String[] args) throws IOException, PrinterException {  
    String downloaded_filename = "C:/pdf.pdf";
    String download_pdf_from = "http://www.example.com/index/print?kiosk=1";
    String downloaded_filename_open_as_pdf = "C:\\pdf.pdf";
    String printerNameDesired = "HP Photosmart 5520 series"; 

    // Get printers
    PrintService[] services = PrinterJob.lookupPrintServices();
    DocPrintJob docPrintJob = null;
          for (int i = 0; i < services.length; i++) {
            System.out.println(services[i]);
          }   

    try{
      URL url = new URL(download_pdf_from);

      if(saveFile(url, downloaded_filename)) {
        try {
          PDDocument pdf = PDDocument.load(new File(downloaded_filename_open_as_pdf));
          PrinterJob job = PrinterJob.getPrinterJob();
          for (int i = 0; i < services.length; i++) {
           if (services[i].getName().equalsIgnoreCase(printerNameDesired)) {
             docPrintJob = services[i].createPrintJob();
           }
          }

          job.setPrintService(docPrintJob.getPrintService());
          job.setPageable(new PDFPageable(pdf));
          //docPrintJob = service[i].createPrintJob();
          job.print();

        } catch (Exception e) {
          System.out.println("[FAIL]" + e);
        }      
      } else {
        System.out.println("[FAIL] - download fail");
      }      
    } catch (Exception ae) {
      System.out.println("[FAIL]" + ae);
    }


  }
}

1 Answers1

2

Change your Python code to launch the Java app using "javaw" instead of "java".

Note that this is only necessary on Windows. On other platforms the "java" command does not launch a command shell.

For more details, refer to:


Given that you are invoking the Java app from Python like this:

Popen(['java', 
       '-cp', 
       'C:/Python27/pdfbox-app-2.0.0-RC3.jar;C:/Python27/jprint.jar',
       'JPrint']) 

the straight-forward fix is to change java to javaw; i.e.

Popen(['javaw', 
       '-cp', 
       'C:/Python27/pdfbox-app-2.0.0-RC3.jar;C:/Python27/jprint.jar',
       'JPrint']) 

@eryksun points out that you can achieve the same ends by telling Popen to override the application's default launch flags; e.g.

DETACHED_PROCESS = 8
Popen(['java', 
       '-cp', 
       'C:/Python27/pdfbox-app-2.0.0-RC3.jar;C:/Python27/jprint.jar',
       'JPrint'],
      creationflags=DETACHED_PROCESS)
Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Already i am running it with `javaw.exe` and `C:\Python27\mypy.pyw`. But still i had that command prompt popup. –  Feb 28 '16 at 05:49
  • This is how from Python its running, i think i have to run this java into javaw. e.g: `Popen(['java', '-cp', 'C:/Python27/pdfbox-app-2.0.0-RC3.jar;C:/Python27/jprint.jar', 'JPrint'])` –  Feb 28 '16 at 05:52
  • 1
    Yes. You do. You are currently using "java.exe", and you need to use "javaw.exe". – Stephen C Feb 28 '16 at 05:54
  • 1
    Alternatively, Python's `Popen` exposes the process `creationflags` and `startupinfo` that give you total control over whether a console will be attached, and if so whether it has a window, and if so whether the window is visible. – Eryk Sun Feb 28 '16 at 05:56
  • 1
    @eryksun - In general (i.e. for normal Windows apps), yes. In this case, I'm not sure. I wouldn't be surprised if the "java.exe" command was overriding what Popen is telling it to do. (I can't test it 'cos I'm running Linux.) – Stephen C Feb 28 '16 at 05:57
  • 1
    @StephenC, the creation or inheritance of a console for an application based on the EXE header flag is handled by Windows, which uses the creation flags such as `DETACHED_PROCESS` and `CREATE_NO_WINDOW`, or the `startupinfo` flag `STARTF_USESHOWWINDOW`. Rarely does a console application manually call `AllocConsole` to get a console if run detached, or first `FreeConsole` to get a new one if run with no window, or unhide its console window if run with a hidden window. I would be surprised if java.exe behaved like that out of the box. A Java program running under java.exe might. – Eryk Sun Feb 28 '16 at 06:17
  • 1
    @eryksun - Have you tried it? Also, how do you explain that there is a `java.exe` and a `javaw.exe` that behave the way that they do. And ... yes ... that >>is<< how they behave: `java.exe` launches a command shell and `javaw.exe` doesn't. – Stephen C Feb 28 '16 at 06:26
  • 1
    Generally a non-console application such as javaw.exe is provided to run without a console as the default and to associate a file extension to run without a console. For example, pythonw.exe is associated with .pyw scripts. The options I mentioned are not the default behavior. If you don't tell Windows you want to run detached, or without a window, or with a new console, or with a hidden console, then Windows sees the EXE is flagged as a console program and gives you the default behavior. There isn't a simple way to control some of these options from cmd or Explorer. – Eryk Sun Feb 28 '16 at 06:38
  • 1
    This is all fine and well ... but HAVE YOU TRIED IT? Have you tried running "java.exe" with Popen and the creation flags? Does it ACTUALLY work? That's all I'm asking. – Stephen C Feb 28 '16 at 07:05
  • 1
    I installed the jdk to test this, to make sure java.exe is no different from 99% of all other console apps I've ever used. At first glance, the import table only has `GetConsoleCP`, `GetConsoleMode`, and `WriteConsoleW` -- no static import of `AllocConsole`, `AttachConsole`, or `FreeConsole`. I see in its strings that `CONOUT$` is listed. `GetConsoleMode` is the standard way to check if a standard handle is a console, so it looks to be checking to open the console, if available, to write Unicode directly via `WriteConsoleW`. Good. I wish Python were this Windows-console friendly. – Eryk Sun Feb 28 '16 at 10:18
  • 1
    I downloaded pdfbox-app-2.0.0-RC3.jar and built the OP's jar. I tested this from Python's IDLE shell, run via `pyw -3 -m idlelib`, so the parent process had no attached console. I evaluated `DETACHED_PROCESS = 8;` `out = subprocess.check_output(['java', '-cp', 'pdfbox-app-2.0.0-RC3.jar;JPrint.jar', 'JPrint'], creationflags=DETACHED_PROCESS)`. This worked as expected. No console was created. Output was written to the `stdout` pipe that `check_output` configured. – Eryk Sun Feb 28 '16 at 10:26
  • 1
    I used `subprocess.check_output` because otherwise the OP's prints vanish into the ether. This wraps calling `Popen` to make `stdout`a pipe and then reads the output. It wouldn't be a problem if the application used file logging or Windows event logging instead of debug print statements. – Eryk Sun Feb 28 '16 at 11:18