0

So I'm running into a strange problem while trying to redirect the output of a process. I created a sample program which first prints a statement and then after 5 seconds prints another statement.

I setup my process via CreateProcesss and setup my pipe via CreatePipeetc, all the normal things one has to do. I make sure to close the process's OUT write and IN rd pipes after creation. I use PeekNamedPipe to determine if there is data to be read. After all this initial setup I do not get any output until the 5 seconds are up. It is only returning data to me after the process exits. I cannot seem to figure out why.

Was wondering if anyone sees something wrong in my logic?

I have the following c code:

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

int main(){


    // the handles for creating pipes
    HANDLE g_hChildStd_IN_Rd = NULL;
    HANDLE g_hChildStd_IN_Wr = NULL;
    HANDLE g_hChildStd_OUT_Rd = NULL;
    HANDLE g_hChildStd_OUT_Wr = NULL;
    HANDLE g_hChildStd_Err_Rd = NULL;
    HANDLE g_hChildStd_Err_Wr = NULL;

    // security attributes for inheriting pipe handles
    SECURITY_ATTRIBUTES saAttr; 

    // Set the bInheritHandle flag so pipe handles are inherited. 
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saAttr.bInheritHandle = TRUE; 
    saAttr.lpSecurityDescriptor = NULL; 

    // Create a pipe for the child process's STDOUT. 
    if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) ) 
        printf("StdoutRd CreatePipe"); 

    // Ensure the read handle to the pipe for STDOUT is not inherited.
    if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) )
        printf("Stdout SetHandleInformation"); 

    // Create a pipe for the child process's STDIN. 
    if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) 
        printf("Stdin CreatePipe"); 

    // Ensure the write handle to the pipe for STDIN is not inherited. 
    if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
        printf("Stdin SetHandleInformation");


    // Create a pipe for the child process's STDERR. 
    if ( ! CreatePipe(&g_hChildStd_Err_Rd, &g_hChildStd_Err_Wr, &saAttr, 0) ) 
        printf("StdoutRd CreatePipe"); 

    // Ensure the read handle to the pipe for STDOUT is not inherited.
    if ( ! SetHandleInformation(g_hChildStd_Err_Rd, HANDLE_FLAG_INHERIT, 0) )
        printf("Stdout SetHandleInformation"); 


    STARTUPINFO si={0};

    ZeroMemory( &si, sizeof(STARTUPINFO) );
    si.cb = sizeof(STARTUPINFO); 
    si.hStdError = g_hChildStd_OUT_Wr;
    si.hStdOutput = g_hChildStd_OUT_Wr;
    si.hStdInput = g_hChildStd_IN_Rd;
    si.dwFlags |= STARTF_USESTDHANDLES;


    PROCESS_INFORMATION pi={0};
    int status = CreateProcessA("a.exe", 0, 0, 0, TRUE, 0, 0, 0, &si, &pi);
    CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    // Dont forget to close stderr once we make it. Currently stderr gets combined
    // with stdout
    CloseHandle(g_hChildStd_OUT_Wr);
    CloseHandle(g_hChildStd_IN_Rd);


    while (1 )
    {
        Sleep(200);
        DWORD dwRead = 0;
        unsigned char out[5] = {0};

        PeekNamedPipe(g_hChildStd_OUT_Rd,0,0,0,&dwRead,0);

        if (dwRead > 0) 
        {
            ReadFile(g_hChildStd_OUT_Rd,out, 5 ,&dwRead, 0);
            printf("STDOUT: %s", out);
        }

        printf("write file\n");
        WriteFile(g_hChildStd_IN_Wr,"hello\n\n",7,&dwRead,0);
    }
}

being tested on the following program a.exe:

#include <stdio.h>
#include <windows.h>
int main()
{

char word[250];

printf("HELLO WORLD: ");

Sleep(500);
printf("\nyou printed %s!\n\n",word);
Sleep(5000);
printf("More prints..\n");

return 0;
}
efel
  • 1,054
  • 3
  • 14
  • 29
  • Provide a mvce http://stackoverflow.com/help/mcve – NineBerry Feb 25 '17 at 13:52
  • It is entirely normal, most any program that supports I/O direction will switch stdout and stderr to buffered output. Makes it a lot more efficient. That buffer won't be flushed until it is full or the stream is closed or the programmer explicitly flushes it. You won't find that programmer here. Just one of the problems that makes I/O redirection is the worst possible way to do process interop, it is a feature that should have stayed in Unix. – Hans Passant Feb 25 '17 at 14:03
  • i dont understand your explanation. When i read from stdout normally, i can see the print statements on the screen at the given times. When i redirect stdout i should be able to see the print statements at the same time and not when the program exits – efel Feb 25 '17 at 15:39
  • The details depend on what language runtime you're using, but typically the runtime will intentionally change the behaviour of output statements depending on whether the output is to the console or to a file. (Pipes are typically treated as files, which is unfortunate IMO, but there you go.) – Harry Johnston Feb 25 '17 at 20:49
  • You can solve the problem in your toy example by changing your child program so that it flushes the data, but this still isn't a very efficient way of doing things. Your child program should perhaps be a DLL instead, or just part of the parent program. Presumably your real use case is different, but as a general rule in Windows reading information from a child process is likely to be the wrong approach. If you describe your real use case we may be able to provide more specific advice. – Harry Johnston Feb 25 '17 at 20:55
  • As edited, arguably a duplicate of http://stackoverflow.com/q/7876660/886887 – Harry Johnston Feb 25 '17 at 20:57
  • Well I would just like to dynamically interact with a a process. So if i run a process and from it's stdout it gives the parent some output I would like to respond to that output via the child's stdin. Is this possible to do given the code I gave? – efel Feb 25 '17 at 20:58
  • Only if the child process is designed to be used that way. The link I've posted shows you how to fix your example code. – Harry Johnston Feb 25 '17 at 20:59
  • I see thank, you. So the only way is to fflush. I will probably mark this as duplicate – efel Feb 25 '17 at 21:04

0 Answers0