Friday, October 25, 2013

PDFs, iText and taskkill, oh my!

Acrobat Reader isn't exactly convenient to developers working to send PDFs for printing. The solutions I  dug up are mostly unofficial, and an outdated PDF at best. And I just recently found out from the user reviews that iText library is no friendly forces either. For all the solutions I could find, acrord32 is known to have at least one window open after all the operations are said and done. Which brings me back to the established solution in the system we're supporting: killing Acrobat Reader.

What the existing codes have been doing along was to trigger tskill via Runtime.exec in order to terminate the acrord32 process. That was all fine and dandy for what used to be WinXP. But the Tech Refresh introduced Win7 as a replacement for most of the machines. The JRE6 Java Console threw this out:
java.io.IOException: Cannot run program "tskill": CreateProcess error=2, The system cannot find the file specified
    at java.lang.ProcessBuilder.start(Unknown Source)
    at java.lang.Runtime.exec(Unknown Source)
Which basically means we're screwed because Win7 didn't know what the tskill program was. When I first turned to this article, I believed that
the addition of "cmd /c" would give me the fix we needed. It only served to hide the exception being thrown without really doing anything useful. In trying to find out more details, this bit of code was added:
Process execProc = Runtime.getRuntime().exec(command);
int exit = execProc.waitFor();
System.out.println("Kill exit code: " + exit);
if(exit!=0) {
    BufferedReader br = new BufferedReader(new InputStreamReader(execProc.getErrorStream()));
    String line;
    while((line = br.readLine()) != null) {
        System.err.println(line);
    }
}
The error came that cmd reported it didn't know what tskill was either. By this time I'd already explored and learnt about the existence of both tskill and taskkill. The main difference is that taskkill is not available on Home platforms and basically offers more options as an upgrade to tskill, thus more powerful.

Since tskill is now practically unavailable to me, I thought we should just give taskkill a chance.

Let's take a look at the command switches for tskill:
C:\Users\thequirksofit>tskill /?
Ends a process.

TSKILL processid | processname [/SERVER:servername] [/ID:sessionid | /A] [/V]

  processid           Process ID for the process to be terminated.
  processname         Process name to be terminated.
  /SERVER:servername  Server containing processID (default is current).
                         /ID or /A must be specified when using processname
                         and /SERVER
  /ID:sessionid       End process running under the specified session.
  /A                  End process running under ALL sessions.
  /V                  Display information about actions being performed.

Not as lengthy compared to the help for taskkill:
C:\Users\thequirksofit>taskkill /?

TASKKILL [/S system [/U username [/P [password]]]]
         { [/FI filter] [/PID processid | /IM imagename] } [/T] [/F]

Description:
    This tool is used to terminate tasks by process id (PID) or image name.

Parameter List:
    /S    system           Specifies the remote system to connect to.

    /U    [domain\]user    Specifies the user context under which the
                           command should execute.

    /P    [password]       Specifies the password for the given user
                           context. Prompts for input if omitted.

    /FI   filter           Applies a filter to select a set of tasks.
                           Allows "*" to be used. ex. imagename eq acme*

    /PID  processid        Specifies the PID of the process to be terminated.
                           Use TaskList to get the PID.

    /IM   imagename        Specifies the image name of the process
                           to be terminated. Wildcard '*' can be used
                           to specify all tasks or image names.

    /T                     Terminates the specified process and any
                           child processes which were started by it.

    /F                     Specifies to forcefully terminate the process(es).

    /?                     Displays this help message.

Filters:
    Filter Name   Valid Operators           Valid Value(s)
    -----------   ---------------           -------------------------
    STATUS        eq, ne                    RUNNING |
                                            NOT RESPONDING | UNKNOWN
    IMAGENAME     eq, ne                    Image name
    PID           eq, ne, gt, lt, ge, le    PID value
    SESSION       eq, ne, gt, lt, ge, le    Session number.
    CPUTIME       eq, ne, gt, lt, ge, le    CPU time in the format
                                            of hh:mm:ss.
                                            hh - hours,
                                            mm - minutes, ss - seconds
    MEMUSAGE      eq, ne, gt, lt, ge, le    Memory usage in KB
    USERNAME      eq, ne                    User name in [domain\]user
                                            format
    MODULES       eq, ne                    DLL name
    SERVICES      eq, ne                    Service name
    WINDOWTITLE   eq, ne                    Window title

    NOTE
    ----
    1) Wildcard '*' for /IM switch is accepted only when a filter is applied.
    2) Termination of remote processes will always be done forcefully (/F).
    3) "WINDOWTITLE" and "STATUS" filters are not considered when a remote
       machine is specified.


Examples:
    TASKKILL /IM notepad.exe
    TASKKILL /PID 1230 /PID 1241 /PID 1253 /T
    TASKKILL /F /IM cmd.exe /T
    TASKKILL /F /FI "PID ge 1000" /FI "WINDOWTITLE ne untitle*"
    TASKKILL /F /FI "USERNAME eq NT AUTHORITY\SYSTEM" /IM notepad.exe
    TASKKILL /S system /U domain\username /FI "USERNAME ne NT*" /IM *
    TASKKILL /S system /U username /P password /FI "IMAGENAME eq note*"

Here's the original command
tskill acrord32
would thus become
taskkill /im acrord32.exe
which, as you may realise would mean that, instead of killing the process name using tskill, we'd now be specifying the imagename of the process with the /im switch. This means the .exe would have to be explicitly added to the end.

With that last command, at last was acrord32 terminated, with not much help from Adobe, iText and tskill because they were mostly powerless in this instance. I guess you could say that, after a day or two of battling... I killed it.

No comments:

Post a Comment