41 std::vector<std::wstring> env_entries;
42 for (
const auto &KV : env) {
45 env_entries.push_back(std::move(wentry));
47 std::sort(env_entries.begin(), env_entries.end(),
48 [](
const std::wstring &a,
const std::wstring &b) {
49 return _wcsicmp(a.c_str(), b.c_str()) < 0;
52 std::vector<wchar_t> buffer;
53 for (
const auto &env_entry : env_entries) {
54 buffer.insert(buffer.end(), env_entry.begin(), env_entry.end());
55 buffer.push_back(L
'\0');
59 buffer.push_back(L
'\0');
61 buffer.push_back(L
'\0');
89 STARTUPINFOEXW startupinfoex = {};
90 startupinfoex.StartupInfo.cb =
sizeof(startupinfoex);
91 startupinfoex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
96 auto close_handles = llvm::make_scope_exit([&] {
98 ::CloseHandle(stdin_handle);
100 ::CloseHandle(stdout_handle);
102 ::CloseHandle(stderr_handle);
105 SIZE_T attributelist_size = 0;
106 InitializeProcThreadAttributeList(
nullptr,
108 &attributelist_size);
110 startupinfoex.lpAttributeList =
111 static_cast<LPPROC_THREAD_ATTRIBUTE_LIST
>(malloc(attributelist_size));
112 auto free_attributelist =
113 llvm::make_scope_exit([&] { free(startupinfoex.lpAttributeList); });
114 if (!InitializeProcThreadAttributeList(startupinfoex.lpAttributeList,
116 &attributelist_size)) {
120 auto delete_attributelist = llvm::make_scope_exit(
121 [&] { DeleteProcThreadAttributeList(startupinfoex.lpAttributeList); });
124 launch_info, startupinfoex, stdout_handle, stderr_handle, stdin_handle);
125 if (!inherited_handles_or_err) {
126 error =
Status(inherited_handles_or_err.getError());
129 std::vector<HANDLE> inherited_handles = *inherited_handles_or_err;
131 const char *hide_console_var =
132 getenv(
"LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
133 if (hide_console_var &&
134 llvm::StringRef(hide_console_var).equals_insensitive(
"true")) {
135 startupinfoex.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
136 startupinfoex.StartupInfo.wShowWindow = SW_HIDE;
139 DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT |
140 EXTENDED_STARTUPINFO_PRESENT;
142 flags |= DEBUG_ONLY_THIS_PROCESS;
144 if (launch_info.
GetFlags().
Test(eLaunchFlagDisableSTDIO))
145 flags &= ~CREATE_NEW_CONSOLE;
147 std::vector<wchar_t> environment =
150 auto wcommandLineOrErr =
152 if (!wcommandLineOrErr) {
156 std::wstring wcommandLine = *wcommandLineOrErr;
160 WCHAR *pwcommandLine = wcommandLine.empty() ? nullptr : &wcommandLine[0];
162 std::wstring wexecutable, wworkingDirectory;
168 PROCESS_INFORMATION pi = {};
170 BOOL result = ::CreateProcessW(
171 wexecutable.c_str(), pwcommandLine, NULL, NULL,
172 !inherited_handles.empty(), flags, environment.data(),
173 wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(),
174 reinterpret_cast<STARTUPINFOW *
>(&startupinfoex), &pi);
186 ::CloseHandle(pi.hThread);
197 HANDLE stdout_handle, HANDLE stderr_handle, HANDLE stdin_handle) {
198 std::vector<HANDLE> inherited_handles;
200 startupinfoex.StartupInfo.hStdError =
201 stderr_handle ? stderr_handle : GetStdHandle(STD_ERROR_HANDLE);
202 startupinfoex.StartupInfo.hStdInput =
203 stdin_handle ? stdin_handle : GetStdHandle(STD_INPUT_HANDLE);
204 startupinfoex.StartupInfo.hStdOutput =
205 stdout_handle ? stdout_handle : GetStdHandle(STD_OUTPUT_HANDLE);
207 if (startupinfoex.StartupInfo.hStdError)
208 inherited_handles.push_back(startupinfoex.StartupInfo.hStdError);
209 if (startupinfoex.StartupInfo.hStdInput)
210 inherited_handles.push_back(startupinfoex.StartupInfo.hStdInput);
211 if (startupinfoex.StartupInfo.hStdOutput)
212 inherited_handles.push_back(startupinfoex.StartupInfo.hStdOutput);
218 inherited_handles.push_back(
reinterpret_cast<HANDLE
>(act->
GetFD()));
221 if (inherited_handles.empty())
222 return inherited_handles;
224 if (!UpdateProcThreadAttribute(
225 startupinfoex.lpAttributeList, 0,
226 PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherited_handles.data(),
227 inherited_handles.size() *
sizeof(HANDLE),
229 return llvm::mapWindowsError(::GetLastError());
231 return inherited_handles;
238 if (action ==
nullptr)
240 SECURITY_ATTRIBUTES secattr = {};
241 secattr.nLength =
sizeof(SECURITY_ATTRIBUTES);
242 secattr.bInheritHandle = TRUE;
245 DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
248 if (fd == STDIN_FILENO) {
249 access = GENERIC_READ;
250 create = OPEN_EXISTING;
251 flags = FILE_ATTRIBUTE_READONLY;
253 if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
254 access = GENERIC_WRITE;
255 create = CREATE_ALWAYS;
256 if (fd == STDERR_FILENO)
257 flags = FILE_FLAG_WRITE_THROUGH;
262 llvm::ConvertUTF8toWide(path, wpath);
263 HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create,
265 return (result == INVALID_HANDLE_VALUE) ? NULL : result;
llvm::ErrorOr< std::vector< HANDLE > > GetInheritedHandles(const ProcessLaunchInfo &launch_info, STARTUPINFOEXW &startupinfoex, HANDLE stdout_handle=NULL, HANDLE stderr_handle=NULL, HANDLE stdin_handle=NULL)
Get the list of Windows handles that should be inherited by the child process and update STARTUPINFOE...