Search code examples
c++winapipipeblockingreadfile

Reading from pipes blocks and deadlock


I am developing a remote shell like program. for running commands on remote machine I create a cmd.exe process and I redirect its stdin and stdout to a pair of pipes. I use these pipes to send commands and get the result. I used ReadFile function for returning the output of command from cmd.exe but I don't know the exact amount of data that I must read from pipe. so if the data is not ready the readfile goes to blocking mode and waiting for data.

I am using MSVC++ 2010 and my OS is Win7. Here is a part of my code as an example:

void CpipesDlg::OnBnClickedBtnredirstd()
{
    char Cmd[]="dir *.*\r\n";
    char Buff[129];
    CString str;
    HANDLE hStdIn_Read, hStdIn_Write;
    HANDLE hStdOut_Read, hStdOut_Write;
    SECURITY_ATTRIBUTES sAttr;

    STARTUPINFOA StartInf;
    PROCESS_INFORMATION procInf;

    DWORD dwBytesToWrite,dwBytesReadFrom;

    sAttr.nLength = sizeof(sAttr);
    sAttr.bInheritHandle = TRUE;
    sAttr.lpSecurityDescriptor = NULL;

    CreatePipe(&hStdIn_Read,&hStdIn_Write,&sAttr,0);
    CreatePipe(&hStdOut_Read,&hStdOut_Write,&sAttr,0);

    //SetHandleInformation(hStdIn_Read, HANDLE_FLAG_INHERIT, 0);
    //SetHandleInformation(hStdIn_Write, HANDLE_FLAG_INHERIT, 0);

    memset(&StartInf,0, sizeof(StartInf));
    memset(&procInf,0,sizeof(procInf));

    StartInf.cb = sizeof(StartInf);
    StartInf.dwFlags = STARTF_USESTDHANDLES;
    StartInf.hStdError = hStdOut_Write;
    StartInf.hStdOutput = hStdOut_Write;
    StartInf.hStdInput = hStdIn_Read;

    WriteFile(hStdIn_Write,Cmd,sizeof(Cmd),&dwBytesToWrite,NULL);

    if(!CreateProcessA(NULL,"cmd.exe",NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW ,NULL,NULL,&StartInf,&procInf))
    {
        MessageBoxA(m_hWnd, "Can't Create Process","Error",MB_OK | MB_ICONERROR);
    }
        WriteFile(hStdIn_Write,Cmd,sizeof(Cmd),&dwBytesToWrite,NULL);

    BOOL bSUCCESS =TRUE;
    Sleep(100);
    while(bSUCCESS)
    {

        BOOL bResult  = ReadFile(hStdOut_Read,Buff,70,&dwBytesReadFrom,NULL);
        if(!bResult)
        {
            break;
        }
        Buff[dwBytesReadFrom]=0;
        str+= Buff;
        bSUCCESS = dwBytesReadFrom!=0;
    }
    m_Disp = str;
    UpdateData(FALSE);
    CloseHandle(hStdIn_Read);
    CloseHandle(hStdIn_Write);
    CloseHandle(hStdOut_Read);
    CloseHandle(hStdOut_Write);
}

In above code, in debugging mode the first calls to ReadFile function returns true data but last call of it blocks, because there is no enough data to read.

Here is my Question: How can I avoid the blocking mode or get the exact number of bytes for reading?

Regards!


Solution

  • You PROBABLY want to use the PeekNamedPipe function, which allows you to interrogate a pipe to see how much data there is available at any given time. If the lpBuffer is NULL then no data is being read.