How does cmd.exe display stdout even though the process doesn't flush?

Viewed 459

I used this MSDN code to hook stdout and stderr for a child process, (except that I'm calling PeekNamedPipe first so that I don't block) and all is well except that for stdout if the process doesn't flush then I don't see the output of the process immediately. Stderr seems to be automatically flushed whenever something is sent to it, but stdout buffers the results.

Suddenly I'm amazed that the cmd.exe shell process can print results immediately when you step through code in Visual Studio. I would like to do so too. How does it do it?

3 Answers

It's not the cmd.exe rather the implementation of the stdio. When printing to stdout it holds the information in a buffer and flushes it periodically (or before shutdown) by a different thread. This behavior is on purpose and used to improve performance. Otherwise, printing will be blocking.

Here is how to make it autoflush after each print command: C autoflush

cmd.exe use direct winapi calls WriteFile or WriteConsoleW for print to stdout. so if you want to do so too - you can also use this winapi.

when stdout is file:

enter image description here

when stdout is console: enter image description here

We can't find out how the Visual Studio implement this logic.

To solve your issue, prevent the parent process blocking and print the output from the child process, you can check the read size returned from ReadFile in your parent process to decide to read continue or stop if you can't control the child process.

for (;;)
{
    bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
    if (!bSuccess || dwRead == 0) break;

    bSuccess = WriteFile(hParentStdOut, chBuf,
        dwRead, &dwWritten, NULL);
    if (!bSuccess) break;

    // Check if there is more data to read, if not break.
    if (dwRead < BUFSIZE)
        break;
}
Related