-1

I have a simple GUI which selects an executable and a batch file. Clicking "run" should launch a command line instance, then run the executable given the selected batch. However, hiccups seem to show up at different points. This is the relevant code snippet:

String[] commands = {"cmd.exe", "/c", "C:\\Xilinx\\14.7\\ISE_DS\\settings64.bat && cd /d ",
                "\"" + simFile.getParent() + "\"", " && ping localhost && ",
                "\"" + jTextField1.getText() + "\"",  " -tclbatch \"" + jTextField2.getText() + "\""};

ProcessBuilder simBuilder = new ProcessBuilder(commands);
simBuilder.redirectErrorStream(true);
Process simulation = simBuilder.start();

BufferedReader reader = new BufferedReader(new InputStreamReader(simulation.getInputStream()));
String line;
while (true) {
    line = reader.readLine();
    if (line == null)
        break;
    System.out.println(line);
}

I chose to create a process through a ProcessBuilder rather than "Runtime.getRuntime().exec" because having the command and arguments as a String array is more readable and manageable. I took a look through the documentation of Runtime, Process, and ProcessBuilder. I also searched for similar questions, the following being the closest: Run cmd commands through Java. However, I'm still having issues getting all commands to run properly, if it all. First point: The program successfully executes the commands until "ping", which I placed to determine where the issue occurs. I get the cmd output in the console through the BufferedReader just fine. However, the next command, which should run the executable indicated by "jTextField1.getText()", gives an error of "The filename, directory name, or volume label syntax is incorrect" although I made sure the path is within escaped double quotes to account for spaces. Is it something in my syntax? Something to do with where the double ampersands are placed? Does every separate command with its argument need to be its own string in the array? I tried that and different things, but it always seems to result in an error.

KMZ
  • 1

1 Answers1

0

You should check that your path names are correct, and try the cmd as one parameter value not as comma separated after cmd.exe /c. This will ensure the arguments are passed to CMD correctly as a single argument for the CMD shell to handle:

import java.nio.file.Files
System.out.println("Files.isDirectory(simFile.getParent())="+Files.isDirectory(simFile.getParent()));
System.out.println("Files.isExecutable(jTextField1.getText())="+Files.isExecutable(Path.of(jTextField1.getText())));

String cmd = "C:\\Xilinx\\14.7\\ISE_DS\\settings64.bat && cd /d "+
            "\"" + simFile.getParent() + "\" && ping localhost && "+
            "\"" + jTextField1.getText() + "\" -tclbatch \"" + jTextField2.getText() + "\"";
String[] commands = {"cmd.exe", "/c", cmd};
DuncG
  • 12,137
  • 2
  • 21
  • 33
  • Thanks. I got errors on the top two lines, so I skipped trying them out. But having all the commands in a single string did work out. May I ask what the reason is? Also, for some reason, excluding "/c" from the string array seems to get the whole program stuck without displaying anything. No buttons can be pressed, and even the exit button does nothing, so I have to use task manager. It shows the cmd line running as a subprocess of the java application, so it seems stuck in the background. Using "/k" instead runs and displays the results of all the commands, but then gets stuck. – KMZ Jan 30 '21 at 19:04
  • Maybe the the cause of your UI freeze is that you are running this action handler in the main UI event loop / thread. If so try in background thread, and make the button disabled while it runs. – DuncG Feb 07 '21 at 16:34
  • I see. That makes sense. If I'm not being bothersome, what's the appropriate way to perform the reading and writing in separate threads? In my understanding, if I create buffered readers (for cmd regular and error output) and writer in the main thread, I won't be able to pass their references to a custom thread class that will use them because Java passes by value. Alternatively, if I make the readers in the custom thread class definition, I don't know if it's possible to have them access the process defined in the main class (NetBeans tells me there's no such process when I do that). – KMZ Feb 12 '21 at 19:04
  • I found a solution for the multi-threading issue. My understanding of passing by value in Java was flawed. When passing object variables, Java passes their reference by value. Therefore, the method/constructor will get the reference to the same object and be able to use its methods. I could pass the BufferedReader just fine, and the thread did the reading as expected. I also figured out that I could keep the writing functionalities within the main thread. – KMZ Feb 20 '21 at 21:01