WinAPI C++ client detect write on anonymous pipe before reading

前端 未结 3 1918
清酒与你
清酒与你 2021-01-20 23:35

I am writing a C++ (Windows) client console application which reads from an anonymous pipe on STDIN. I would like to be able to use my program as follows:

echo i         


        
相关标签:
3条回答
  • 2021-01-21 00:06

    This also works without overlapped I/O while using a second thread, that does the synchronous ReadFile-call. Then the main thread waits an arbitrary amount of time and acts like above...

    Hope this helps...

    0 讨论(0)
  • 2021-01-21 00:13

    It looks like what you're really trying to do here is to determine whether you've got console input (where you use default value) vs pipe input (where you use input from the pipe).

    Suggest testing that directly instead of trying to check if there's input ready: the catch with trying to sniff whether there's data in the pipe is that if the source app is slow in generating output, your app might make an incorrect assumption just because there isn't input yet available. (It might also be possible that, due to typeahead, there's a user could have typed in characters that area ready to be read from console STDIN before your app gets around to checking if input is available.)

    Also, keep in mind that it might be useful to allow your app to be used with file redirection, not just pipes - eg:

    myapp.exe < some_input_file
    

    The classic way to do this "interactive mode, vs used with redirected input" test on unix is using isatty(); and luckily there's an equivalent in the Windows CRT - see function _isatty(); or use GetFileType() checking for FILE_TYPE_CHAR on GetStdHandle(STD_INPUT_HANDLE) - or use say GetConsoleMode as Remy does, which will only succeed on a real console handle.

    0 讨论(0)
  • 2021-01-21 00:17

    Look at PeekNamedPipe(). Despite its name, it works for both named and anonymous pipes.

    int main(int argc, const char *argv[])
    {
        char char_buffer[BUFSIZE]; 
        DWORD bytes_read;
        DWORD bytes_avail;
        DWORD dw;
        HANDLE stdin_handle;
        bool is_pipe;
    
        stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
        is_pipe = !GetConsoleMode(stdin_handle, &dw);
    
        if (stdin_handle == INVALID_HANDLE_VALUE) {
            std::cout << "Error: invalid handle value!\n\n";
        } else {
            while (1) { 
                if (is_pipe) {
                    if (PeekNamedPipe(stdin_handle, NULL, 0, NULL, &bytes_avail, NULL)) {
                        if (bytes_avail == 0) {
                            Sleep(100);
                            continue;
                        }
                    }
                }
    
                if (!ReadFile(stdin_handle, char_buffer, min(bytes_avail, BUFSIZE), &bytes_read, NULL)) {
                    break; 
                }
    
                if (bytes_read == 0) {
                    break;
                }
    
                // Output what we have read so far
                for (unsigned int i = 0; i < bytes_read; i++) {
                    std::cout << char_buffer[i];
                }
            }
        }
    
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题