Question

I've written a small program which is supposed to redirect cmd.exe stdout by given it a command, and use a pipe to get the input.

The program works perfectly well while using commands like ipconfig, but when I try to pass tasklist as a command, for example, the program just gets stuck and won't get any output.

Here is the code :

#include <Windows.h>
#include <tchar.h>
#include <iostream>

#define BUFFSIZE 100000

int wmain(int argc, wchar_t* argv[])
{    
    HANDLE  hReadPipe, hWritePipe;
    SECURITY_ATTRIBUTES saAttr;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;
    if (CreatePipe(&hReadPipe, &hWritePipe, &saAttr, 0) != 0)
    {
        STARTUPINFO structStartUpInfo;
        ZeroMemory(&structStartUpInfo, sizeof(STARTUPINFO));
        structStartUpInfo.cb = sizeof(STARTUPINFO);
        structStartUpInfo.wShowWindow = SW_HIDE;
        structStartUpInfo.hStdInput = hReadPipe;
        structStartUpInfo.hStdOutput = hWritePipe;
        structStartUpInfo.dwFlags = STARTF_USESTDHANDLES;
        PROCESS_INFORMATION structProcInf;
        ZeroMemory(&structProcInf, sizeof(PROCESS_INFORMATION));
        if (CreateProcess(NULL, L"tasklist", NULL, NULL, TRUE, NORM    AL_PRIORITY_CLASS, NULL, NULL, &structStartUpInfo, &structProcInf) != 0)
        {
            WaitForSingleObject(structProcInf.hProcess, INFINITE);
            CHAR output[BUFFSIZE];
            DWORD wdByteToRead = BUFFSIZE;
            DWORD dwByteread;
            ReadFile(hReadPipe, output, wdByteToRead, &dwByteread, NULL);
            std::string final = output;
            final = final.substr(0, dwByteread);
            std::cout << final.c_str();
        }
    }
    return 0;

How can I fix this?

Was it helpful?

Solution

Pipes have a maximum buffer size. tasklist is probably writing up to the buffer size without blocking, but it blocks when writing after that.

By looking at your code, the child process would need to read its own input to avoid blocking.

You need to call CreatePipe twice, then keep the reading pipe of one pair and the writing pipe of the other pair for yourself (the parent process) and provide the writing pipe of the former pair and the reading pipe of the latter pair to the child process.

Even so, pipes have a maximum buffer size. To avoid the child process from blocking, you must keep reading from the pipe in the parent process.

EDIT: If you're not going to write to the child process, you may as well close the parent's writing end of the pipe or set hStdInput to zero.

Also, you should initialize hStdError, either with the writing end of another pipe or by setting it to zero.

Programs based on (one of) the Microsoft C Runtime(s) simply ignore a standard handle when it is zero, but other programs might not, so having 3 pairs of pipes is probably the safest approach. But then, you have to read from that pipe as well to avoid a subprocess from blocking when writing to it, however unlikely.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top