I am creating a child process, and reading its output. My code works fine when the child process creates output (cmd /c echo Hello World
), however ReadFile will hang if process does not create output (cmd /c echo Hello World > output.txt
). I am only reading after the process has terminated.
Am I doing something horribly wrong? Is there anyway to do this with synchronous mode, or do I have to use asynchronous mode? All of this is happening in a seperate thread, so I dont think asynchronous mode would offer any benefit to me, unless it is the only way to get this to work. Thanks a lot!
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);
You redirect the output of the process to a pipe, start the process, wait till it exits, and then read the output.
The problem is that windows buffers just a limited amount of data. So you must read the pipe while the process is still running, otherwise the process will be blocked because it cannot write any more data to the pipe.
You should close the write end of the output pipe before you read from it, as @Marcus suggested in the comment.
CloseHandle(g_hChildStd_OUT_Wr);
For me this is the real answer.
You could 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);
}
}
来源:https://stackoverflow.com/questions/13816962/win32-readfile-hangs-when-reading-from-pipe