/*========================================================================= Program: KWSys - Kitware System Library Module: $RCSfile$ Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ /* On Windows9x platforms, this executable is spawned between a parent process and the child it is invoking to work around a bug. See the Win32 implementation file for details. */ #ifdef _MSC_VER #pragma warning (push, 1) #endif #include #include void ReportLastError(HANDLE errorPipe); int main() { /* Process startup information for the real child. */ STARTUPINFO si; PROCESS_INFORMATION pi; /* The result of waiting for the child to exit. */ DWORD waitResult; /* The child's process return code. */ DWORD retVal; /* The command line used to invoke this process. */ LPSTR commandLine = GetCommandLine(); /* Pointer that will be advanced to the beginning of the command line of the real child process. */ LPSTR cmdLine = commandLine; /* Handle to the error reporting pipe provided by the parent. This is parsed off the command line. */ HANDLE errorPipe = 0; HANDLE errorPipeOrig = 0; /* Handle to the event the parent uses to tell us to resume the child. This is parsed off the command line. */ HANDLE resumeEvent = 0; /* Handle to the event the parent uses to tell us to kill the child. This is parsed off the command line. */ HANDLE killEvent = 0; /* Flag for whether to hide window of child process. */ int hideWindow = 0; /* An array of the handles on which we wait when the child is running. */ HANDLE waitHandles[2] = {0, 0}; /* Move the pointer past the name of this executable. */ if(*cmdLine == '"') { ++cmdLine; while(*cmdLine && *cmdLine != '"') { ++cmdLine; } if(*cmdLine) { ++cmdLine; } } else { while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } } /* Parse the error pipe handle. */ while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } sscanf(cmdLine, "%p", &errorPipeOrig); /* Parse the resume event handle. */ while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } sscanf(cmdLine, "%p", &resumeEvent); /* Parse the kill event handle. */ while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } sscanf(cmdLine, "%p", &killEvent); /* Parse the hide window flag. */ while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } sscanf(cmdLine, "%d", &hideWindow); /* Skip to the beginning of the command line of the real child. */ while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } /* Create a non-inherited copy of the error pipe. We do not want the child to get it. */ if(DuplicateHandle(GetCurrentProcess(), errorPipeOrig, GetCurrentProcess(), &errorPipe, 0, FALSE, DUPLICATE_SAME_ACCESS)) { /* Have a non-inherited duplicate. Close the inherited one. */ CloseHandle(errorPipeOrig); } else { /* Could not duplicate handle. Report the error. */ ReportLastError(errorPipeOrig); return 1; } /* Create the subprocess. */ ZeroMemory(&si, sizeof(si)); ZeroMemory(&pi, sizeof(pi)); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; si.wShowWindow = hideWindow?SW_HIDE:SW_SHOWDEFAULT; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle(STD_ERROR_HANDLE); if(CreateProcess(0, cmdLine, 0, 0, TRUE, CREATE_SUSPENDED, 0, 0, &si, &pi)) { /* Process created successfully. Close the error reporting pipe to notify the parent of success. */ CloseHandle(errorPipe); } else { /* Error creating the process. Report the error to the parent process through the special error reporting pipe. */ ReportLastError(errorPipe); return 1; } /* Wait for resume or kill event from parent. */ waitHandles[0] = killEvent; waitHandles[1] = resumeEvent; waitResult = WaitForMultipleObjects(2, waitHandles, 0, INFINITE); /* Check what happened. */ if(waitResult == WAIT_OBJECT_0) { /* We were asked to kill the child. */ TerminateProcess(pi.hProcess, 255); WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return 1; } else { /* We were asked to resume the child. */ ResumeThread(pi.hThread); CloseHandle(pi.hThread); } /* Wait for subprocess to exit or for kill event from parent. */ waitHandles[0] = killEvent; waitHandles[1] = pi.hProcess; waitResult = WaitForMultipleObjects(2, waitHandles, 0, INFINITE); /* Check what happened. */ if(waitResult == WAIT_OBJECT_0) { /* We were asked to kill the child. */ TerminateProcess(pi.hProcess, 255); WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); return 1; } else { /* The child exited. Get the return code. */ GetExitCodeProcess(pi.hProcess, &retVal); CloseHandle(pi.hProcess); return retVal; } } void ReportLastError(HANDLE errorPipe) { LPVOID lpMsgBuf; DWORD n; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); WriteFile(errorPipe, lpMsgBuf, strlen(lpMsgBuf)+1, &n, 0); LocalFree( lpMsgBuf ); }