Win32 ReadFile freezes while reading from a pipe

I create a child process and read its output. My code works fine when a child process produces output ( cmd /c echo Hello World ), however the ReadFile will hang if the process does not generate output ( cmd /c echo Hello World > output.txt ). I read only after the process has completed.

Am I doing something terribly wrong? Do I need to do this in synchronous mode, or do I need to use asynchronous mode? All this happens in a separate thread, so I do not think that asynchronous mode will bring me any benefit, unless this is the only way to make it work. Thank you very much!

 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0); SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0); memset(&piProcInfo, 0, sizeof(PROCESS_INFORMATION)); memset(&siStartInfo, 0, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = g_hChildStd_OUT_Wr; siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; siStartInfo.dwFlags |= STARTF_USESTDHANDLES; CreateProcess(NULL, commandWideString, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo); while(1) { GetExitCodeProcess(piProcInfo.hProcess, &processExitCode); if(processExitCode != STILL_ACTIVE) break; else Sleep(1); } *output = (char *)calloc(32, sizeof(char)); processOutputSize = 0; while(1) { bSuccess = ReadFile( g_hChildStd_OUT_Rd, processOutputTemp, 32, &dwRead, NULL); if(!bSuccess || !dwRead) break; memcpy(*output + processOutputSize, processOutputTemp, dwRead); processOutputSize += dwRead; if(dwRead == 32) *output = (char *)realloc(*output, processOutputSize + 32); else { memset(*output + processOutputSize, 0, 1); break; } } CloseHandle(piProcInfo.hProcess); CloseHandle(piProcInfo.hThread); CloseHandle(g_hChildStd_OUT_Rd); CloseHandle(g_hChildStd_OUT_Wr); 
+4
source share
3 answers

You redirect the process output to the channel, start the process, wait until it exits, and then read the output.

The problem is that Windows only buffers a limited amount of data. Therefore, you must read the pipe while the process is still running, otherwise the process will be blocked because it will not be able to write more data to the channel.

+3
source

You must close the end of the output channel record before reading from it, as indicated by @Marcus.

CloseHandle(g_hChildStd_OUT_Wr);

For me, this is the real answer.

+4
source

You can use PeekNamedPipe in a loop like this:

 for (;;) { DWORD bytesAvail = 0; if (!PeekNamedPipe(stdoutPipeRead, NULL, 0, NULL, &bytesAvail, NULL)) { std::cout << "Failed to call PeekNamedPipe" << std::endl; } if (bytesAvail) { CHAR buf[BUFSIZE]; DWORD n; BOOL success = ReadFile(stdoutPipeRead, buf, BUFSIZE, &n, NULL); if (!success || n == 0) { std::cout << "Failed to call ReadFile" << std::endl; } std::cout << std::string(buf, buf + n); } } 
+1
source

All Articles