75 return llvm::make_error<llvm::StringError>(
"ConPTY is not available",
76 llvm::errc::io_error);
79 "ConPTY has already been opened");
82 HANDLE hInputRead = INVALID_HANDLE_VALUE;
83 HANDLE hInputWrite = INVALID_HANDLE_VALUE;
84 HANDLE hOutputRead = INVALID_HANDLE_VALUE;
85 HANDLE hOutputWrite = INVALID_HANDLE_VALUE;
87 wchar_t pipe_name[MAX_PATH];
88 swprintf(pipe_name, MAX_PATH, L
"\\\\.\\pipe\\conpty-lldb-%d-%p",
89 GetCurrentProcessId(),
this);
94 CreateNamedPipeW(pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
95 PIPE_TYPE_BYTE | PIPE_WAIT, 1, 4096, 4096, 0, NULL);
96 hOutputWrite = CreateFileW(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
97 FILE_ATTRIBUTE_NORMAL, NULL);
99 if (!CreatePipe(&hInputRead, &hInputWrite, NULL, 0))
100 return llvm::errorCodeToError(
101 std::error_code(GetLastError(), std::system_category()));
103 COORD consoleSize{80, 25};
104 CONSOLE_SCREEN_BUFFER_INFO csbi;
105 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
107 static_cast<SHORT
>(csbi.srWindow.Right - csbi.srWindow.Left + 1),
108 static_cast<SHORT
>(csbi.srWindow.Bottom - csbi.srWindow.Top + 1)};
109 HPCON hPC = INVALID_HANDLE_VALUE;
110 hr =
kernel32.CreatePseudoConsole(consoleSize, hInputRead, hOutputWrite, 0,
112 CloseHandle(hInputRead);
113 CloseHandle(hOutputWrite);
116 CloseHandle(hInputWrite);
117 CloseHandle(hOutputRead);
118 return llvm::make_error<llvm::StringError>(
119 "Failed to create Windows ConPTY pseudo terminal",
120 llvm::errc::io_error);
123 DWORD mode = PIPE_NOWAIT;
124 SetNamedPipeHandleState(hOutputRead, &mode, NULL, NULL);
133 "failed to finalize ConPTY's setup: {0}");
136 return llvm::Error::success();
166 STARTUPINFOEXW startupinfoex = {};
167 startupinfoex.StartupInfo.cb =
sizeof(STARTUPINFOEXW);
168 startupinfoex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
171 if (!attributelist_or_err)
172 return llvm::errorCodeToError(attributelist_or_err.getError());
177 PROCESS_INFORMATION pi = {};
179 wchar_t comspec[MAX_PATH];
180 DWORD comspecLen = GetEnvironmentVariableW(L
"COMSPEC", comspec, MAX_PATH);
181 if (comspecLen == 0 || comspecLen >= MAX_PATH)
182 return llvm::createStringError(
183 std::error_code(GetLastError(), std::system_category()),
184 "Failed to get the 'COMSPEC' environment variable");
186 std::wstring cmdline_str = std::wstring(comspec) + L
" /c 'echo foo && exit'";
187 std::vector<wchar_t> cmdline(cmdline_str.begin(), cmdline_str.end());
188 cmdline.push_back(L
'\0');
190 if (!CreateProcessW(comspec, cmdline.data(),
193 EXTENDED_STARTUPINFO_PRESENT |
194 CREATE_UNICODE_ENVIRONMENT,
197 reinterpret_cast<STARTUPINFOW *
>(&startupinfoex),
199 return llvm::errorCodeToError(
200 std::error_code(GetLastError(), std::system_category()));
204 ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
209 WaitForSingleObject(pi.hProcess, INFINITE);
211 if (GetOverlappedResult(
m_conpty_output, &ov, &read, FALSE) && read > 0) {
212 ResetEvent(ov.hEvent);
217 CloseHandle(ov.hEvent);
218 CloseHandle(pi.hProcess);
219 CloseHandle(pi.hThread);
221 return llvm::Error::success();