I think this will work only on an English language Windows installation:
System.getProperty("user.home") + "/Desktop";
How can I make this work for non English Windows?
I use a french version of Windows and with it the instruction:
System.getProperty("user.home") + "/Desktop";
works fine for me.
I think this is the same question... but I'm not sure!:
In java under Windows, how do I find a redirected Desktop folder?
Reading it I would expect that solution to return the user.home, but apparently not, and the link in the answer comments back that up. Haven't tried it myself.
I guess by using JFileChooser the solution will require a non-headless JVM, but you are probably running one of them.
This is for Windows only. Launch REG.EXE and capture its output :
import java.io.*;
public class WindowsUtils {
private static final String REGQUERY_UTIL = "reg query ";
private static final String REGSTR_TOKEN = "REG_SZ";
private static final String DESKTOP_FOLDER_CMD = REGQUERY_UTIL
+ "\"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\"
+ "Explorer\\Shell Folders\" /v DESKTOP";
private WindowsUtils() {}
public static String getCurrentUserDesktopPath() {
try {
Process process = Runtime.getRuntime().exec(DESKTOP_FOLDER_CMD);
StreamReader reader = new StreamReader(process.getInputStream());
reader.start();
process.waitFor();
reader.join();
String result = reader.getResult();
int p = result.indexOf(REGSTR_TOKEN);
if (p == -1) return null;
return result.substring(p + REGSTR_TOKEN.length()).trim();
}
catch (Exception e) {
return null;
}
}
/**
* TEST
*/
public static void main(String[] args) {
System.out.println("Desktop directory : "
+ getCurrentUserDesktopPath());
}
static class StreamReader extends Thread {
private InputStream is;
private StringWriter sw;
StreamReader(InputStream is) {
this.is = is;
sw = new StringWriter();
}
public void run() {
try {
int c;
while ((c = is.read()) != -1)
sw.write(c);
}
catch (IOException e) { ; }
}
String getResult() {
return sw.toString();
}
}
}
or you can use JNA (complete example here)
Shell32.INSTANCE.SHGetFolderPath(null,
ShlObj.CSIDL_DESKTOPDIRECTORY, null, ShlObj.SHGFP_TYPE_CURRENT,
pszPath);
javax.swing.filechooser.FileSystemView.getFileSystemView().getHomeDirectory()
Seems not that easy...
But you could try to find an anwser browsing the code of some open-source projects, e.g. on Koders. I guess all the solutions boil down to checking the HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Desktop path in the Windows registry. And probably are Windows-specific.
If you need a more general solution I would try to find an open-source application you know is working properly on different platforms and puts some icons on the user's Desktop.
You're just missing "C:\\Users\\":
String userDefPath = "C:\\Users\\" + System.getProperty("user.name") + "\\Desktop";
public class Sample {
public static void main(String[] args) {
String desktopPath =System.getProperty("user.home") + "\\"+"Desktop";
String s = "\"" + desktopPath.replace("\\","\\\\") + "\\\\" +"satis" + "\"";
System.out.print(s);
File f = new File(s);
boolean mkdir = f.mkdir();
System.out.println(mkdir);
}
}
there are 2 things.
you are using the wrong slash. for windows it's \ not /.
i'm using RandomAccesFile and File to manage fles and folders, and it requires double slash ( \\ ) to separate the folders name.
Simplest solution is to find out machine name, since this name is only variable changing in path to Desktop folder. So if you can find this, you have found path to Desktop. Following code should do the trick - it did for me :)
String machine_name = InetAddress.getLocalHost().getHostName();
String path_to_desktop = "C:/Documents and Settings/"+machine_name+"/Desktop/";
Related
Here is the situation:
I have been called upon to work with InstallAnywhere 8, a Java-based installer IDE, of sorts, that allows starting and stopping of windows services, but has no built-in method to query their states. Fortunately, it allows you to create custom actions in Java which can be called at any time during the installation process (by way of what I consider to be a rather convoluted API).
I just need something that will tell me if a specific service is started or stopped.
The IDE also allows calling batch scripts, so this is an option as well, although once the script is run, there is almost no way to verify that it succeeded, so I'm trying to avoid that.
Any suggestions or criticisms are welcome.
here's what I had to do. It's ugly, but it works beautifully.
String STATE_PREFIX = "STATE : ";
String s = runProcess("sc query \""+serviceName+"\"");
// check that the temp string contains the status prefix
int ix = s.indexOf(STATE_PREFIX);
if (ix >= 0) {
// compare status number to one of the states
String stateStr = s.substring(ix+STATE_PREFIX.length(), ix+STATE_PREFIX.length() + 1);
int state = Integer.parseInt(stateStr);
switch(state) {
case (1): // service stopped
break;
case (4): // service started
break;
}
}
runProcess is a private method that runs the given string as a command line process and returns the resulting output. As I said, ugly, but works. Hope this helps.
You can create a small VBS on-th-fly, launch it and capture its return code.
import java.io.File;
import java.io.FileWriter;
public class VBSUtils {
private VBSUtils() { }
public static boolean isServiceRunning(String serviceName) {
try {
File file = File.createTempFile("realhowto",".vbs");
file.deleteOnExit();
FileWriter fw = new java.io.FileWriter(file);
String vbs = "Set sh = CreateObject(\"Shell.Application\") \n"
+ "If sh.IsServiceRunning(\""+ serviceName +"\") Then \n"
+ " wscript.Quit(1) \n"
+ "End If \n"
+ "wscript.Quit(0) \n";
fw.write(vbs);
fw.close();
Process p = Runtime.getRuntime().exec("wscript " + file.getPath());
p.waitFor();
return (p.exitValue() == 1);
}
catch(Exception e){
e.printStackTrace();
}
return false;
}
public static void main(String[] args){
//
// DEMO
//
String result = "";
msgBox("Check if service 'Themes' is running (should be yes)");
result = isServiceRunning("Themes") ? "" : " NOT ";
msgBox("service 'Themes' is " + result + " running ");
msgBox("Check if service 'foo' is running (should be no)");
result = isServiceRunning("foo") ? "" : " NOT ";
msgBox("service 'foo' is " + result + " running ");
}
public static void msgBox(String msg) {
javax.swing.JOptionPane.showConfirmDialog((java.awt.Component)
null, msg, "VBSUtils", javax.swing.JOptionPane.DEFAULT_OPTION);
}
}
Based on the other answers I constructed the following code to check for Windows Service status:
public void checkService() {
String serviceName = "myService";
try {
Process process = new ProcessBuilder("C:\\Windows\\System32\\sc.exe", "query" , serviceName ).start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
String scOutput = "";
// Append the buffer lines into one string
while ((line = br.readLine()) != null) {
scOutput += line + "\n" ;
}
if (scOutput.contains("STATE")) {
if (scOutput.contains("RUNNING")) {
System.out.println("Service running");
} else {
System.out.println("Service stopped");
}
} else {
System.out.println("Unknown service");
}
} catch (IOException e) {
e.printStackTrace();
}
}
I have been dealing with installers for years and the trick is to create your own EXE and call it on setup. This offers good flexibility like displaying precise error messages in the event an error occurs, and have success-based return values so your installer knows about what happened.
Here's how to start, stop and query states for windows services (C++):
http://msdn.microsoft.com/en-us/library/ms684941(VS.85).aspx
(VB and C# offers similar functions)
I have had some luck in the past with the Java Service Wrapper. Depending upon your situation you may need to pay in order to use it. But it offers a clean solution that supports Java and could be used in the InstallAnywhere environment with (I think) little trouble. This will also allow you to support services on Unix boxes as well.
http://wrapper.tanukisoftware.org/doc/english/download.jsp
A shot in the dark but take a look at your Install Anywhere java documentation.
Specifically,
/javadoc/com/installshield/wizard/platform/win32/Win32Service.html
The class:
com.installshield.wizard.platform.win32
Interface Win32Service
All Superinterfaces:
Service
The method:
public NTServiceStatus queryNTServiceStatus(String name)
throws ServiceException
Calls the Win32 QueryServiceStatus to retrieve the status of the specified service. See the Win32 documentation for this API for more information.
Parameters:
name - The internal name of the service.
Throws:
ServiceException
Here's a straignt C# / P/Invoke solution.
/// <summary>
/// Returns true if the specified service is running, or false if it is not present or not running.
/// </summary>
/// <param name="serviceName">Name of the service to check.</param>
/// <returns>Returns true if the specified service is running, or false if it is not present or not running.</returns>
static bool IsServiceRunning(string serviceName)
{
bool rVal = false;
try
{
IntPtr smHandle = NativeMethods.OpenSCManager(null, null, NativeMethods.ServiceAccess.ENUMERATE_SERVICE);
if (smHandle != IntPtr.Zero)
{
IntPtr svHandle = NativeMethods.OpenService(smHandle, serviceName, NativeMethods.ServiceAccess.ENUMERATE_SERVICE);
if (svHandle != IntPtr.Zero)
{
NativeMethods.SERVICE_STATUS servStat = new NativeMethods.SERVICE_STATUS();
if (NativeMethods.QueryServiceStatus(svHandle, servStat))
{
rVal = servStat.dwCurrentState == NativeMethods.ServiceState.Running;
}
NativeMethods.CloseServiceHandle(svHandle);
}
NativeMethods.CloseServiceHandle(smHandle);
}
}
catch (System.Exception )
{
}
return rVal;
}
public static class NativeMethods
{
[DllImport("AdvApi32")]
public static extern IntPtr OpenSCManager(string machineName, string databaseName, ServiceAccess access);
[DllImport("AdvApi32")]
public static extern IntPtr OpenService(IntPtr serviceManagerHandle, string serviceName, ServiceAccess access);
[DllImport("AdvApi32")]
public static extern bool CloseServiceHandle(IntPtr serviceHandle);
[DllImport("AdvApi32")]
public static extern bool QueryServiceStatus(IntPtr serviceHandle, [Out] SERVICE_STATUS status);
[Flags]
public enum ServiceAccess : uint
{
ALL_ACCESS = 0xF003F,
CREATE_SERVICE = 0x2,
CONNECT = 0x1,
ENUMERATE_SERVICE = 0x4,
LOCK = 0x8,
MODIFY_BOOT_CONFIG = 0x20,
QUERY_LOCK_STATUS = 0x10,
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_ALL = 0x10000000
}
public enum ServiceState
{
Stopped = 1,
StopPending = 3,
StartPending = 2,
Running = 4,
Paused = 7,
PausePending =6,
ContinuePending=5
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class SERVICE_STATUS
{
public int dwServiceType;
public ServiceState dwCurrentState;
public int dwControlsAccepted;
public int dwWin32ExitCode;
public int dwServiceSpecificExitCode;
public int dwCheckPoint;
public int dwWaitHint;
};
}
I improvised on the given solutions, to make it locale independent.
Comparing the string "RUNNING" would not work in systems with non-english locales as Alejandro González rightly pointed out.
I made use of sc interrogate and look for the status codes returned by it.
Mainly, the service can have 3 states:-
1 - Not available
[SC] OpenService FAILED 1060: The specified service does not exist as an installed service.
2 - Not running
([SC] ControlService FAILED 1062: The service has not been started)
3 - Running
TYPE : 10 WIN32_OWN_PROCESS
STATE : 2 START_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x7d0
PID : 21100code here
So using them in following code, gives us the desired result :-
public static void checkBackgroundService(String serviceName) {
Process process;
try {
process = Runtime.getRuntime().exec("sc interrogate " + serviceName);
Scanner reader = new Scanner(process.getInputStream(), "UTF-8");
StringBuffer buffer = new StringBuffer();
while (reader.hasNextLine()) {
buffer.append(reader.nextLine());
}
System.out.println(buffer.toString());
if (buffer.toString().contains("1060:")) {
System.out.println("Specified Service does not exist");
} else if (buffer.toString().contains("1062:")) {
System.out.println("Specified Service is not started (not running)");
} else {
System.out.println("Specified Service is running");
}
} catch (IOException e) {
e.printStackTrace();
}
}
During startup, create a file with File.deleteOnExit().
Check for the existence of the file in your scripts.
Simply call this method to check the status of service whether running or not.
public boolean checkIfServiceRunning(String serviceName) {
Process process;
try {
process = Runtime.getRuntime().exec("sc query " + serviceName);
Scanner reader = new Scanner(process.getInputStream(), "UTF-8");
while(reader.hasNextLine()) {
if(reader.nextLine().contains("RUNNING")) {
return true;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
Does anyone know how Java is able to circumvent the windows MAX_PATH limitations. Using the below code I was able to create a really long path in Java and was able to perform I/O, which would have been impossible using windows without prefixing \\?\.
public static void main(String[] args) throws IOException {
BufferedWriter bufWriter = null;
try {
StringBuilder s = new StringBuilder();
for (int i = 0; i < 130; i++) {
s.append("asdf\\");
}
String filePath = "C:\\" + s.toString();;
System.out.println("File Path = " + filePath);
File f = new File(filePath);
f.mkdirs();
f = new File(f, "dummy.txt");
System.out.println("Full path = " + f);
bufWriter = new BufferedWriter(new FileWriter(f));
bufWriter.write("Hello");
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (bufWriter != null) {
bufWriter.close();
}
}
}
From the JVM's canonicalize_md.c:
/* copy \\?\ or \\?\UNC\ to the front of path*/
WCHAR* getPrefixed(const WCHAR* path, int pathlen) {
[download JVM source code (below) to see implementation]
}
The function getPrefixed is called:
by the function wcanonicalize if ((pathlen = wcslen(path)) > MAX_PATH - 1)
by the function wcanonicalizeWithPrefix.
I didn't trace the call chain farther than that, but I assume the JVM always uses these canonicalization routines before accessing the filesystem, and so always hits this code one way or another. If you want to trace the call chain farther yourself, you too can partake in the joys of browsing the JVM source code! Download at: http://download.java.net/openjdk/jdk6/
Windows bypasses that limitation if the path is prefixed with \\?\.
Most likely Java is in fact using UNC paths (\?) internally.
I have a Java application that I'm about to begin to use Web Start to deploy. But a new demand has made me rethink this, as I'm now required to add a piece of functionality that allows the end user to select whether or not they'd like to run this program on startup (of Windows, not cross-platform). But I'd still like to shy away from making this run as a service. Is there any way that this can be accomplished using Web Start, or should I explore other options to deploy this? Thanks in advance.
It actually works to put a this in the jnlp-file:
<shortcut online="true">
<desktop/>
<menu submenu="Startup"/>
</shortcut>
But that still would only work with English windows versions. German is "Autostart", Spanish was "Iniciar" I think. So it causes basically the same headache as the way via the IntegrationService.
I have not tried it, but I wonder if you could use the new JNLP IntegrationService in combination with the javaws command line program. The idea being to programmatically create a shortcut in the Windows startup group (although that location is dependent on specific Windows version).
To get around the language problem for the Startup folder just use the registry. Here is some code that should work. This calls reg.exe to make registry changes.
public class StartupCreator {
public static void setupStartupOnWindows(String jnlpUrl, String applicationName) throws Exception {
String foundJavaWsPath = findJavaWsOnWindows();
String cmd = foundJavaWsPath + " -Xnosplash \"" + jnlpUrl + "\"";
setRegKey("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", applicationName, cmd);
}
public static String findJavaWsOnWindows() {
// The paths where it will look for java
String[] paths = {
// first use the JRE that was used to launch this app, it will probably not reach the below paths
System.getProperty("java.home") + File.separator + "bin" + File.separator + "javaws.exe",
// it must check for the 64 bit path first because inside a 32-bit process system32 is actually syswow64
// 64 bit machine with 32 bit JRE
System.getenv("SYSTEMROOT") + File.separator + "syswow64" + File.separator + "javaws.exe",
// 32 bit machine with 32 bit JRE or 64 bit machine with 64 bit JRE
System.getenv("SYSTEMROOT") + File.separator + "system32" + File.separator + "javaws.exe",};
return findJavaWsInPaths(paths);
}
public static String findJavaWsInPaths(String[] paths) throws RuntimeException {
String foundJavaWsPath = null;
for (String p : paths) {
File f = new File(p);
if (f.exists()) {
foundJavaWsPath = p;
break;
}
}
if (foundJavaWsPath == null) {
throw new RuntimeException("Could not find path for javaws executable");
}
return foundJavaWsPath;
}
public static String setRegKey(String location, String regKey, String regValue) throws Exception {
String regCommand = "add \"" + location + "\" /v \"" + regKey + "\" /f /d \"" + regValue + "\"";
return doReg(regCommand);
}
public static String doReg(String regCommand) throws Exception {
final String REG_UTIL = "reg";
final String regUtilCmd = REG_UTIL + " " + regCommand;
return runProcess(regUtilCmd);
}
public static String runProcess(final String regUtilCmd) throws Exception {
StringWriter sw = new StringWriter();
Process process = Runtime.getRuntime().exec(regUtilCmd);
InputStream is = process.getInputStream();
int c = 0;
while ((c = is.read()) != -1) {
sw.write(c);
}
String result = sw.toString();
try {
process.waitFor();
} catch (Throwable ex) {
System.out.println(ex.getMessage());
}
if (process.exitValue() == -1) {
throw new Exception("REG QUERY command returned with exit code -1");
}
return result;
}
}
I'm writing a program in scala which call:
Runtime.getRuntime().exec( "svn ..." )
I want to check if "svn" is available from the commandline (ie. it is reachable in the PATH).
How can I do this ?
PS: My program is designed to be run on windows
Here's a Java 8 solution:
String exec = <executable name>;
boolean existsInPath = Stream.of(System.getenv("PATH").split(Pattern.quote(File.pathSeparator)))
.map(Paths::get)
.anyMatch(path -> Files.exists(path.resolve(exec)));
Replace anyMatch(...) with filter(...).findFirst() to get a fully qualified path.
Here's a cross-platform static method that compares common executable extensions:
import java.io.File;
import java.nio.file.Paths;
import java.util.stream.Stream;
import static java.io.File.pathSeparator;
import static java.nio.file.Files.isExecutable;
import static java.lang.System.getenv;
import static java.util.regex.Pattern.quote;
public static boolean canExecute( final String exe ) {
final var paths = getenv( "PATH" ).split( quote( pathSeparator ) );
return Stream.of( paths ).map( Paths::get ).anyMatch(
path -> {
final var p = path.resolve( exe );
var found = false;
for( final var extension : EXTENSIONS ) {
if( isExecutable( Path.of( p.toString() + extension ) ) ) {
found = true;
break;
}
}
return found;
}
);
}
This should address most of the critiques for the first solution. Aside, iterating over the PATHEXT system environment variable would avoid hard-coding extensions, but comes with its own drawbacks.
I'm no scala programmer, but what I would do in any language, is to execute something like 'svn help' just to check the return code (0 or 1) of the exec method... if it fails the svn is not in the path :P
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("svn help");
int exitVal = proc.exitValue();
By convention, the value 0 indicates normal termination.
this code uses "where" command on Windows, and "which" command on other systems, to check if the system knows about the desired program in PATH. If found, the function returns a java.nio.file.Path to the program, and null otherwise.
I tested it with Java 8 on Windows 7 and Linux Mint 17.3.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Logger;
public class SimulationUtils
{
private final static Logger LOGGER = Logger.getLogger(SimulationUtils.class.getName());
public static Path lookForProgramInPath(String desiredProgram) {
ProcessBuilder pb = new ProcessBuilder(isWindows() ? "where" : "which", desiredProgram);
Path foundProgram = null;
try {
Process proc = pb.start();
int errCode = proc.waitFor();
if (errCode == 0) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
foundProgram = Paths.get(reader.readLine());
}
LOGGER.info(desiredProgram + " has been found at : " + foundProgram);
} else {
LOGGER.warning(desiredProgram + " not in PATH");
}
} catch (IOException | InterruptedException ex) {
LOGGER.warning("Something went wrong while searching for " + desiredProgram);
}
return foundProgram;
}
private static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("windows");
}
}
To use it :
System.out.println(SimulationUtils.lookForProgramInPath("notepad"));
On my Windows 7 system, it displays :
C:\Windows\System32\notepad.exe
And on linux :
System.out.println(SimulationUtils.lookForProgramInPath("psql"));
/usr/bin/psql
The advantage of this method is that it should work on any platform and there's no need to parse the PATH environment variable or look at the registry. The desired program is never called, even if found. Finally, there's no need to know the program extension. gnuplot.exe under Windows and gnuplot under Linux would both be found by the same code :
SimulationUtils.lookForProgramInPath("gnuplot")
Suggestions for improvement are welcome!
Selenium has what looks to be a reasonably complete implementation for Windows/Linux/Mac in the class org.openqa.selenium.os.ExecutableFinder, with public access since Selenium 3.1 (previously only accessible via the deprecated method org.openqa.selenium.os.CommandLine#find). It is ASL 2.0 though.
Note that ExecutableFinder doesn't understand PATHEXT on Windows - it just has a hard-coded set of executable file extensions (.exe, .com, .bat).
This is similar to Dmitry Ginzburg's answer but it also addresses the rare case of someone having an invalid path in the PATH environment variable. This would cause an InvalidPathException.
private static final String ENVIRONMENT_VARIABLES_TEXT = System.getenv("PATH");
private static boolean isCommandAvailable(String executableFileName)
{
String[] environmentVariables = ENVIRONMENT_VARIABLES_TEXT.split(File.pathSeparator);
for (String environmentVariable : environmentVariables)
{
try
{
Path environmentVariablePath = Paths.get(environmentVariable);
if (Files.exists(environmentVariablePath))
{
Path resolvedEnvironmentVariableFilePath = environmentVariablePath.resolve(executableFileName);
if (Files.isExecutable(resolvedEnvironmentVariableFilePath))
{
return true;
}
}
} catch (InvalidPathException exception)
{
exception.printStackTrace();
}
}
return false;
}
Overall this might now be the most efficient and robust solution.
Concerning the original question I'd also check for existence as FMF suggested.
I'd also like to point out that you'll have to handle at least the output of the process, reading available data so the streams won't be filled to the brim. This would cause the process to block, otherwise.
To do this, retrieve the InputStreams of the process using proc.getInputStream() (for System.out) and proc.getErrorStream() (for System.err) and read available data in different threads.
I just tell you because this is a common pitfall and svn will potentially create quite a bit of output.
If you have cygwin installed you could first call "which svn", which will return the absolute path to svn if it's in the executable path, or else "which: no svn in (...)". The call to "which" will return an exitValue of 1 if not found, or 0 if it is found. You can check this error code in the manner FMF details.
In my experience it is impossible to tell over the various systems through just calling a the command with the ProcessBuilder if it exits or not (neither Exceptions nor return values seem consistent)
So here is a Java7 solution that traverses the PATH environment variable and looks for a matching tool. Will check all files if directory. The matchesExecutable must be the name of the tool ignoring extension and case.
public static File checkAndGetFromPATHEnvVar(final String matchesExecutable) {
String[] pathParts = System.getenv("PATH").split(File.pathSeparator);
for (String pathPart : pathParts) {
File pathFile = new File(pathPart);
if (pathFile.isFile() && pathFile.getName().toLowerCase().contains(matchesExecutable)) {
return pathFile;
} else if (pathFile.isDirectory()) {
File[] matchedFiles = pathFile.listFiles(new FileFilter() {
#Override
public boolean accept(File pathname) {
return FileUtil.getFileNameWithoutExtension(pathname).toLowerCase().equals(matchesExecutable);
}
});
if (matchedFiles != null) {
for (File matchedFile : matchedFiles) {
if (FileUtil.canRunCmd(new String[]{matchedFile.getAbsolutePath()})) {
return matchedFile;
}
}
}
}
}
return null;
}
Here are the helper:
public static String getFileNameWithoutExtension(File file) {
String fileName = file.getName();
int pos = fileName.lastIndexOf(".");
if (pos > 0) {
fileName = fileName.substring(0, pos);
}
return fileName;
}
public static boolean canRunCmd(String[] cmd) {
try {
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
Process process = pb.start();
try (BufferedReader inStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
while ((inStreamReader.readLine()) != null) {
}
}
process.waitFor();
} catch (Exception e) {
return false;
}
return true;
}
you can use the where command under windows. Let's suppose you check if the git-bash.exe app is on the windows path. You must run the shell command: cmd /c where git-bash. Then on the returned trimmed string you can do: if(shellResult!=null && shellResult.endsWith('git-bash.exe')) ..... do yout things
Beware: The accepted answer executes the target program. So, if you would use "shutdown", for instance, your system may shutdown just because you wanted to know if it exists.
I added my solution that does an exact match. It does not check if the file is executable. It is case-sensitive. If this does not meet your needs, feel free to adapt it accordingly.
public static File findInPATH(String executable) {
String[] PATH = System.getenv("PATH").split(File.pathSeparator);
for (var p : PATH) {
File entry = new File(p);
if (!entry.exists())
continue;
if (entry.isFile() && entry.getName().equals(executable)) {
return entry;
} else if (entry.isDirectory()) {
for (var f : entry.listFiles())
if (f.getName().equals(executable))
return f;
}
}
return null;
}
Here is the situation:
I have been called upon to work with InstallAnywhere 8, a Java-based installer IDE, of sorts, that allows starting and stopping of windows services, but has no built-in method to query their states. Fortunately, it allows you to create custom actions in Java which can be called at any time during the installation process (by way of what I consider to be a rather convoluted API).
I just need something that will tell me if a specific service is started or stopped.
The IDE also allows calling batch scripts, so this is an option as well, although once the script is run, there is almost no way to verify that it succeeded, so I'm trying to avoid that.
Any suggestions or criticisms are welcome.
here's what I had to do. It's ugly, but it works beautifully.
String STATE_PREFIX = "STATE : ";
String s = runProcess("sc query \""+serviceName+"\"");
// check that the temp string contains the status prefix
int ix = s.indexOf(STATE_PREFIX);
if (ix >= 0) {
// compare status number to one of the states
String stateStr = s.substring(ix+STATE_PREFIX.length(), ix+STATE_PREFIX.length() + 1);
int state = Integer.parseInt(stateStr);
switch(state) {
case (1): // service stopped
break;
case (4): // service started
break;
}
}
runProcess is a private method that runs the given string as a command line process and returns the resulting output. As I said, ugly, but works. Hope this helps.
You can create a small VBS on-th-fly, launch it and capture its return code.
import java.io.File;
import java.io.FileWriter;
public class VBSUtils {
private VBSUtils() { }
public static boolean isServiceRunning(String serviceName) {
try {
File file = File.createTempFile("realhowto",".vbs");
file.deleteOnExit();
FileWriter fw = new java.io.FileWriter(file);
String vbs = "Set sh = CreateObject(\"Shell.Application\") \n"
+ "If sh.IsServiceRunning(\""+ serviceName +"\") Then \n"
+ " wscript.Quit(1) \n"
+ "End If \n"
+ "wscript.Quit(0) \n";
fw.write(vbs);
fw.close();
Process p = Runtime.getRuntime().exec("wscript " + file.getPath());
p.waitFor();
return (p.exitValue() == 1);
}
catch(Exception e){
e.printStackTrace();
}
return false;
}
public static void main(String[] args){
//
// DEMO
//
String result = "";
msgBox("Check if service 'Themes' is running (should be yes)");
result = isServiceRunning("Themes") ? "" : " NOT ";
msgBox("service 'Themes' is " + result + " running ");
msgBox("Check if service 'foo' is running (should be no)");
result = isServiceRunning("foo") ? "" : " NOT ";
msgBox("service 'foo' is " + result + " running ");
}
public static void msgBox(String msg) {
javax.swing.JOptionPane.showConfirmDialog((java.awt.Component)
null, msg, "VBSUtils", javax.swing.JOptionPane.DEFAULT_OPTION);
}
}
Based on the other answers I constructed the following code to check for Windows Service status:
public void checkService() {
String serviceName = "myService";
try {
Process process = new ProcessBuilder("C:\\Windows\\System32\\sc.exe", "query" , serviceName ).start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
String scOutput = "";
// Append the buffer lines into one string
while ((line = br.readLine()) != null) {
scOutput += line + "\n" ;
}
if (scOutput.contains("STATE")) {
if (scOutput.contains("RUNNING")) {
System.out.println("Service running");
} else {
System.out.println("Service stopped");
}
} else {
System.out.println("Unknown service");
}
} catch (IOException e) {
e.printStackTrace();
}
}
I have been dealing with installers for years and the trick is to create your own EXE and call it on setup. This offers good flexibility like displaying precise error messages in the event an error occurs, and have success-based return values so your installer knows about what happened.
Here's how to start, stop and query states for windows services (C++):
http://msdn.microsoft.com/en-us/library/ms684941(VS.85).aspx
(VB and C# offers similar functions)
I have had some luck in the past with the Java Service Wrapper. Depending upon your situation you may need to pay in order to use it. But it offers a clean solution that supports Java and could be used in the InstallAnywhere environment with (I think) little trouble. This will also allow you to support services on Unix boxes as well.
http://wrapper.tanukisoftware.org/doc/english/download.jsp
A shot in the dark but take a look at your Install Anywhere java documentation.
Specifically,
/javadoc/com/installshield/wizard/platform/win32/Win32Service.html
The class:
com.installshield.wizard.platform.win32
Interface Win32Service
All Superinterfaces:
Service
The method:
public NTServiceStatus queryNTServiceStatus(String name)
throws ServiceException
Calls the Win32 QueryServiceStatus to retrieve the status of the specified service. See the Win32 documentation for this API for more information.
Parameters:
name - The internal name of the service.
Throws:
ServiceException
Here's a straignt C# / P/Invoke solution.
/// <summary>
/// Returns true if the specified service is running, or false if it is not present or not running.
/// </summary>
/// <param name="serviceName">Name of the service to check.</param>
/// <returns>Returns true if the specified service is running, or false if it is not present or not running.</returns>
static bool IsServiceRunning(string serviceName)
{
bool rVal = false;
try
{
IntPtr smHandle = NativeMethods.OpenSCManager(null, null, NativeMethods.ServiceAccess.ENUMERATE_SERVICE);
if (smHandle != IntPtr.Zero)
{
IntPtr svHandle = NativeMethods.OpenService(smHandle, serviceName, NativeMethods.ServiceAccess.ENUMERATE_SERVICE);
if (svHandle != IntPtr.Zero)
{
NativeMethods.SERVICE_STATUS servStat = new NativeMethods.SERVICE_STATUS();
if (NativeMethods.QueryServiceStatus(svHandle, servStat))
{
rVal = servStat.dwCurrentState == NativeMethods.ServiceState.Running;
}
NativeMethods.CloseServiceHandle(svHandle);
}
NativeMethods.CloseServiceHandle(smHandle);
}
}
catch (System.Exception )
{
}
return rVal;
}
public static class NativeMethods
{
[DllImport("AdvApi32")]
public static extern IntPtr OpenSCManager(string machineName, string databaseName, ServiceAccess access);
[DllImport("AdvApi32")]
public static extern IntPtr OpenService(IntPtr serviceManagerHandle, string serviceName, ServiceAccess access);
[DllImport("AdvApi32")]
public static extern bool CloseServiceHandle(IntPtr serviceHandle);
[DllImport("AdvApi32")]
public static extern bool QueryServiceStatus(IntPtr serviceHandle, [Out] SERVICE_STATUS status);
[Flags]
public enum ServiceAccess : uint
{
ALL_ACCESS = 0xF003F,
CREATE_SERVICE = 0x2,
CONNECT = 0x1,
ENUMERATE_SERVICE = 0x4,
LOCK = 0x8,
MODIFY_BOOT_CONFIG = 0x20,
QUERY_LOCK_STATUS = 0x10,
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_ALL = 0x10000000
}
public enum ServiceState
{
Stopped = 1,
StopPending = 3,
StartPending = 2,
Running = 4,
Paused = 7,
PausePending =6,
ContinuePending=5
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class SERVICE_STATUS
{
public int dwServiceType;
public ServiceState dwCurrentState;
public int dwControlsAccepted;
public int dwWin32ExitCode;
public int dwServiceSpecificExitCode;
public int dwCheckPoint;
public int dwWaitHint;
};
}
I improvised on the given solutions, to make it locale independent.
Comparing the string "RUNNING" would not work in systems with non-english locales as Alejandro González rightly pointed out.
I made use of sc interrogate and look for the status codes returned by it.
Mainly, the service can have 3 states:-
1 - Not available
[SC] OpenService FAILED 1060: The specified service does not exist as an installed service.
2 - Not running
([SC] ControlService FAILED 1062: The service has not been started)
3 - Running
TYPE : 10 WIN32_OWN_PROCESS
STATE : 2 START_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x7d0
PID : 21100code here
So using them in following code, gives us the desired result :-
public static void checkBackgroundService(String serviceName) {
Process process;
try {
process = Runtime.getRuntime().exec("sc interrogate " + serviceName);
Scanner reader = new Scanner(process.getInputStream(), "UTF-8");
StringBuffer buffer = new StringBuffer();
while (reader.hasNextLine()) {
buffer.append(reader.nextLine());
}
System.out.println(buffer.toString());
if (buffer.toString().contains("1060:")) {
System.out.println("Specified Service does not exist");
} else if (buffer.toString().contains("1062:")) {
System.out.println("Specified Service is not started (not running)");
} else {
System.out.println("Specified Service is running");
}
} catch (IOException e) {
e.printStackTrace();
}
}
During startup, create a file with File.deleteOnExit().
Check for the existence of the file in your scripts.
Simply call this method to check the status of service whether running or not.
public boolean checkIfServiceRunning(String serviceName) {
Process process;
try {
process = Runtime.getRuntime().exec("sc query " + serviceName);
Scanner reader = new Scanner(process.getInputStream(), "UTF-8");
while(reader.hasNextLine()) {
if(reader.nextLine().contains("RUNNING")) {
return true;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}