43 std::vector<std::wstring> env_entries;
44 for (
const auto &KV : env) {
47 env_entries.push_back(std::move(wentry));
49 std::sort(env_entries.begin(), env_entries.end(),
50 [](
const std::wstring &a,
const std::wstring &b) {
51 return _wcsicmp(a.c_str(), b.c_str()) < 0;
54 std::vector<wchar_t> buffer;
55 for (
const auto &env_entry : env_entries) {
56 buffer.insert(buffer.end(), env_entry.begin(), env_entry.end());
57 buffer.push_back(L
'\0');
61 buffer.push_back(L
'\0');
63 buffer.push_back(L
'\0');
94 SIZE_T attributelist_size = 0;
95 InitializeProcThreadAttributeList(
nullptr,
99 startupinfoex.lpAttributeList =
100 static_cast<LPPROC_THREAD_ATTRIBUTE_LIST
>(malloc(attributelist_size));
102 if (!startupinfoex.lpAttributeList)
103 return llvm::mapWindowsError(ERROR_OUTOFMEMORY);
105 if (!InitializeProcThreadAttributeList(startupinfoex.lpAttributeList,
107 0, &attributelist_size)) {
108 free(startupinfoex.lpAttributeList);
109 return llvm::mapWindowsError(GetLastError());
129 STARTUPINFOEXW startupinfoex = {};
130 startupinfoex.StartupInfo.cb =
sizeof(STARTUPINFOEXW);
131 startupinfoex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
134 ? launch_info.
GetPTY().GetMode()
140 llvm::scope_exit close_handles([&] {
142 ::CloseHandle(stdin_handle);
144 ::CloseHandle(stdout_handle);
146 ::CloseHandle(stderr_handle);
150 if (!attributelist_or_err) {
151 error = attributelist_or_err.getError();
156 std::vector<HANDLE> inherited_handles;
159 HPCON hPC = launch_info.
GetPTY().GetPseudoTerminalHandle();
172 if (!UpdateProcThreadAttribute(
173 startupinfoex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
174 inherited_handles.data(), inherited_handles.size() *
sizeof(
HANDLE),
182 auto inherited_handles_or_err =
184 stderr_handle, stdin_handle);
185 if (!inherited_handles_or_err) {
186 error =
Status(inherited_handles_or_err.getError());
189 inherited_handles = std::move(*inherited_handles_or_err);
194 const char *hide_console_var =
195 getenv(
"LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
196 if (hide_console_var &&
197 llvm::StringRef(hide_console_var).equals_insensitive(
"true")) {
198 startupinfoex.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
199 startupinfoex.StartupInfo.wShowWindow = SW_HIDE;
202 DWORD flags = CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT;
203 const bool stdio_redirected = launch_info.
IsFDRedirected(STDIN_FILENO) &&
206 if (stdio_redirected)
207 flags |= CREATE_NO_WINDOW;
208 else if (!launch_info.
GetFlags().
Test(eLaunchFlagDisableSTDIO) &&
210 flags |= CREATE_NEW_CONSOLE;
213 flags |= DEBUG_ONLY_THIS_PROCESS;
215 std::vector<wchar_t> environment =
218 auto wcommandLineOrErr =
220 if (!wcommandLineOrErr) {
224 std::wstring wcommandLine = *wcommandLineOrErr;
228 WCHAR *pwcommandLine = wcommandLine.empty() ? nullptr : &wcommandLine[0];
230 llvm::SmallVector<wchar_t, MAX_PATH> wexecutable;
231 if (std::error_code ec = llvm::sys::windows::widenPath(
236 std::wstring wworkingDirectory;
240 PROCESS_INFORMATION pi = {};
242 BOOL result = ::CreateProcessW(
243 wexecutable.data(), pwcommandLine,
nullptr,
nullptr,
244 !inherited_handles.empty() ||
246 flags, environment.data(),
247 wworkingDirectory.size() == 0 ?
nullptr : wworkingDirectory.c_str(),
248 reinterpret_cast<STARTUPINFOW *
>(&startupinfoex), &pi);
260 ::CloseHandle(pi.hThread);
262 launch_info.
GetPTY().CloseAnonymousPipes();
270 std::vector<HANDLE> inherited_handles;
272 startupinfoex.StartupInfo.hStdInput =
273 stdin_handle ? stdin_handle : GetStdHandle(STD_INPUT_HANDLE);
274 startupinfoex.StartupInfo.hStdOutput =
275 stdout_handle ? stdout_handle : GetStdHandle(STD_OUTPUT_HANDLE);
281 HANDLE effective_stderr = stderr_handle;
282 if (!effective_stderr && launch_info) {
287 effective_stderr = startupinfoex.StartupInfo.hStdOutput;
292 startupinfoex.StartupInfo.hStdError =
293 effective_stderr ? effective_stderr : GetStdHandle(STD_ERROR_HANDLE);
296 auto push_if_new = [&](
HANDLE h) {
297 if (h && std::find(inherited_handles.begin(), inherited_handles.end(), h) ==
298 inherited_handles.end())
299 inherited_handles.push_back(h);
301 push_if_new(startupinfoex.StartupInfo.hStdError);
302 push_if_new(startupinfoex.StartupInfo.hStdInput);
303 push_if_new(startupinfoex.StartupInfo.hStdOutput);
309 if (std::find(inherited_handles.begin(), inherited_handles.end(),
310 act->
GetHandle()) != inherited_handles.end())
316 inherited_handles.push_back(act->
GetHandle());
319 inherited_handles.push_back(act->
GetHandle());
323 if (inherited_handles.empty())
324 return inherited_handles;
326 if (!UpdateProcThreadAttribute(
327 startupinfoex.lpAttributeList, 0,
328 PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherited_handles.data(),
329 inherited_handles.size() *
sizeof(
HANDLE),
331 return llvm::mapWindowsError(::GetLastError());
333 return inherited_handles;
351 SECURITY_ATTRIBUTES secattr = {};
352 secattr.nLength =
sizeof(SECURITY_ATTRIBUTES);
353 secattr.bInheritHandle = TRUE;
356 DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
361 access = GENERIC_READ;
362 create = OPEN_EXISTING;
363 flags = FILE_ATTRIBUTE_READONLY;
366 flags = FILE_FLAG_WRITE_THROUGH;
369 access = GENERIC_WRITE;
370 create = CREATE_ALWAYS;
377 llvm::ConvertUTF8toWide(path, wpath);
378 HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create,
380 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...