Java Runtime Exec for Windows does not work with Unicode in arguments

I want to launch a browser and load a webpage using Java Runtime exec. The exact call is as follows:

String[] explorer = {"C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE", "-noframemerging", "C:\\ ... path containing unicode chars ... \\Main.html"}; Runtime.getRuntime().exec(explorer); 

In my case, the path contains "\u65E5\u672C\u8A9E" , the characters 日本語.

Apparently this is a Java bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4947220

My question is: is there a viable workaround that can only be done using Java? It seems like you can write a JNI library for this, but I would like to avoid this if possible. I tried to encode the URI path as ascii and write commands to a batch file without success.

+6
windows unicode
source share
6 answers

On the mentioned Java bug page , you will find a workaround that is reported to work using ProcessBuilder and wrap parameters in environment variables. Here is the source code for Parag Thakur:

 String[] cmd = new String[]{"yourcmd.exe", "Japanese CLI argument: \ufeff\u30cb\u30e5\u30fc\u30b9"}; Map<String, String> newEnv = new HashMap<String, String>(); newEnv.putAll(System.getenv()); String[] i18n = new String[cmd.length + 2]; i18n[0] = "cmd"; i18n[1] = "/C"; i18n[2] = cmd[0]; for (int counter = 1; counter < cmd.length; counter++) { String envName = "JENV_" + counter; i18n[counter + 2] = "%" + envName + "%"; newEnv.put(envName, cmd[counter]); } cmd = i18n; ProcessBuilder pb = new ProcessBuilder(cmd); Map<String, String> env = pb.environment(); env.putAll(newEnv); final Process p = pb.start(); 
+2
source share

These are the two solutions that I reviewed, each of which are more or less workarounds:

  • Create a temp html redirect file that redirects the browser to the desired page. Note that IE will expect unencoded unicode for local files, while other browsers can only accept uri encoded files

  • Use the short file name for the Windows file. It will not contain Unicode characters.

0
source share

We used JNI to run processes with Java for many years. Neither Runtime.exec nor ProcessBuilder will work, and it is unlikely that they will fix it, given how long it has been.

However, you should be able to work around the problem by using an input stream, socket, or environment variables to pass parameters. If you do not have direct control over the executable, you will have to create a shell.

0
source share

You can use JNA . With version 3.3.0 or later of CreateProcess :

 WinBase.PROCESS_INFORMATION.ByReference processInfo = new WinBase.PROCESS_INFORMATION.ByReference(); WinBase.STARTUPINFO startupInfo = new WinBase.STARTUPINFO(); String command = "C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE " + "-noframemerging \"C:\\\u65E5\u672C\u8A9E\\Main.html\""; if (!Kernel32.INSTANCE.CreateProcess( null, // Application name, not needed if supplied in command line command, // Command line null, // Process security attributes null, // Thread security attributes true, // Inherit handles 0, // Creation flags null, // Environment null, // Directory startupInfo, processInfo)) { throw new IllegalStateException("Error creating process. Last error: " + Kernel32.INSTANCE.GetLastError()); } // The CreateProcess documentation indicates that it is very important to // close the returned handles Kernel32.INSTANCE.CloseHandle(processInfo.hThread); Kernel32.INSTANCE.CloseHandle(processInfo.hProcess); long pid = processInfo.dwProcessId.longValue(); 

Redirecting output from a child process is a bit more complicated, but not impossible.

0
source share

Create a .bat / .sh file. Write your commands to this file and execute it. Make sure you change the code page to unicode in case of windows (chcp 65001). For example, to execute the following command in windows:

 String[] command ={"C:\\aconex\\学校\\mysql\\bin\\mysql", "-esource", "大村箕島a\\data.sql"}; 

Create a temporary temp.bat file and execute using Runtime.getRuntime (). exec temp.bat

 chcp 65001 C:\aconex\学校\mysql\bin\mysql -esource 大村箕島a\data.sql 
0
source share

I think you can use the Apache Commons Exec or ProcessBuilder library to try :)

-one
source share

All Articles