ArcticLord ArcticLord - 1 month ago 3x
C++ Question

How can I read process output that has not been flushed?

Consider this little programm be compiled as


#include <stdio.h>

int main()
char str[100];
printf ("Hello, please type something\n");
scanf("%[^\n]s", &str);
printf("you typed: %s\n", str);
return 0;

Now I use this code to start
and fetch its output.

#include <stdio.h>
#include <iostream>
#include <stdexcept>

int main()
char buffer[128];
FILE* pipe = popen("application.exe", "r");
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != NULL)
return 0;

My problem is that there is no output until I did my input. Then both output lines get fetched.
I can workarround this problem by adding this line after the first


Then the first line is fetched before I do my input as expected.

But how can I fetch output of applications that I cannot modify and that do not use
in "realtime" (means before they exit)? .
And how does the windows cmd do it?


The problems of my question in my original post are already very good explained in the other answers.
Console applications use a function named isatty() to detect if their stdout handler is connected to a pipe or a real console. In case of a pipe all output is buffered and flushed in chunks except if you directly call fflush(). In case of a real console the output is unbuffered and gets directly printed to the console output.
In Linux you can use openpty() to create a pseudoterminal and create your process in it. As a result the process will think it runs in a real terminal and uses unbuffered output.
Windows seems not to have such an option.

After a lot of digging through winapi documentation I found that this is not true. Actually you can create your own console screen buffer and use it for stdout of your process that will be unbuffered then.
Sadly this is not a very comfortable solution because there are no event handler and we need to poll for new data. Also at the moment I'm not sure how to handle scrolling when this screen buffer is full.
But even if there are still some problems left I think I have created a very useful (and interesting) starting point for those of you who ever wanted to fetch unbuffered (and unflushed) windows console process output.

#include <windows.h>
#include <stdio.h>

int main(int argc, char* argv[])
    char cmdline[] = "application.exe"; // process command
    HANDLE scrBuff;                     // our virtual screen buffer
    CONSOLE_SCREEN_BUFFER_INFO scrBuffInfo; // state of the screen buffer
                                            // like actual cursor position
    COORD scrBuffSize = {80, 25};       // size in chars of our screen buffer
    SECURITY_ATTRIBUTES sa;             // security attributes
    PROCESS_INFORMATION procInfo;       // process information
    STARTUPINFO startInfo;              // process start parameters
    DWORD procExitCode;                 // state of process (still alive)
    DWORD NumberOfCharsWritten;         // output of fill screen buffer func
    COORD pos = {0, 0};                 // scr buff pos of data we have consumed
    bool quit = false;                  // flag for reading loop

    // 1) Create a screen buffer, set size and clear

    sa.nLength = sizeof(sa);
    scrBuff = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
                                         FILE_SHARE_READ | FILE_SHARE_WRITE,
                                         &sa, CONSOLE_TEXTMODE_BUFFER, NULL);
    SetConsoleScreenBufferSize(scrBuff, scrBuffSize);
    // clear the screen buffer
    FillConsoleOutputCharacter(scrBuff, '\0', scrBuffSize.X * scrBuffSize.Y,
                               pos, &NumberOfCharsWritten);

    // 2) Create and start a process
    //      [using our screen buffer as stdout]

    ZeroMemory(&procInfo, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&startInfo, sizeof(STARTUPINFO));
    startInfo.cb = sizeof(STARTUPINFO);
    startInfo.hStdOutput = scrBuff;
    startInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
    startInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    startInfo.dwFlags |= STARTF_USESTDHANDLES;
    CreateProcess(NULL, cmdline, NULL, NULL, FALSE,
                  0, NULL, NULL, &startInfo, &procInfo);    

    // 3) Read from our screen buffer while process is alive

        // check if process is still alive or we could quit reading
        GetExitCodeProcess(procInfo.hProcess, &procExitCode);
        if(procExitCode != STILL_ACTIVE) quit = true;

        // get actual state of screen buffer
        GetConsoleScreenBufferInfo(scrBuff, &scrBuffInfo);

        // check if screen buffer cursor moved since
        // last time means new output was written
        if (pos.X != scrBuffInfo.dwCursorPosition.X ||
            pos.Y != scrBuffInfo.dwCursorPosition.Y)            
            // Get new content of screen buffer
            //  [ calc len from pos to cursor pos: 
            //    (curY - posY) * lineWidth + (curX - posX) ]
            DWORD len =  (scrBuffInfo.dwCursorPosition.Y - pos.Y)
                        * scrBuffInfo.dwSize.X 
                        +(scrBuffInfo.dwCursorPosition.X - pos.X);
            char buffer[len];
            ReadConsoleOutputCharacter(scrBuff, buffer, len, pos, &len);

            // Print new content
            // [ there is no newline, unused space is filled with '\0'
            //   so we read char by char and if it is '\0' we do 
            //   new line and forward to next real char ]
            for(int i = 0; i < len; i++)
                if(buffer[i] != '\0') printf("%c",buffer[i]);
                    while((i + 1) < len && buffer[i + 1] == '\0')i++;

            // Save new position of already consumed data
            pos = scrBuffInfo.dwCursorPosition;
        // no new output so sleep a bit before next check
        else Sleep(100);

    // 4) Cleanup and end

    return 0;