views:

248

answers:

4

There's plenty of information on running Java apps as services, but I need to know how to detect whether a windows service is running or not. Does anyone know how???

At the DOS prompt, I can run:

tasklist /svc|findstr "NonRunningService"
echo Return code for N onRunningService is %ERRORLEVEL%
tasklist /svc|findstr "RunningService"
echo Return code for RunningService is %ERRORLEVEL%

I get the following:

Return code for NonRunningService is 1
Return code for RunningService is 0

In code, I have:

int retCode = Runtime.getRuntime.exec("tasklist /svc|findstr \"NonRunningService\"").waitFor();
System.out.println("Return code for NonRunningService is " + retCode);
retCode = Runtime.getRuntime.exec("tasklist /svc|findstr \"RunningService\"").waitFor();
System.out.println("Return code for RunningService is " + retCode);

I get the following output

Return code for NonRunningService is 1
Return code for RunningService is 1

According to the JavaDocs, the waitFor() should block until the process finishes, and give me the exit value of the process.

I've also tried using the Process/ProcessBuilder command line calls:

//'tasklist /nh /fi "SERVICES eq RunningService"' will return a line for 
// each running service of the requested type.
Process p1 = new ProcessBuilder("tasklist", "/nh", "/fi" "SERVICES eq RunningService").start();
p1.waitFor();
BufferedReader is = new BufferedReader(new InputStreamReader(p1.getInputStream()));
String line = is.readLine();
System.out.println("Service - " + line);
System.out.println("Running? ", (line==null?"No":"Yes");

gives:

Service -
Running? No

even when I get lines in the output at the command line!

A: 

This is a wild guess. It looks like your waitFor is in the wrong spot. I would read while the process is running, then wait for the exit:

Process p1 = new ProcessBuilder("tasklist", "/nh", "/fi" "SERVICES eq RunningService").start();
BufferedReader is = new BufferedReader(new InputStreamReader(p1.getInputStream()));
String line = is.readLine();
System.out.println("Service - " + line);
System.out.println("Running? ", (line==null?"No":"Yes");
p1.waitFor();

You can also redirect the error stream to make sure you read all the output:

p1.redirectErrorStream(true);

Jonathon
This shouldn't matter. The `waitFor()` is superfluous if you already call `getInputStream()`. In other words, it's only useful if you're not interested in any of its results but would like to block the current thread until the executed process is finished. E.g. because the remnant of the code is dependent on the process' results (file creation/deletion, etc).
BalusC
@BalusC in simpler terms, output from the process is available after process termination?
Jonathon
Not necessarily. The output can also be available before termination. In this specific case there's no technical difference, maybe only in your case the output is a tad sooner displayed.
BalusC
A: 

Your first example is failing, since you cannot use shell or command/cmd features (pipes) in Runtime#exec.

As already pointed out, your second example looks ok, but the code you've pasted does not match your alleged output. If line had really been null, the first println would have written "Service - null" and not "Service -". According to your output from the first println, line must be an empty string (""), but in that case, the second println would have printed "Yes" instead of "No".

jarnbjo
+2  A: 

I recreated your code and added some extra debugging output by creating a class to print the output from process:

private static class Writer implements Runnable {

    private InputStream is;

    public Writer(InputStream is) {
        this.is = is;
    }

    @Override
    public void run() {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
}

In the main method I then started an instance of this before calling waitFor():

public static void main(String[] args) throws Exception {
    String command = "tasklist /svc | findstr \"svchost.exe\"";
    Process p = Runtime.getRuntime().exec(command);

    new Thread(new Writer(p.getInputStream())).start();
    new Thread(new Writer(p.getErrorStream())).start();

    System.out.println("Return code: " + p.waitFor());

}

The output from this is:

ERROR: Invalid argument/option - '|'.
Type "TASKLIST /?" for usage.

Because the command isn't executed in a shell, you first need to call the Windows shell, and pass in the command as an argument:

String command = "cmd /c tasklist /svc | findstr \"svchost.exe\"";

After changing this the output is now Return code: 0.

I've found a strange issue however, in that if you don't handle the output from the process's stdout channel, for some reason the process does not terminate. To get around this, I've had to put in a loop to read and discard the output from the process:

public static void main(String[] args) throws Exception {
    String command = "cmd /c tasklist /svc | findstr \"svchost.exe\"";
    Process p = Runtime.getRuntime().exec(command);
    while(p.getInputStream().read() != -1) {} //hangs without this line

    System.out.println("Return code: " + p.waitFor());

}
Jared Russell
A: 

This is what i used in order to find if the indexing service is up and running:

In order to do this you must know the name of the service and use the SC command:

public boolean isIndexingServiceOperational() {
    String[] result = getResultFor("SC QUERY \"CiSvc\"");
    if (result != null) {
        if (!result[0].contains("does not exist")) {
            return true;
        }
    }
    return false;
}

public boolean isIndexingServiceRunning() {
    String[] result = getResultFor("SC QUERY \"CiSvc\"");
    if (result != null) {
        if (result[0].contains("RUNNING")) {
            return true;
        }
    }
    return false;
}

private String[] getResultFor(String command) {
    try {
        Process p = Runtime.getRuntime().exec(command);
        BufferedInputStream in = new BufferedInputStream(p.getInputStream());
        BufferedInputStream err = new BufferedInputStream(p
                .getErrorStream());
        StringBuffer inS = new StringBuffer();
        byte[] b = new byte[1024];
        while (in.read(b) != -1) {
            inS.append(new String(b));
        }
        StringBuffer errS = new StringBuffer();
        b = new byte[1024];
        while (err.read(b) != -1) {
            errS.append(new String(b));
        }
        in.close();
        err.close();
        return new String[] { inS.toString(), errS.toString() };
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
Savvas Dalkitsis