簡體   English   中英

Win32 ReadFile輸出,無需等待緩沖區

[英]Win32 ReadFile Output without waiting for buffer

我使用CreateProcess()對cmd.exe運行命令。 該命令本身具有無窮無盡的輸出,因此我使用了根據該答案修改的函數,以將部分輸出轉換為字符串。

#define BUFSIZE 4096
HANDLE g_hChildStd_OUT_Rd = NULL;

std::string ReadFromPipe(PROCESS_INFORMATION piProcInfo) {
    DWORD dwRead; 
    CHAR chBuf[BUFSIZE];
    ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
    std::string s(chBuf, dwRead);
    return s;
}

但是這段代碼會帶來一些問題。

首先,每次調用它時,它都可能在等待輸出緩沖到4096字節時凍結程序。

其次,它將始終僅在輸出隊列中獲得下一個4096字節。 (即使當前輸出大很多)

我想要的是調用該函數並獲取同時輸出的所有數據,並且還能夠設置要獲取的最小字節數(而不是緩沖區)。 如果最小字節數尚不可用,我希望它完全跳過ReadFile()並只返回false (而不是凍結應用程序)

這可能嗎?

Arkadiy的評論將我引向正確的方向。 我在PeekNamedPipe()的幫助下使其工作

我當前的代碼:

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

#pragma warning( disable : 4800 ) // hide bool warning
#define BUFSIZE 1024
HANDLE g_hChildStd_OUT_Rd = NULL;

std::string ReadFromPipe(PROCESS_INFORMATION piProcInfo) {
    CHAR chBuf[BUFSIZE];
    DWORD dwRead;
    DWORD avail;
    bool bSuccess = FALSE;
    bool tSuccess = FALSE;
    std::string out = "";
    tSuccess = PeekNamedPipe( g_hChildStd_OUT_Rd, NULL, 0, NULL, &avail, NULL );
    if (tSuccess && avail >= BUFSIZE) {
        while (avail >= BUFSIZE) {
            bSuccess=ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
            if( ! bSuccess || dwRead == 0 ) break; 
            std::string s(chBuf, dwRead);
            out += s;
            avail = avail - BUFSIZE;
        }
        return out;
    } else {
        return "[false]";
    }
}

此函數在被調用時將返回自上次調用以來的輸出。 BUFSIZE現在充當最小緩沖區,如果輸出小於最小緩沖區,則該函數將返回[false] (作為字符串,不是bool)。

一種選擇是將從管道中讀取的代碼放在自己的線程中,並使其在循環中運行。 這樣可以防止主線程阻塞,並且您始終可以讀取盡可能多的數據。 挑戰在於,您現在需要一種獲取讀取線程的方法,以將數據傳輸回主線程。

另一種選擇是使用重疊的I / O,這在MSDN的ReadFile和CreateFile文檔中進行了討論。 無論何時從管道中讀取數據,這都是一種使操作系統回調的方式。 因此,您的ReadFile不會被阻止,但是(可能)在緩沖區中不會有任何數據,直到稍后。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM