本文介绍了子进程的重定向STDOUT上的ReadFileEx重叠,从不触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基于控制台的长期运行的应用程序Sender,它使用cout<<等非缓冲输出将简单文本发送到STDOUT.邮件"<<flush().我想创建一个基于MFC对话框的应用程序(名为Receiver),该应用程序启动Sender并可以读取其输出.接收方还应该能够检测出发件人何时死亡,或者能够杀死发件人.发件人对接收者一无所知,我无法更改发件人的代码.

I have a long-running console-based application Sender that sends simple text to STDOUT using non-buffered output such as cout << "Message" << flush(). I want to create an MFC dialog-based application (named Receiver) that starts Sender and can read it's output. Receiver should also be able to detect when Sender has died, or be able to kill Sender if it wants to. Sender knows nothing of Reciever, and I can't change Sender's code.

我问过有关执行此操作的最佳方法的单独问题.我的第一个尝试是为子进程创建带有重定向的STDIN和STDOUT的管道,并使用异步ReadFileEx调用来读取Sender的数据.这无法正常工作,因为ReadFileEx函数仅触发一次,并且仅传输零字节,即使我知道 Sender 正在发送数据的事实.

I have asked a separate question about the best way to do this. My first attempt was to create pipes with redirected STDIN and STDOUT for the child process and use asynchronous ReadFileEx calls to read in Sender's data. This isn't working correctly, because the ReadFileEx function only fires once, and only with zero bytes transferred even though I know for a fact that Sender is sending data.

我正在使用重定向的STDIN和STDOUT创建2个管道,例如此MS示例:

I am creating 2 pipes with redirected STDIN and STDOUT, ala this MS example:

// allow the child process to inherit handles
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(sa);
sa.bInheritHandle = 1;

// create pipes with rerouted stdin & stdout
CreatePipe(&handles[h_Child_StdOut_Read], &handles[h_Child_StdOut_Write], &sa, 0);
SetHandleInformation(handles[h_Child_StdOut_Read], HANDLE_FLAG_INHERIT, 0);
CreatePipe(&handles[h_Child_StdIn_Read], &handles[h_Child_StdIn_Write], &sa, 0);
SetHandleInformation(handles[h_Child_StdIn_Read], HANDLE_FLAG_INHERIT, 0);

... Receiver 然后通过CreateProcess()启动 Sender :

...Receiver then goes on to start Sender via CreateProcess():

// create child process
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
si.cb = sizeof(si);
si.hStdOutput = handles[h_Child_StdOut_Write];
si.hStdInput = handles[h_Child_StdIn_Read];
si.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess( 0, "Sender.EXE", 0, 0, 1, 0, 0, 0, &si, &pi);
handles[h_Child_Process] = pi.hProcess;
handles[h_Child_Thread] = pi.hThread;

我的主循环基于WaitForObjectsEx,它处于可警告的等待状态,以支持读取异步文件.我正在等待两个句柄:一个在 Sender 过早终止时发出信号,另一个在 Receiver 的主线程希望 Sender 死亡时发出信号..在开始循环之前,我开始在 Sender 的STDOUT上进行重叠(异步)的文件读取操作.忽略明显的内存泄漏和其他攻击-这是说明性的:

My main loop is based on WaitForObjectsEx, placed in to an alertable wait state to support the asynch file read. I am waiting on two handles: one that signals when Sender dies prematurely, and one that signals when Receiver's main thread wants Sender to die. Before starting the loop, I kick off an overlapped (asynchronous) file read operation on Sender's STDOUT. Ignore the obvious memory leaks and other hacks -- this is illustrative:

vector<HANDLE> wait_handles;
wait_handles.push_back(handles[h_Die_Sig]);
wait_handles.push_back(handles[h_Child_Process]);

for( bool cont = true; cont; )
{
    IO* io = new IO;
    memset(io, 0, sizeof(IO));
    io->buf_size_ = 16 * 1024;
    io->buf_ = new char[io->buf_size_];
    memset(io->buf_, 0, io->buf_size_);
    io->thread_ = &param;
    io->file_ = handles[h_Child_StdOut_Read];
    if( !ReadFileEx(io->file_, io->buf_, io->buf_size_, io, OnFileRead) )
    {
        DWORD err = GetLastError();
        string err_msg = util::strprintwinerr(err);
    }

    DWORD rc = WaitForMultipleObjectsEx(wait_handles.size(), &wait_handles[0], FALSE, INFINITE, TRUE);

    // ...
}

上面的 IO 对象是从 OVERLAPPED 公开获得的:

The IO object above is derived publicly from OVERLAPPED:

struct IO : public OVERLAPPED
{
    char* buf_;
    DWORD buf_size_;
    DWORD read_;
    ThreadParam* thread_;
    HANDLE file_;
};

重叠的读取功能完成后,我读取了传入的数据并生成了一个字符串:

When the overlapped Read function completes, I read the incoming data and generate a string:

void CALLBACK OnFileRead(DWORD err, DWORD bytes, OVERLAPPED* ovr)
{
    IO* io = static_cast<IO*>(ovr);
    string msg(io->buf_, bytes);
}

发件人 Receiver 不了解,它使用非常简单但无缓冲的方式将文本发送到控制台.

Sender knows nothing of Receiver, and it sends text to the console using very simple, but non-buffered means.

问题:我知道 Sender 正在向其STDOUT发送数据,但是我的 OnFileRead 函数仅被调用一次,并且传输的字节数为零.

The problem: I know that Sender is sending data to its STDOUT, but my OnFileRead function is called only once, and only with zero bytes transferred.

为什么我不能通过这种方式接收 Sender 的输出?我是否有错误,或者我做错了什么?

Why can't I receive Sender's output this way? Do I have a bug, or am I doing something wrong?

推荐答案

我认为您有错字:

CreatePipe(&handles[h_Child_StdOut_Read], &handles[h_Child_StdOut_Write], &sa, 0);
SetHandleInformation(handles[h_Child_StdOut_Read], HANDLE_FLAG_INHERIT, 0);
CreatePipe(&handles[h_Child_StdIn_Read], &handles[h_Child_StdIn_Write], &sa, 0);
SetHandleInformation(handles[h_Child_StdIn_Read], HANDLE_FLAG_INHERIT, 0);

将最后一个更改为

SetHandleInformation(handles[h_Child_StdIn_Write], HANDLE_FLAG_INHERIT, 0);

这也是他们在MSDN示例中所做的.

that's also what they do at the MSDN example.

这篇关于子进程的重定向STDOUT上的ReadFileEx重叠,从不触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 07:28