From 8f652ce12d0f0f358acfb10cb0c8c76d1b7dae04 Mon Sep 17 00:00:00 2001 From: James Sanders Date: Thu, 29 Nov 2007 18:01:07 -0700 Subject: [PATCH] Implemented native Process.exitValue and Process.waitFor on windows --- classpath/java-lang.cpp | 80 +++++++++++++++++++++++--------- classpath/java/lang/Runtime.java | 18 +++---- test/RuntimeExec.java | 33 +++++++++++-- 3 files changed, 98 insertions(+), 33 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index bcc1f0318c..9a73e90715 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -11,6 +11,7 @@ #ifdef WIN32 # include "windows.h" +# include "winbase.h" # include "io.h" # include "tchar.h" # define SO_PREFIX "" @@ -28,6 +29,25 @@ namespace { #ifdef WIN32 + char* getErrorStr(DWORD err){ + // The poor man's error string, just print the error code + char * errStr = (char*) malloc(9 * sizeof(char)); + snprintf(errStr, 9, "%d", (int) err); + return errStr; + + // The better way to do this, if I could figure out how to convert LPTSTR to char* + //char* errStr; + //LPTSTR s; + //if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + // FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, &s, 0, NULL) == 0) + //{ + // errStr.Format("Unknown error occurred (%08x)", err); + //} else { + // errStr = s; + //} + //return errStr; + } + void makePipe(JNIEnv* e, HANDLE p[2]) { SECURITY_ATTRIBUTES sa; @@ -37,9 +57,7 @@ namespace { BOOL success = CreatePipe(p, p + 1, &sa, 0); if (not success) { - char* errStr = (char*) malloc(9 * sizeof(char)); - snprintf(errStr, 9, "%d", (int) GetLastError()); - throwNew(e, "java/io/IOException", errStr); + throwNew(e, "java/io/IOException", getErrorStr(GetLastError())); } } @@ -55,10 +73,10 @@ namespace { } #ifdef WIN32 -extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, - jobjectArray command, jintArray process) +extern "C" JNIEXPORT void JNICALL +Java_java_lang_Runtime_exec(JNIEnv* e, jclass, + jobjectArray command, jlongArray process) { - //const char* line = e->GetStringUTFChars(command, 0); int size = 0; for (int i = 0; i < e->GetArrayLength(command); ++i){ @@ -73,31 +91,30 @@ extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, jstring element = (jstring) e->GetObjectArrayElement(command, i); const char* s = e->GetStringUTFChars(element, 0); _tcscpy(linep, s); + e->ReleaseStringUTFChars(element, s); linep += e->GetStringUTFLength(element); } *(linep++) = _T('\0'); - printf("command: %s\n", _T(line)); - HANDLE in[] = { 0, 0 }; HANDLE out[] = { 0, 0 }; HANDLE err[] = { 0, 0 }; makePipe(e, in); SetHandleInformation(in[0], HANDLE_FLAG_INHERIT, 0); - jint inDescriptor = descriptor(e, in[0]); + jlong inDescriptor = static_cast(descriptor(e, in[0])); if(e->ExceptionOccurred()) return; - e->SetIntArrayRegion(process, 1, 1, &inDescriptor); + e->SetLongArrayRegion(process, 1, 1, &inDescriptor); makePipe(e, out); SetHandleInformation(out[1], HANDLE_FLAG_INHERIT, 0); - jint outDescriptor = descriptor(e, out[1]); + jlong outDescriptor = static_cast(descriptor(e, out[1])); if(e->ExceptionOccurred()) return; - e->SetIntArrayRegion(process, 2, 1, &outDescriptor); + e->SetLongArrayRegion(process, 2, 1, &outDescriptor); makePipe(e, err); SetHandleInformation(err[0], HANDLE_FLAG_INHERIT, 0); - jint errDescriptor = descriptor(e, err[0]); + jlong errDescriptor = static_cast(descriptor(e, err[0])); if(e->ExceptionOccurred()) return; - e->SetIntArrayRegion(process, 3, 1, &errDescriptor); + e->SetLongArrayRegion(process, 3, 1, &errDescriptor); PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); @@ -113,20 +130,41 @@ extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, BOOL success = CreateProcess(0, (LPSTR) line, 0, 0, 1, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, 0, 0, &si, &pi); - - //e->ReleaseStringUTFChars(command, line); if (not success) { - char* errStr = (char*) malloc(9 * sizeof(char)); - snprintf(errStr, 9, "%d", (int) GetLastError()); - throwNew(e, "java/io/IOException", errStr); + throwNew(e, "java/io/IOException", getErrorStr(GetLastError())); return; } - jint pid = reinterpret_cast(pi.hProcess); - e->SetIntArrayRegion(process, 0, 1, &pid); + jlong pid = reinterpret_cast(pi.hProcess); + e->SetLongArrayRegion(process, 0, 1, &pid); } + +extern "C" JNIEXPORT jint JNICALL +Java_java_lang_Runtime_exitValue(JNIEnv* e, jclass, jlong pid) +{ + DWORD exitCode; + BOOL success = GetExitCodeProcess(reinterpret_cast(pid), &exitCode); + if(not success){ + throwNew(e, "java/lang/Exception", getErrorStr(GetLastError())); + } else if(exitCode == STILL_ACTIVE){ + throwNew(e, "java/lang/IllegalThreadStateException", "Process is still active"); + } + return exitCode; +} + +extern "C" JNIEXPORT jint JNICALL +Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid) +{ + DWORD exitCode; + WaitForSingleObject(reinterpret_cast(pid), INFINITE); + BOOL success = GetExitCodeProcess(reinterpret_cast(pid), &exitCode); + if(not success){ + throwNew(e, "java/lang/Exception", getErrorStr(GetLastError())); + } + return exitCode; +} #endif extern "C" JNIEXPORT jstring JNICALL diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index f8478e0de9..9307ede463 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -34,28 +34,28 @@ public class Runtime { } public Process exec(String command) throws IOException { - int[] process = new int[4]; + long[] process = new long[4]; StringTokenizer t = new StringTokenizer(command); String[] cmd = new String[t.countTokens()]; for (int i = 0; i < cmd.length; i++) cmd[i] = t.nextToken(); exec(cmd, process); - return new MyProcess(process[0], process[1], process[2], process[3]); + return new MyProcess(process[0], (int) process[1], (int) process[2], (int) process[3]); } public Process exec(String[] command) { - int[] process = new int[4]; + long[] process = new long[4]; exec(command, process); - return new MyProcess(process[0], process[1], process[2], process[3]); + return new MyProcess(process[0], (int) process[1], (int) process[2], (int) process[3]); } //private static native void exec(String command, int[] process); - private static native void exec(String[] command, int[] process); + private static native void exec(String[] command, long[] process); - private static native int exitValue(int pid); + private static native int exitValue(long pid); - private static native int waitFor(int pid); + private static native int waitFor(long pid); private static native void load(String name, boolean mapName); @@ -68,13 +68,13 @@ public class Runtime { public native long totalMemory(); private static class MyProcess extends Process { - private int pid; + private long pid; private final int in; private final int out; private final int err; private int exitCode; - public MyProcess(int pid, int in, int out, int err) { + public MyProcess(long pid, int in, int out, int err) { this.pid = pid; this.in = in; this.out = out; diff --git a/test/RuntimeExec.java b/test/RuntimeExec.java index 86c03299c6..7aa53f3944 100644 --- a/test/RuntimeExec.java +++ b/test/RuntimeExec.java @@ -1,13 +1,40 @@ import java.lang.Runtime; +import java.lang.Process; public class RuntimeExec { - public static void main(String[] args) throws java.io.IOException { + public static void main(String[] args) throws java.io.IOException, java.lang.InterruptedException { + Runtime runtime = Runtime.getRuntime(); + System.out.println("Executing internet explorer"); - Runtime.getRuntime().exec("\"c:\\program files\\internet explorer\\iexplore.exe\" http://www.google.com"); + String ieStr = "\"c:\\program files\\internet explorer\\iexplore.exe\" http://www.google.com"; + Process ie = runtime.exec(ieStr); + System.out.println("Executing firefox"); String[] firefox = new String[2]; firefox[0] = "c:\\program files\\mozilla firefox\\firefox.exe"; firefox[1] = "http://www.google.com"; - Runtime.getRuntime().exec(firefox); + Process ff = runtime.exec(firefox); + + boolean ffSuccess = false; + boolean ieSuccess = false; + while(!(ieSuccess && ffSuccess)){ + if(!ffSuccess){ + try{ + System.out.println("Firefox exit value: " + ff.exitValue()); + ffSuccess = true; + } catch(IllegalThreadStateException e) {} + } + if(!ieSuccess){ + try{ + System.out.println("Internet Explorer exit value: " + ie.exitValue()); + ieSuccess = true; + } catch(IllegalThreadStateException e) {} + } + } + + System.out.println("Executing and waiting for charmap"); + String charmapStr = "c:\\windows\\system32\\charmap.exe"; + Process cm = runtime.exec(charmapStr); + System.out.println("Charmap exit value: " + cm.waitFor()); } }