【问题标题】:Win32 ReadFile Output without waiting for bufferWin32 ReadFile 输出无需等待缓冲区
【发布时间】:2015-03-27 16:27:32
【问题描述】:

我使用CreateProcess() 向 cmd.exe 运行命令。该命令本身具有无限输出,因此我使用从this answer 修改的函数将部分输出转换为字符串。

#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。 (而不是冻结应用程序)

这可能吗?

【问题讨论】:

  • 很好的链接。谢谢你。 :)
  • 它不应该等待所有 4096 个字节。只要至少有一个字节可用,它就应该返回。你确定这个问题真的存在吗?注意你必须检查错误返回。
  • 这可能是因为我正在构建一个 FireBreath 项目,并且我正在从浏览器调用 C++ 函数,所以它也可能会冻结,因为浏览器在获得返回值之前无法继续。但我确信该函数会一直等到它获取整个缓冲区,然后才返回该值。我的回答完全解决了这个问题。

标签: c++ visual-studio-2012 readfile


【解决方案1】:

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](作为字符串,而不是布尔值)。

【讨论】:

    【解决方案2】:

    一种选择是将从管道读取的代码放在它自己的线程中,并让它在循环中运行。这将使您的主线程不会阻塞,并且您始终可以读取尽可能多的数据。挑战在于您现在需要有一种方法让读取线程将数据传输回主线程。

    另一种选择是使用重叠 I/O,这在 MSDN 的 ReadFile 和 CreateFile 文档中进行了讨论。这是一种让操作系统在从管道读取数据时回调的方法。因此,您的 ReadFile 不会阻塞,但缓冲区中(可能)直到稍后才会有任何数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-27
      • 1970-01-01
      • 2011-07-24
      • 1970-01-01
      • 1970-01-01
      • 2021-04-01
      • 1970-01-01
      相关资源
      最近更新 更多