Java Runtime Exec on Windows Fails with Unicode in Arguments
Asked Answered
I

6

7

I want to launch a browser and load a web page using Java's Runtime exec. The exact call looks like this:

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 it's a java bug: https://bugs.java.com/bugdatabase/view_bug?bug_id=4947220

My question is: is there a viable workaround that can be done solely using Java? It appears that it is possible to write a JNI library for this, but I'd like to avoid that if possible. I have tried URI-encoding the path as ascii and writing the commands to a batch file, without success.

Instil answered 9/12, 2009 at 20:8 Comment(1)
This bug has been fixed in Java 6 and 7, and presumably all later versions. The workaround should no longer be necessary,Soonsooner
P
2

At the mentioned Java bug page you will find a workaround that is reported to work using ProcessBuilder and wrapping the parameters in environment variables. Here is the source code from 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();
Pomiculture answered 11/8, 2010 at 15:49 Comment(0)
N
2

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

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

Create a temp file called temp.bat and execute with the Runtime.getRuntime().exec temp.bat

chcp 65001
C:\aconex\学校\mysql\bin\mysql -esource 大村箕島a\data.sql
Necrosis answered 23/3, 2015 at 5:44 Comment(0)
I
0

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

  1. Create a temp html redirect file which will redirect the browser to the proper page. Note that IE will expect unencoded unicode for local files, while other browsers may accept only uri-encoded file paths

  2. Use the short filename for the windows file. It won't contain unicode characters.

Instil answered 16/12, 2009 at 19:25 Comment(0)
L
0

We've been using a JNI to start processes from Java for years. Neither Runtime.exec or ProcessBuilder will work, and it seems unlikely that they will fix this, given how long it's been already.

However, you should be able to work around the issue by using the input stream, a socket, or environment variables to pass parameters. If you don't have direct control over the executable, you'll have to make a wrapper.

Litt answered 15/6, 2011 at 3:49 Comment(0)
C
0

You could use JNA. With version 3.3.0 or later call 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 the child process is a bit harder but not impossible.

Chkalov answered 20/9, 2011 at 6:26 Comment(0)
S
-1

I think you can use Apache Commons Exec library or ProcessBuilder to give a try;)

Shawana answered 16/12, 2009 at 19:34 Comment(3)
ProcessBuilder seems to have the same trouble with unicode in its command argument string. I unfortunately can't bring in an outside library for my particular case.Instil
How about initialize your arguments to variables using getPath() method and use them in ProcessBuilder without touching any non-unicode stuff within source code?Shawana
Apache Commons Exec uses the Runtime.exec() API internally, you will still have the same problem as before.Inclining

© 2022 - 2024 — McMap. All rights reserved.