|
|
@@ -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;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|