|  |  | @@ -19,7 +19,7 @@ | 
		
	
		
			
			|  |  |  | // Place, Suite 330, Boston, MA 02111-1307 USA | 
		
	
		
			
			|  |  |  | //============================================================================== | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // See child.hpp for notes. | 
		
	
		
			
			|  |  |  | #include <iostream> // Temporary. | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | #include <stdexcept> | 
		
	
		
			
			|  |  |  |  | 
		
	
	
		
			
			|  |  | @@ -28,28 +28,190 @@ | 
		
	
		
			
			|  |  |  | namespace CodeDweller { | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | Child::Child(std::vector<std::string> args) { | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | init(); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | if (args.size() == 0) { | 
		
	
		
			
			|  |  |  | // | 
		
	
		
			
			|  |  |  | } else if (args.size() == 1) { | 
		
	
		
			
			|  |  |  | cmdline = args[0]; | 
		
	
		
			
			|  |  |  | return; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Append all but last command-line arguments. | 
		
	
		
			
			|  |  |  | for (size_t i = 0; i < args.size() - 1; i++) { | 
		
	
		
			
			|  |  |  | cmdline += args[i] + " "; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | cmdline += args.back(); // Append last command-line argument. | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | Child::Child(std::string childpath) { | 
		
	
		
			
			|  |  |  | Child::Child(std::string childpath) : | 
		
	
		
			
			|  |  |  | cmdline(childpath) { | 
		
	
		
			
			|  |  |  | init(); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | Child::~Child() { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | void | 
		
	
		
			
			|  |  |  | Child::init() { | 
		
	
		
			
			|  |  |  | exitCodeObtainedFlag = false; | 
		
	
		
			
			|  |  |  | exitCode = 0; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | std::istream * | 
		
	
		
			
			|  |  |  | Child::reader() { | 
		
	
		
			
			|  |  |  | return new std::istream(std::cin.rdbuf()); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | std::ostream * | 
		
	
		
			
			|  |  |  | Child::writer() { | 
		
	
		
			
			|  |  |  | return new std::ostream(std::cout.rdbuf()); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | void | 
		
	
		
			
			|  |  |  | Child::run() { | 
		
	
		
			
			|  |  |  | throw std::runtime_error("Not implemented"); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Set the bInheritHandle flag so pipe handles are inherited. | 
		
	
		
			
			|  |  |  | SECURITY_ATTRIBUTES securityAttributes; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); | 
		
	
		
			
			|  |  |  | securityAttributes.bInheritHandle = true; | 
		
	
		
			
			|  |  |  | securityAttributes.lpSecurityDescriptor = NULL; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Create a pipe for the child process's STDOUT. | 
		
	
		
			
			|  |  |  | HANDLE childStdOutAtChild; | 
		
	
		
			
			|  |  |  | HANDLE childStdInAtChild; | 
		
	
		
			
			|  |  |  | int bufferSize = 0; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | if (!CreatePipe(&childStdOutAtParent, | 
		
	
		
			
			|  |  |  | &childStdOutAtChild, | 
		
	
		
			
			|  |  |  | &securityAttributes, | 
		
	
		
			
			|  |  |  | bufferSize)) { | 
		
	
		
			
			|  |  |  | throw std::runtime_error("Error from CreatePipe for stdout:  " + | 
		
	
		
			
			|  |  |  | getErrorText()); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Ensure the read handle to the pipe for STDOUT is not inherited. | 
		
	
		
			
			|  |  |  | int inheritFlag = 0; | 
		
	
		
			
			|  |  |  | if (!SetHandleInformation(childStdOutAtParent, | 
		
	
		
			
			|  |  |  | HANDLE_FLAG_INHERIT, | 
		
	
		
			
			|  |  |  | inheritFlag) ) { | 
		
	
		
			
			|  |  |  | throw std::runtime_error("Error from GetHandleInformation for stdout:  " + | 
		
	
		
			
			|  |  |  | getErrorText()); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Create a pipe for the child process's STDIN. | 
		
	
		
			
			|  |  |  | if (! CreatePipe(&childStdInAtChild, | 
		
	
		
			
			|  |  |  | &childStdInAtParent, | 
		
	
		
			
			|  |  |  | &securityAttributes, | 
		
	
		
			
			|  |  |  | bufferSize)) { | 
		
	
		
			
			|  |  |  | throw std::runtime_error("Error from CreatePipe for stdin:  " + | 
		
	
		
			
			|  |  |  | getErrorText()); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Ensure the write handle to the pipe for STDIN is not inherited. | 
		
	
		
			
			|  |  |  | if (!SetHandleInformation(childStdInAtParent, | 
		
	
		
			
			|  |  |  | HANDLE_FLAG_INHERIT, | 
		
	
		
			
			|  |  |  | inheritFlag)) { | 
		
	
		
			
			|  |  |  | throw std::runtime_error("Error from GetHandleInformation for stdin:  " + | 
		
	
		
			
			|  |  |  | getErrorText()); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Set up members of the PROCESS_INFORMATION structure. | 
		
	
		
			
			|  |  |  | PROCESS_INFORMATION processInfo; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | std::fill((char *) &processInfo, | 
		
	
		
			
			|  |  |  | ((char *) &processInfo) + sizeof(PROCESS_INFORMATION), | 
		
	
		
			
			|  |  |  | 0); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Set up members of the STARTUPINFO structure.  This structure | 
		
	
		
			
			|  |  |  | // specifies the STDIN and STDOUT handles for redirection. | 
		
	
		
			
			|  |  |  | STARTUPINFO startInfo; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | std::fill((char *) &startInfo, | 
		
	
		
			
			|  |  |  | ((char *) &startInfo) + sizeof(STARTUPINFO), | 
		
	
		
			
			|  |  |  | 0); | 
		
	
		
			
			|  |  |  | startInfo.cb = sizeof(STARTUPINFO); | 
		
	
		
			
			|  |  |  | startInfo.hStdError = childStdOutAtChild; | 
		
	
		
			
			|  |  |  | startInfo.hStdOutput = childStdOutAtChild; | 
		
	
		
			
			|  |  |  | startInfo.hStdInput = childStdInAtChild; | 
		
	
		
			
			|  |  |  | startInfo.dwFlags |= STARTF_USESTDHANDLES; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Create the child process. | 
		
	
		
			
			|  |  |  | bool createSuccess; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | createSuccess = CreateProcess(NULL, | 
		
	
		
			
			|  |  |  | (char *) cmdline.c_str(), // command line | 
		
	
		
			
			|  |  |  | NULL,         	  // process security attributes | 
		
	
		
			
			|  |  |  | NULL,         	  // primary thread security attributes | 
		
	
		
			
			|  |  |  | true,         	  // handles are inherited | 
		
	
		
			
			|  |  |  | 0,            	  // creation flags | 
		
	
		
			
			|  |  |  | NULL,         	  // use parent's environment | 
		
	
		
			
			|  |  |  | NULL,         	  // use parent's current directory | 
		
	
		
			
			|  |  |  | &startInfo,   	  // STARTUPINFO pointer | 
		
	
		
			
			|  |  |  | &processInfo);	  // receives PROCESS_INFORMATION | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // If an error occurs, exit the application. | 
		
	
		
			
			|  |  |  | if (!createSuccess ) { | 
		
	
		
			
			|  |  |  | throw std::runtime_error("Error from CreateProcess with " | 
		
	
		
			
			|  |  |  | "command line \"" + cmdline + "\":  " + | 
		
	
		
			
			|  |  |  | getErrorText()); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Save the handles to the child process and its primary thread. | 
		
	
		
			
			|  |  |  | childProcess = processInfo.hProcess; | 
		
	
		
			
			|  |  |  | childThread = processInfo.hThread; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Close the child's end of the pipes. | 
		
	
		
			
			|  |  |  | CloseHandle(childStdOutAtChild); | 
		
	
		
			
			|  |  |  | CloseHandle(childStdInAtChild); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | void | 
		
	
		
			
			|  |  |  | Child::terminate() { | 
		
	
		
			
			|  |  |  | throw std::runtime_error("Not implemented"); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | if (!TerminateProcess(childProcess, terminateExitCode)) { | 
		
	
		
			
			|  |  |  | throw std::runtime_error("Error terminating the child process:  " + | 
		
	
		
			
			|  |  |  | getErrorText()); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | int32_t | 
		
	
		
			
			|  |  |  | Child::result() { | 
		
	
		
			
			|  |  |  | throw std::runtime_error("Not implemented"); | 
		
	
		
			
			|  |  |  | return 0; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | int result; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | if (!GetExitCodeProcess(childProcess, (LPDWORD) &result)) { | 
		
	
		
			
			|  |  |  | throw std::runtime_error("Error getting child process exit code:  " + | 
		
	
		
			
			|  |  |  | getErrorText()); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | return result; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | std::string | 
		
	
		
			
			|  |  |  | Child::getErrorText() { | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | LPVOID winMsgBuf; | 
		
	
		
			
			|  |  |  | DWORD lastError = GetLastError(); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | FormatMessage( | 
		
	
		
			
			|  |  |  | FORMAT_MESSAGE_ALLOCATE_BUFFER | | 
		
	
		
			
			|  |  |  | FORMAT_MESSAGE_FROM_SYSTEM | | 
		
	
		
			
			|  |  |  | FORMAT_MESSAGE_IGNORE_INSERTS, | 
		
	
		
			
			|  |  |  | NULL, | 
		
	
		
			
			|  |  |  | lastError, | 
		
	
		
			
			|  |  |  | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | 
		
	
		
			
			|  |  |  | (char *) &winMsgBuf, | 
		
	
		
			
			|  |  |  | 0, NULL ); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | std::string errMsg((char *) winMsgBuf); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | LocalFree(winMsgBuf); | 
		
	
		
			
			|  |  |  | return errMsg; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | } |