// natWin32Process.cc - Native side of Win32 process code. /* Copyright (C) 2003 Free Software Foundation This file is part of libgcj. This software is copyrighted work licensed under the terms of the Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ #include #include #define WIN32_LEAN_AND_MEAN #include // Conflicts with the definition in "java/lang/reflect/Modifier.h" #undef STRICT #include #include #include #include #include #include #include #include #include #include #include #include #include void java::lang::ConcreteProcess::cleanup (void) { if (inputStream != NULL) { inputStream->close (); inputStream = NULL; } if (outputStream != NULL) { outputStream->close (); outputStream = NULL; } if (errorStream != NULL) { errorStream->close (); errorStream = NULL; } } void java::lang::ConcreteProcess::destroy (void) { if (! hasExited ()) { // Kill it forcibly and assign an (arbitrary) exit code of 0. TerminateProcess ((HANDLE) procHandle, 0); exitCode = 0; cleanup (); } } jboolean java::lang::ConcreteProcess::hasExited (void) { DWORD exitStatus; if (GetExitCodeProcess ((HANDLE) procHandle, &exitStatus) != 0) { // NOTE: STILL_ACTIVE is defined as "259" by Win32 - if the // child actually exits with this return code, we have a // problem here. See MSDN documentation on GetExitCodeProcess( ). if (exitStatus == STILL_ACTIVE) return false; else { cleanup (); exitCode = exitStatus; return true; } } else return true; } jint java::lang::ConcreteProcess::waitFor (void) { if (! hasExited ()) { DWORD exitStatus = 0UL; // FIXME: The wait should be interruptible. WaitForSingleObject ((HANDLE) procHandle, INFINITE); GetExitCodeProcess ((HANDLE) procHandle, &exitStatus); exitCode = exitStatus; cleanup (); } return exitCode; } static char * new_string (jstring string) { jsize s = _Jv_GetStringUTFLength (string); char *buf = (char *) _Jv_Malloc (s + 1); _Jv_GetStringUTFRegion (string, 0, s, buf); buf[s] = '\0'; return buf; } void java::lang::ConcreteProcess::startProcess (jstringArray progarray, jstringArray envp, java::io::File *dir) { using namespace java::io; procHandle = (jint) INVALID_HANDLE_VALUE; // Reconstruct the command line. jstring *elts = elements (progarray); int cmdLineLen = 0; for (int i = 0; i < progarray->length; ++i) cmdLineLen += (_Jv_GetStringUTFLength (elts[i]) + 3); char *cmdLine = (char *) _Jv_Malloc (cmdLineLen + 1); char *cmdLineCurPos = cmdLine; for (int i = 0; i < progarray->length; ++i) { if (i > 0) *cmdLineCurPos++ = ' '; *cmdLineCurPos++ = '\"'; jsize s = _Jv_GetStringUTFLength (elts[i]); _Jv_GetStringUTFRegion (elts[i], 0, s, cmdLineCurPos); cmdLineCurPos += s; *cmdLineCurPos++ = '\"'; } *cmdLineCurPos = '\0'; // Get the environment, if any. char *env = NULL; if (envp) { elts = elements (envp); int envLen = 0; for (int i = 0; i < envp->length; ++i) envLen += (_Jv_GetStringUTFLength (elts[i]) + 1); env = (char *) _Jv_Malloc (envLen + 1); int j = 0; for (int i = 0; i < envp->length; ++i) { jsize s = _Jv_GetStringUTFLength (elts[i]); _Jv_GetStringUTFRegion (elts[i], 0, s, (env + j)); j += s; *(env + j) = '\0'; j++; } *(env + j) = '\0'; } // Get the working directory path, if specified. char *wdir = NULL; if (dir != NULL) wdir = new_string (dir->getPath ()); errorStream = NULL; inputStream = NULL; outputStream = NULL; java::lang::Throwable *exc = NULL; try { // We create anonymous pipes to communicate with the child // on each of standard streams. HANDLE cldStdInRd, cldStdInWr; HANDLE cldStdOutRd, cldStdOutWr; HANDLE cldStdErrRd, cldStdErrWr; SECURITY_ATTRIBUTES sAttrs; // Explicitly allow the handles to the pipes to be inherited. sAttrs.nLength = sizeof (SECURITY_ATTRIBUTES); sAttrs.bInheritHandle = 1; sAttrs.lpSecurityDescriptor = NULL; char tmpBuff[64]; if (CreatePipe (&cldStdInRd, &cldStdInWr, &sAttrs, 0) == 0) { sprintf (tmpBuff, "Error creating stdin pipe (Win32 Error Code: %lu)", GetLastError ()); throw new IOException (JvNewStringLatin1 (tmpBuff)); } if (CreatePipe (&cldStdOutRd, &cldStdOutWr, &sAttrs, 0) == 0) { sprintf (tmpBuff, "Error creating stdout pipe (Win32 Error Code: %lu)", GetLastError ()); throw new IOException (JvNewStringLatin1 (tmpBuff)); } if (CreatePipe (&cldStdErrRd, &cldStdErrWr, &sAttrs, 0) == 0) { sprintf (tmpBuff, "Error creating stderr pipe (Win32 Error Code: %lu)", GetLastError ()); throw new IOException (JvNewStringLatin1 (tmpBuff)); } outputStream = new FileOutputStream (new FileDescriptor ((jint) cldStdInWr)); inputStream = new FileInputStream (new FileDescriptor ((jint) cldStdOutRd)); errorStream = new FileInputStream (new FileDescriptor ((jint) cldStdErrRd)); // Now create the child process. PROCESS_INFORMATION pi; STARTUPINFO si; ZeroMemory (&pi, sizeof (PROCESS_INFORMATION)); ZeroMemory (&si, sizeof (STARTUPINFO)); si.cb = sizeof (STARTUPINFO); // Explicitly specify the handles to the standard streams. si.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = cldStdInRd; si.hStdOutput = cldStdOutWr; si.hStdError = cldStdErrWr; if (CreateProcess (NULL, cmdLine, NULL, NULL, 1, 0, env, wdir, &si, &pi) == 0) { sprintf (tmpBuff, "Error creating child process (Win32 Error Code: %lu)", GetLastError ()); throw new IOException (JvNewStringLatin1 (tmpBuff)); } procHandle = (jint ) pi.hProcess; // Close the wrong ends (for the parent) of the pipes. CloseHandle (cldStdInRd); CloseHandle (cldStdOutWr); CloseHandle (cldStdErrWr); _Jv_Free (cmdLine); if (env != NULL) _Jv_Free (env); if (wdir != NULL) _Jv_Free (wdir); } catch (java::lang::Throwable *thrown) { cleanup (); exc = thrown; } if (exc != NULL) throw exc; }