in util/process_wrapper/system_windows.cc [197:295]
int System::Exec(const System::StrType& executable,
const System::Arguments& arguments,
const System::EnvironmentBlock& environment_block,
const StrType& stdout_file, const StrType& stderr_file) {
STARTUPINFO startup_info;
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(STARTUPINFO);
OutputPipe stdout_pipe;
OutputPipe stderr_pipe;
if (!stdout_file.empty() || !stderr_file.empty()) {
// We will be setting our own stdout/stderr handles. Note that when setting `STARTF_USESTDHANDLES`
// it is critical to set *all* handles or the child process might get a null handle (or garbage).
startup_info.dwFlags |= STARTF_USESTDHANDLES;
startup_info.hStdInput = INVALID_HANDLE_VALUE;
SECURITY_ATTRIBUTES saAttr;
ZeroMemory(&saAttr, sizeof(SECURITY_ATTRIBUTES));
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!stdout_file.empty()) {
if (!stdout_pipe.CreateEnds(saAttr)) {
std::cerr << "process wrapper error: failed to create stdout pipe: "
<< GetLastErrorAsStr();
return -1;
}
startup_info.hStdOutput = stdout_pipe.WriteEndHandle();
} else {
startup_info.hStdOutput = INVALID_HANDLE_VALUE;
}
if (!stderr_file.empty()) {
if (!stderr_pipe.CreateEnds(saAttr)) {
std::cerr << "process wrapper error: failed to create stderr pipe: "
<< GetLastErrorAsStr();
return -1;
}
startup_info.hStdError = stderr_pipe.WriteEndHandle();
} else {
startup_info.hStdError = INVALID_HANDLE_VALUE;
}
}
System::StrType command_line;
ArgumentQuote(executable, command_line);
MakeCommandLine(arguments, command_line);
System::StrType environment_block_win;
MakeEnvironmentBlock(environment_block, environment_block_win);
PROCESS_INFORMATION process_info;
ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
BOOL success = ::CreateProcess(
/*lpApplicationName*/ nullptr,
/*lpCommandLine*/ command_line.empty() ? nullptr : &command_line[0],
/*lpProcessAttributes*/ nullptr,
/*lpThreadAttributes*/ nullptr,
/*bInheritHandles*/ TRUE,
/*dwCreationFlags*/ 0
#if defined(UNICODE)
| CREATE_UNICODE_ENVIRONMENT
#endif // defined(UNICODE)
,
/*lpEnvironment*/ environment_block_win.empty()
? nullptr
: &environment_block_win[0],
/*lpCurrentDirectory*/ nullptr,
/*lpStartupInfo*/ &startup_info,
/*lpProcessInformation*/ &process_info);
if (success == FALSE) {
std::cerr << "process wrapper error: failed to launch a new process: "
<< GetLastErrorAsStr();
return -1;
}
if (!stdout_file.empty()) {
if (!stdout_pipe.WriteToFile(stdout_file)) {
return -1;
}
}
if (!stderr_file.empty()) {
if (!stderr_pipe.WriteToFile(stderr_file)) {
return -1;
}
}
DWORD exit_status;
WaitForSingleObject(process_info.hProcess, INFINITE);
if (GetExitCodeProcess(process_info.hProcess, &exit_status) == FALSE)
exit_status = -1;
CloseHandle(process_info.hThread);
CloseHandle(process_info.hProcess);
return exit_status;
}