@@ -71,30 +71,6 @@ thread_local ClosePseudoConsole_T ClosePseudoConsoleFunc = nullptr;
7171
7272using HPCON = HANDLE;
7373
74- /* *
75- * @class ConsoleAttacher
76- * @date 11/03/10
77- * @brief a helper class to attach this process to a process' console
78- * this allows us to write directly into that process console-input-buffer
79- * One should check isAttached once this object is constructed
80- */
81- class ConsoleAttacher
82- {
83- public:
84- bool isAttached;
85-
86- public:
87- ConsoleAttacher (long pid) { isAttached = AttachConsole (pid); }
88-
89- ~ConsoleAttacher ()
90- {
91- if (isAttached) {
92- FreeConsole ();
93- }
94- isAttached = false ;
95- }
96- };
97-
9874static bool CheckIsAlive (HANDLE hProcess)
9975{
10076 DWORD dwExitCode;
@@ -284,117 +260,10 @@ IProcess* WinProcessImpl::Execute(wxEvtHandler* parent,
284260 return Execute (parent, cmd, flags, workingDirectory, cb);
285261}
286262
287- IProcess*
288- WinProcessImpl::ExecuteConPTY (wxEvtHandler* parent, const wxString& cmd, size_t flags, const wxString& workingDir)
289- {
290- // - Close these after CreateProcess of child application with pseudoconsole object.
291- HANDLE inputReadSide, outputWriteSide;
292-
293- // - Hold onto these and use them for communication with the child through the pseudoconsole.
294- HANDLE outputReadSide, inputWriteSide;
295- HPCON hPC = 0 ;
296-
297- // Create the in/out pipes:
298- if (!CreatePipe (&inputReadSide, &inputWriteSide, NULL , 0 )) {
299- return nullptr ;
300- }
301- if (!CreatePipe (&outputReadSide, &outputWriteSide, NULL , 0 )) {
302- ::CloseHandle (inputReadSide);
303- ::CloseHandle (inputWriteSide);
304- return nullptr ;
305- }
306-
307- #if !defined(_MSC_VER)
308- // Create the Pseudo Console, using the pipes
309- if (loadOnce) {
310- loadOnce = false ;
311- auto hDLL = ::LoadLibrary (L" Kernel32.dll" );
312- if (hDLL) {
313- CreatePseudoConsoleFunc = (CreatePseudoConsole_T)::GetProcAddress (hDLL, " CreatePseudoConsole" );
314- ClosePseudoConsoleFunc = (ClosePseudoConsole_T)::GetProcAddress (hDLL, " ClosePseudoConsole" );
315- FreeLibrary (hDLL);
316- }
317- }
318- #endif
319-
320- if (!CreatePseudoConsoleFunc || !ClosePseudoConsoleFunc) {
321- ::CloseHandle (inputReadSide);
322- ::CloseHandle (outputWriteSide);
323- ::CloseHandle (inputWriteSide);
324- ::CloseHandle (outputReadSide);
325- return nullptr ;
326- }
327- auto hr = CreatePseudoConsoleFunc ({1000 , 32 }, inputReadSide, outputWriteSide, 0 , &hPC);
328- if (FAILED (hr)) {
329- ::CloseHandle (inputReadSide);
330- ::CloseHandle (outputWriteSide);
331- ::CloseHandle (inputWriteSide);
332- ::CloseHandle (outputReadSide);
333- return nullptr ;
334- }
335-
336- // Prepare the StartupInfoEx structure attached to the ConPTY.
337- STARTUPINFOEX siEx{};
338- PrepareStartupInformation (hPC, &siEx);
339-
340- WinProcessImpl* prc = new WinProcessImpl (parent);
341- ::ZeroMemory (&prc->piProcInfo, sizeof (prc->piProcInfo));
342-
343- auto fSuccess = CreateProcess (nullptr ,
344- (wchar_t *)cmd.wc_str (),
345- nullptr ,
346- nullptr ,
347- FALSE ,
348- EXTENDED_STARTUPINFO_PRESENT,
349- nullptr ,
350- nullptr ,
351- &siEx.StartupInfo ,
352- &prc->piProcInfo );
353-
354- if (!fSuccess ) {
355- clERROR () << " Failed to launch process:" << cmd << " ." << GetLastError () << endl;
356- wxDELETE (prc);
357- return nullptr ;
358- }
359- ::CloseHandle (inputReadSide);
360- ::CloseHandle (outputWriteSide);
361-
362- if (!(prc->m_flags & IProcessCreateSync)) {
363- prc->StartReaderThread ();
364- }
365- prc->m_writerThread = new WinWriterThread (prc->piProcInfo .hProcess , inputWriteSide);
366- prc->m_writerThread ->Start ();
367-
368- prc->m_callback = nullptr ;
369- prc->m_flags = flags;
370- prc->m_pid = prc->piProcInfo .dwProcessId ;
371- prc->hChildStdoutRdDup = outputReadSide;
372- prc->m_hPseudoConsole = hPC;
373- return prc;
374- }
375-
376- IProcess* WinProcessImpl::ExecuteConPTY (wxEvtHandler* parent,
377- const std::vector<wxString>& args,
378- size_t flags,
379- const wxString& workingDir)
380- {
381- wxArrayString wxarr;
382- wxarr.reserve (args.size ());
383- for (const auto & arg : args) {
384- wxarr.Add (arg);
385- }
386- wxString cmd = ArrayJoin (wxarr, flags);
387- return ExecuteConPTY (parent, cmd, flags, workingDir);
388- }
389-
390263/* static*/
391264IProcess* WinProcessImpl::Execute (
392265 wxEvtHandler* parent, const wxString& cmd, size_t flags, const wxString& workingDir, IProcessCallback* cb)
393266{
394- if (flags & IProcessPseudoConsole) {
395- return ExecuteConPTY (parent, cmd, flags, workingDir);
396- }
397-
398267 SECURITY_ATTRIBUTES saAttr;
399268 BOOL fSuccess ;
400269
@@ -415,29 +284,17 @@ IProcess* WinProcessImpl::Execute(
415284 bool redirectOutput = !(flags & IProcessNoRedirect);
416285
417286 // The steps for redirecting child process's STDOUT:
418- // 1. Save current STDOUT, to be restored later.
419- // 2. Create anonymous pipe to be STDOUT for child process.
420- // 3. Set STDOUT of the parent process to be write handle to
421- // the pipe, so it is inherited by the child process.
422- // 4. Create a noninheritable duplicate of the read handle and
287+ // 1. Create anonymous pipe to be STDOUT for child process.
288+ // 2. Create a noninheritable duplicate of the read handle and
423289 // close the inheritable read handle.
424290
425291 if (redirectOutput) {
426- // Save the handle to the current STDOUT.
427- prc->hSaveStdout = GetStdHandle (STD_OUTPUT_HANDLE);
428-
429292 // Create a pipe for the child process's STDOUT.
430293 if (!CreatePipe (&prc->hChildStdoutRd , &prc->hChildStdoutWr , &saAttr, 0 )) {
431294 delete prc;
432295 return NULL ;
433296 }
434297
435- // Set a write handle to the pipe to be STDOUT.
436- if (!SetStdHandle (STD_OUTPUT_HANDLE, prc->hChildStdoutWr )) {
437- delete prc;
438- return NULL ;
439- }
440-
441298 // Create noninheritable read handle and close the inheritable read handle.
442299 fSuccess = DuplicateHandle (GetCurrentProcess (),
443300 prc->hChildStdoutRd ,
@@ -453,28 +310,16 @@ IProcess* WinProcessImpl::Execute(
453310 CloseHandle (prc->hChildStdoutRd );
454311
455312 // The steps for redirecting child process's STDERR:
456- // 1. Save current STDERR, to be restored later.
457- // 2. Create anonymous pipe to be STDERR for child process.
458- // 3. Set STDERR of the parent process to be write handle to
459- // the pipe, so it is inherited by the child process.
460- // 4. Create a noninheritable duplicate of the read handle and
313+ // 1. Create anonymous pipe to be STDERR for child process.
314+ // 2. Create a noninheritable duplicate of the read handle and
461315 // close the inheritable read handle.
462316
463- // Save the handle to the current STDERR.
464- prc->hSaveStderr = GetStdHandle (STD_ERROR_HANDLE);
465-
466317 // Create a pipe for the child process's STDERR.
467318 if (!CreatePipe (&prc->hChildStderrRd , &prc->hChildStderrWr , &saAttr, 0 )) {
468319 delete prc;
469320 return NULL ;
470321 }
471322
472- // Set a write handle to the pipe to be STDERR.
473- if (!SetStdHandle (STD_ERROR_HANDLE, prc->hChildStderrWr )) {
474- delete prc;
475- return NULL ;
476- }
477-
478323 // Create noninheritable read handle and close the inheritable read handle.
479324 fSuccess = DuplicateHandle (GetCurrentProcess (),
480325 prc->hChildStderrRd ,
@@ -490,26 +335,16 @@ IProcess* WinProcessImpl::Execute(
490335 CloseHandle (prc->hChildStderrRd );
491336
492337 // The steps for redirecting child process's STDIN:
493- // 1. Save current STDIN, to be restored later.
494- // 2. Create anonymous pipe to be STDIN for child process.
495- // 3. Set STDIN of the parent to be the read handle to the
496- // pipe, so it is inherited by the child process.
497- // 4. Create a noninheritable duplicate of the write handle,
338+ // 1. Create anonymous pipe to be STDIN for child process.
339+ // 2. Create a noninheritable duplicate of the write handle,
498340 // and close the inheritable write handle.
499341
500- // Save the handle to the current STDIN.
501- prc->hSaveStdin = GetStdHandle (STD_INPUT_HANDLE);
502-
503342 // Create a pipe for the child process's STDIN.
504343 if (!CreatePipe (&prc->hChildStdinRd , &prc->hChildStdinWr , &saAttr, 0 )) {
505344 delete prc;
506345 return NULL ;
507346 }
508- // Set a read handle to the pipe to be STDIN.
509- if (!SetStdHandle (STD_INPUT_HANDLE, prc->hChildStdinRd )) {
510- delete prc;
511- return NULL ;
512- }
347+
513348 // Duplicate the write handle to the pipe so it is not inherited.
514349 fSuccess = DuplicateHandle (GetCurrentProcess (),
515350 prc->hChildStdinWr ,
@@ -546,13 +381,19 @@ IProcess* WinProcessImpl::Execute(
546381
547382 if (flags & IProcessCreateWithHiddenConsole) {
548383 siStartInfo.wShowWindow = SW_HIDE;
549- creationFlags = CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP;
384+ // When redirecting output, we cannot use CREATE_NEW_CONSOLE because Windows
385+ // ignores STARTF_USESTDHANDLES when CREATE_NEW_CONSOLE is set. The child would
386+ // get its own console buffer that we cannot read from. Use CREATE_NO_WINDOW instead.
387+ if (redirectOutput) {
388+ creationFlags = CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP;
389+ } else {
390+ creationFlags = CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP;
391+ }
550392 }
551393
552394 LOG_IF_TRACE { clDEBUG1 () << " Running process:" << cmd << endl; }
553395 BOOL ret = FALSE ;
554396 {
555- ConsoleAttacher ca (prc->GetPid ());
556397 ret = CreateProcess (NULL ,
557398 cmd.wchar_str (), // shell line execution command
558399 NULL , // process security attributes
@@ -573,30 +414,6 @@ IProcess* WinProcessImpl::Execute(
573414 wxDELETE (prc);
574415 return NULL ;
575416 }
576-
577- if (redirectOutput) {
578- // After process creation, restore the saved STDIN and STDOUT.
579- if (!SetStdHandle (STD_INPUT_HANDLE, prc->hSaveStdin )) {
580- delete prc;
581- return NULL ;
582- }
583- if (!SetStdHandle (STD_OUTPUT_HANDLE, prc->hSaveStdout )) {
584- delete prc;
585- return NULL ;
586- }
587- if (!SetStdHandle (STD_OUTPUT_HANDLE, prc->hSaveStderr )) {
588- delete prc;
589- return NULL ;
590- }
591- }
592-
593- if ((prc->m_flags & IProcessCreateConsole) || (prc->m_flags & IProcessCreateWithHiddenConsole)) {
594- ConsoleAttacher ca (prc->GetPid ());
595- if (ca.isAttached ) {
596- freopen (" CONOUT$" , " wb" , stdout); // reopen stout handle as console window output
597- freopen (" CONOUT$" , " wb" , stderr); // reopen stderr handle as console window output
598- }
599- }
600417 prc->SetPid (prc->dwProcessId );
601418 if (!(prc->m_flags & IProcessCreateSync)) {
602419 prc->StartReaderThread ();
@@ -829,46 +646,7 @@ void WinProcessImpl::Terminate()
829646 }
830647}
831648
832- bool WinProcessImpl::WriteToConsole (const wxString& buff)
833- {
834- wxString pass (buff);
835- pass.Trim ().Trim (false );
836-
837- // To write password, we need to attach to the child process console
838- if (!(m_flags & (IProcessCreateWithHiddenConsole | IProcessCreateConsole)))
839- return false ;
840-
841- ConsoleAttacher ca (GetPid ());
842- if (ca.isAttached == false )
843- return false ;
844-
845- HANDLE hStdIn = ::CreateFile (
846- L" CONIN$" , GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL , OPEN_EXISTING, 0 , 0 );
847- if (hStdIn == INVALID_HANDLE_VALUE) {
848- return false ;
849- }
850-
851- pass += wxT (" \r\n " );
852- std::vector<INPUT_RECORD> pKeyEvents (pass.Len ());
853-
854- for (size_t i = 0 ; i < pass.Len (); i++) {
855- pKeyEvents[i].EventType = KEY_EVENT;
856- pKeyEvents[i].Event .KeyEvent .bKeyDown = TRUE ;
857- pKeyEvents[i].Event .KeyEvent .wRepeatCount = 1 ;
858- pKeyEvents[i].Event .KeyEvent .wVirtualKeyCode = LOBYTE (::VkKeyScan (pass[i]));
859- pKeyEvents[i].Event .KeyEvent .wVirtualScanCode = 0 ;
860- pKeyEvents[i].Event .KeyEvent .uChar .UnicodeChar = pass[i];
861- pKeyEvents[i].Event .KeyEvent .dwControlKeyState = 0 ;
862- }
863-
864- DWORD dwTextWritten;
865- if (::WriteConsoleInput (hStdIn, pKeyEvents.data (), pass.Len (), &dwTextWritten) == FALSE ) {
866- CloseHandle (hStdIn);
867- return false ;
868- }
869- CloseHandle (hStdIn);
870- return true ;
871- }
649+ bool WinProcessImpl::WriteToConsole (const wxString& buff) { return Write (buff); }
872650
873651void WinProcessImpl::Detach ()
874652{
0 commit comments