Note that there are some explanatory texts on larger screens.

plurals
  1. POHow can I read a child process's output?
    text
    copied!<p>I have written a function that attempts to read a child process's command line output via a pipe. This should be a simple subset of <a href="http://msdn.microsoft.com/en-us/library/ms682499%28VS.85%29.aspx" rel="noreferrer">the MSDN Creating a Child Process with Redirected Input and Output article</a>, but I am clearly making an error of some sort. </p> <p>The ReadFile(...) call below blocks forever no matter if I place it before or after the WaitForSingleObject(...) call that should signal the end of the child process. </p> <p>I have read all the answers that suggest "Use asynchronous ReadFile" and I am open to that suggestion if someone could give me some idea how that is accomplished on a pipe. Although I don't understand why asynchronous I/O should be needed for this case.</p> <pre><code>#include "stdafx.h" #include &lt;string&gt; #include &lt;windows.h&gt; unsigned int launch( const std::string &amp; cmdline ); int _tmain(int argc, _TCHAR* argv[]) { launch( std::string("C:/windows/system32/help.exe") ); return 0; } void print_error( unsigned int err ) { char* msg = NULL; FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&amp;msg, 0, NULL ); std::cout &lt;&lt; "------ Begin Error Msg ------" &lt;&lt; std::endl; std::cout &lt;&lt; msg &lt;&lt; std::endl; std::cout &lt;&lt; "------ End Error Msg ------" &lt;&lt; std::endl; LocalFree( msg ); } unsigned int launch( const std::string &amp; cmdline ) { TCHAR cl[_MAX_PATH*sizeof(TCHAR)]; memset( cl, 0, sizeof(cl) ); cmdline.copy( cl, (_MAX_PATH*sizeof(TCHAR)) - 1); HANDLE stdoutReadHandle = NULL; HANDLE stdoutWriteHandle = NULL; SECURITY_ATTRIBUTES saAttr; memset( &amp;saAttr, 0, sizeof(saAttr) ); saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // Create a pipe for the child process's STDOUT. if ( ! CreatePipe(&amp;stdoutReadHandle, &amp;stdoutWriteHandle, &amp;saAttr, 5000) ) throw std::runtime_error( "StdoutRd CreatePipe" ); // Ensure the read handle to the pipe for STDOUT is not inherited. if ( ! SetHandleInformation(stdoutReadHandle, HANDLE_FLAG_INHERIT, 0) ) throw std::runtime_error( "Stdout SetHandleInformation" ); STARTUPINFO startupInfo; memset( &amp;startupInfo, 0, sizeof(startupInfo) ); startupInfo.cb = sizeof(startupInfo); startupInfo.hStdError = stdoutWriteHandle; startupInfo.hStdOutput = stdoutWriteHandle; startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); startupInfo.dwFlags |= STARTF_USESTDHANDLES; char* rawEnvVars = GetEnvironmentStringsA(); //__asm _emit 0xcc; PROCESS_INFORMATION processInfo; memset( &amp;processInfo, 0, sizeof(processInfo) ); std::cout &lt;&lt; "Start [" &lt;&lt; cmdline &lt;&lt; "]" &lt;&lt; std::endl; if ( CreateProcessA( 0, &amp;cl[0], 0, 0, false, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, rawEnvVars, 0, &amp;startupInfo, &amp;processInfo ) ) { //CloseHandle( stdoutWriteHandle ); DWORD wordsRead; char tBuf[257] = {'\0'}; bool success = true; std::string outBuf(""); unsigned int t; while(success) { //__asm _emit 0xcc; std::cout &lt;&lt; "Just before ReadFile(...)" &lt;&lt; std::endl; success = ReadFile( stdoutReadHandle, tBuf, 256, &amp;wordsRead, NULL); (t=GetLastError())?print_error(t):t=t; std::cout &lt;&lt; "Just after ReadFile(...) | read " &lt;&lt; wordsRead&lt;&lt; std::endl; std::cout &lt;&lt; "."; if( success == false ) break; outBuf += tBuf; tBuf[0] = '\0'; } std::cout &lt;&lt; "output = [" &lt;&lt; outBuf &lt;&lt; "]" &lt;&lt; std::endl; if ( WaitForSingleObject( processInfo.hProcess, INFINITE ) == WAIT_OBJECT_0 ) { unsigned int exitcode = 0; GetExitCodeProcess( processInfo.hProcess, (LPDWORD)&amp;exitcode ); std::cout &lt;&lt; "exitcode = [" &lt;&lt; exitcode &lt;&lt; "]" &lt;&lt; std::endl; //__asm _emit 0xcc; CloseHandle( processInfo.hProcess ); CloseHandle( processInfo.hThread ); return exitcode; } } else { DWORD procErr = GetLastError(); std::cout &lt;&lt; "FAILED TO CREATE PROCESS!" &lt;&lt; std::endl; print_error( procErr ); } return -1; } // end launch() </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload