42 std::vector<std::wstring> env_entries;
43 for (
const auto &KV : env) {
46 env_entries.push_back(std::move(wentry));
48 std::sort(env_entries.begin(), env_entries.end(),
49 [](
const std::wstring &a,
const std::wstring &b) {
50 return _wcsicmp(a.c_str(), b.c_str()) < 0;
53 std::vector<wchar_t> buffer;
54 for (
const auto &env_entry : env_entries) {
55 buffer.insert(buffer.end(), env_entry.begin(), env_entry.end());
56 buffer.push_back(L
'\0');
60 buffer.push_back(L
'\0');
62 buffer.push_back(L
'\0');
93 SIZE_T attributelist_size = 0;
94 InitializeProcThreadAttributeList(
nullptr,
98 startupinfoex.lpAttributeList =
99 static_cast<LPPROC_THREAD_ATTRIBUTE_LIST
>(malloc(attributelist_size));
101 if (!startupinfoex.lpAttributeList)
102 return llvm::mapWindowsError(ERROR_OUTOFMEMORY);
104 if (!InitializeProcThreadAttributeList(startupinfoex.lpAttributeList,
106 0, &attributelist_size)) {
107 free(startupinfoex.lpAttributeList);
108 return llvm::mapWindowsError(GetLastError());
128 STARTUPINFOEXW startupinfoex = {};
129 startupinfoex.StartupInfo.cb =
sizeof(STARTUPINFOEXW);
130 startupinfoex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
133 ? launch_info.
GetPTY().GetMode()
139 llvm::scope_exit close_handles([&] {
141 ::CloseHandle(stdin_handle);
143 ::CloseHandle(stdout_handle);
145 ::CloseHandle(stderr_handle);
149 if (!attributelist_or_err) {
150 error = attributelist_or_err.getError();
155 std::vector<HANDLE> inherited_handles;
158 HPCON hPC = launch_info.
GetPTY().GetPseudoTerminalHandle();
171 if (!UpdateProcThreadAttribute(
172 startupinfoex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
173 inherited_handles.data(), inherited_handles.size() *
sizeof(
HANDLE),
181 auto inherited_handles_or_err =
183 stderr_handle, stdin_handle);
184 if (!inherited_handles_or_err) {
185 error =
Status(inherited_handles_or_err.getError());
188 inherited_handles = std::move(*inherited_handles_or_err);
193 const char *hide_console_var =
194 getenv(
"LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
195 if (hide_console_var &&
196 llvm::StringRef(hide_console_var).equals_insensitive(
"true")) {
197 startupinfoex.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
198 startupinfoex.StartupInfo.wShowWindow = SW_HIDE;
201 DWORD flags = CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT;
202 const bool stdio_redirected = launch_info.
IsFDRedirected(STDIN_FILENO) &&
205 if (stdio_redirected)
206 flags |= CREATE_NO_WINDOW;
207 else if (!launch_info.
GetFlags().
Test(eLaunchFlagDisableSTDIO) &&
209 flags |= CREATE_NEW_CONSOLE;
212 flags |= DEBUG_ONLY_THIS_PROCESS;
214 std::vector<wchar_t> environment =
217 auto wcommandLineOrErr =
219 if (!wcommandLineOrErr) {
223 std::wstring wcommandLine = *wcommandLineOrErr;
227 WCHAR *pwcommandLine = wcommandLine.empty() ? nullptr : &wcommandLine[0];
229 std::wstring wexecutable, wworkingDirectory;
235 PROCESS_INFORMATION pi = {};
237 BOOL result = ::CreateProcessW(
238 wexecutable.c_str(), pwcommandLine,
nullptr,
nullptr,
239 !inherited_handles.empty() ||
241 flags, environment.data(),
242 wworkingDirectory.size() == 0 ?
nullptr : wworkingDirectory.c_str(),
243 reinterpret_cast<STARTUPINFOW *
>(&startupinfoex), &pi);
255 ::CloseHandle(pi.hThread);
257 launch_info.
GetPTY().CloseAnonymousPipes();
265 std::vector<HANDLE> inherited_handles;
267 startupinfoex.StartupInfo.hStdInput =
268 stdin_handle ? stdin_handle : GetStdHandle(STD_INPUT_HANDLE);
269 startupinfoex.StartupInfo.hStdOutput =
270 stdout_handle ? stdout_handle : GetStdHandle(STD_OUTPUT_HANDLE);
276 HANDLE effective_stderr = stderr_handle;
277 if (!effective_stderr && launch_info) {
282 effective_stderr = startupinfoex.StartupInfo.hStdOutput;
287 startupinfoex.StartupInfo.hStdError =
288 effective_stderr ? effective_stderr : GetStdHandle(STD_ERROR_HANDLE);
291 auto push_if_new = [&](
HANDLE h) {
292 if (h && std::find(inherited_handles.begin(), inherited_handles.end(), h) ==
293 inherited_handles.end())
294 inherited_handles.push_back(h);
296 push_if_new(startupinfoex.StartupInfo.hStdError);
297 push_if_new(startupinfoex.StartupInfo.hStdInput);
298 push_if_new(startupinfoex.StartupInfo.hStdOutput);
304 if (std::find(inherited_handles.begin(), inherited_handles.end(),
305 act->
GetHandle()) != inherited_handles.end())
311 inherited_handles.push_back(act->
GetHandle());
314 inherited_handles.push_back(act->
GetHandle());
318 if (inherited_handles.empty())
319 return inherited_handles;
321 if (!UpdateProcThreadAttribute(
322 startupinfoex.lpAttributeList, 0,
323 PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherited_handles.data(),
324 inherited_handles.size() *
sizeof(
HANDLE),
326 return llvm::mapWindowsError(::GetLastError());
328 return inherited_handles;
346 SECURITY_ATTRIBUTES secattr = {};
347 secattr.nLength =
sizeof(SECURITY_ATTRIBUTES);
348 secattr.bInheritHandle = TRUE;
351 DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
356 access = GENERIC_READ;
357 create = OPEN_EXISTING;
358 flags = FILE_ATTRIBUTE_READONLY;
361 flags = FILE_FLAG_WRITE_THROUGH;
364 access = GENERIC_WRITE;
365 create = CREATE_ALWAYS;
372 llvm::ConvertUTF8toWide(path, wpath);
373 HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create,
375 return (result == INVALID_HANDLE_VALUE) ? nullptr : result;
static llvm::ErrorOr< std::vector< HANDLE > > GetInheritedHandles(STARTUPINFOEXW &startupinfoex, const ProcessLaunchInfo *launch_info=nullptr, HANDLE stdout_handle=nullptr, HANDLE stderr_handle=nullptr, HANDLE stdin_handle=nullptr)
Get the list of Windows handles that should be inherited by the child process and update STARTUPINFOE...