1 //===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Host/windows/ProcessLauncherWindows.h"
11 #include "lldb/Host/HostProcess.h"
12 #include "lldb/Target/ProcessLaunchInfo.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/Support/ConvertUTF.h"
21 using namespace lldb_private;
24 void CreateEnvironmentBuffer(const Environment &env,
25 std::vector<char> &buffer) {
29 // Environment buffer is a null terminated list of null terminated strings
30 for (const auto &KV : env) {
32 if (llvm::ConvertUTF8toWide(Environment::compose(KV), warg)) {
33 buffer.insert(buffer.end(), (char *)warg.c_str(),
34 (char *)(warg.c_str() + warg.size() + 1));
37 // One null wchar_t (to end the block) is two null bytes
44 ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
48 std::string executable;
49 std::string commandLine;
50 std::vector<char> environment;
51 STARTUPINFO startupinfo = {};
52 PROCESS_INFORMATION pi = {};
54 HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO);
55 HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO);
56 HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO);
58 startupinfo.cb = sizeof(startupinfo);
59 startupinfo.dwFlags |= STARTF_USESTDHANDLES;
60 startupinfo.hStdError =
61 stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE);
62 startupinfo.hStdInput =
63 stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE);
64 startupinfo.hStdOutput =
65 stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE);
67 const char *hide_console_var =
68 getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
69 if (hide_console_var &&
70 llvm::StringRef(hide_console_var).equals_lower("true")) {
71 startupinfo.dwFlags |= STARTF_USESHOWWINDOW;
72 startupinfo.wShowWindow = SW_HIDE;
75 DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
76 if (launch_info.GetFlags().Test(eLaunchFlagDebug))
77 flags |= DEBUG_ONLY_THIS_PROCESS;
79 LPVOID env_block = nullptr;
80 ::CreateEnvironmentBuffer(launch_info.GetEnvironment(), environment);
81 if (!environment.empty())
82 env_block = environment.data();
84 executable = launch_info.GetExecutableFile().GetPath();
85 launch_info.GetArguments().GetQuotedCommandString(commandLine);
87 std::wstring wexecutable, wcommandLine, wworkingDirectory;
88 llvm::ConvertUTF8toWide(executable, wexecutable);
89 llvm::ConvertUTF8toWide(commandLine, wcommandLine);
90 llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(),
93 wcommandLine.resize(PATH_MAX); // Needs to be over-allocated because
94 // CreateProcessW can modify it
95 BOOL result = ::CreateProcessW(
96 wexecutable.c_str(), &wcommandLine[0], NULL, NULL, TRUE, flags, env_block,
97 wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(),
101 // Call GetLastError before we make any other system calls.
102 error.SetError(::GetLastError(), eErrorTypeWin32);
106 // Do not call CloseHandle on pi.hProcess, since we want to pass that back
107 // through the HostProcess.
108 ::CloseHandle(pi.hThread);
112 ::CloseHandle(stdin_handle);
114 ::CloseHandle(stdout_handle);
116 ::CloseHandle(stderr_handle);
119 return HostProcess();
121 return HostProcess(pi.hProcess);
125 ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info,
127 const FileAction *action = launch_info.GetFileActionForFD(fd);
128 if (action == nullptr)
130 SECURITY_ATTRIBUTES secattr = {};
131 secattr.nLength = sizeof(SECURITY_ATTRIBUTES);
132 secattr.bInheritHandle = TRUE;
134 llvm::StringRef path = action->GetPath();
136 DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
139 if (fd == STDIN_FILENO) {
140 access = GENERIC_READ;
141 create = OPEN_EXISTING;
142 flags = FILE_ATTRIBUTE_READONLY;
144 if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
145 access = GENERIC_WRITE;
146 create = CREATE_ALWAYS;
147 if (fd == STDERR_FILENO)
148 flags = FILE_FLAG_WRITE_THROUGH;
152 llvm::ConvertUTF8toWide(path, wpath);
153 HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create,
155 return (result == INVALID_HANDLE_VALUE) ? NULL : result;