使用管道从子进程进行I/O重定向-WinAPI [英] I/O redirection from child process using pipes - winapi

查看:172
本文介绍了使用管道从子进程进行I/O重定向-WinAPI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用提供api的应用程序,以便更轻松地编写脚本.基本上,当您编写有效输入时,它会输出一个答案.我想使用该输出来发送更多输入,例如:

I'm working with an application that offers an api so that scripting it is easier. Basically, when you write valid input, it outputs an answer. I would like to use that output to sends more input, e.g.:

Input: <nodes>
Output: 1, 56, 23
Input <56>
Output: "Apple"

我想做的是一个程序,该程序写入目标进程STDIN,然后从其STDOUT中读取输出.为此,我主要从那里获取代码:

What I'd like to do is a program that writes to the target process STDIN, then reads the output from it's STDOUT. To do that, I mostly took the code from there:

创建子进程具有重定向的输入和输出(Windows)-MSDN

唯一的问题是,为了从子进程中读取数据,我首先需要关闭用于写入子进程的父进程的句柄,这意味着我无法使用子进程的输出来编写更多内容东西.

The only problem is that in order to read from the child process, I first need to close the handle of my parent process used to write to it, which means I can't use the output from the child process to write more stuff to it.

这是从msdn提取的简化代码:

Here is the simplified code taken from msdn:

#include <Windows.h>
#include <string>

using std::string;

HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;

#define BUFSIZE 4096

void WriteToPipe(string msg); 
void ReadFromPipe(void); 

int main()
{
    /*
     * CREATE PIPES
    */

    SECURITY_ATTRIBUTES saAttr;

    // Set the bInheritHandle flag so pipe handles are inherited.
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    // Create pipes for the child process's STDOUT and STDIN,
    // ensures both handle are not inherited
    CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0);
    SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0);

    CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0);
    SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0);

    /*
     * CREATE CHILD PROCESS
    */

    TCHAR szCmdline[]=TEXT("target.exe");
    STARTUPINFO siStartInfo;
    PROCESS_INFORMATION piProcInfo;

    // Set up members of the PROCESS_INFORMATION structure.
    ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );

    // Set up members of the STARTUPINFO structure.
    // This structure specifies the STDIN and STDOUT handles for redirection.
    ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
    siStartInfo.cb = sizeof(STARTUPINFO);
    siStartInfo.hStdError  = g_hChildStd_OUT_Wr;
    siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
    siStartInfo.hStdInput  = g_hChildStd_IN_Rd;
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

    CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, 0,
                  NULL,  NULL, &siStartInfo, &piProcInfo);

    // Close handles to the child process and its primary thread.
    // Some applications might keep these handles to monitor the status
    // of the child process, for example. 
    CloseHandle(g_hChildStd_OUT_Wr);
    CloseHandle(g_hChildStd_IN_Rd);
    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProcInfo.hThread);

    /*
     * ACTUAL APPLICATION
    */

    WriteToPipe("<nodes>\n");

    // Need to close the handle before reading
    CloseHandle(g_hChildStd_IN_Wr); // PROBLEM HERE

    ReadFromPipe();

    WriteToPipe("<56>\n"); // I can't, as I have released the handle already

    system("pause");

    return 0;
}

void WriteToPipe(string msg)
{
    WriteFile(g_hChildStd_IN_Wr, msg.c_str(), msg.size(), NULL, NULL);
}

void ReadFromPipe(void)
{
    DWORD dwRead, dwWritten;
    CHAR chBuf[BUFSIZE];
    BOOL bSuccess = FALSE;
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

    for (;;)
    {
        bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
        if( ! bSuccess || dwRead == 0 ) break;

        bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
        if (! bSuccess ) break;
    }
}

问题出在那一行:

CloseHandle(g_hChildStd_IN_Wr);

要么我把它留在那儿,我一读就无法写它的子进程,或者先删除它,然后ReadFromPipe陷入死锁.

Either I leave it there, and I won't be able to write to my child process after I read it once, or I remove it and then ReadFromPipe get stuck in a deadlock.

任何帮助将不胜感激,谢谢!

Any help would be appreciated, thanks!

推荐答案

ReadFile(..., BUFSIZE)的意思是等待程序写入BUFSIZE字节,或关闭它的管道末端".该程序仅写入少量字节,然后等待更多您未提供的输入.如果关闭写管道,它将知道没有更多的输入,然后退出,这时您的ReadFile会知道没有更多的输入并返回.您需要找到一种方法,以仅读取管道中的所有字节.

ReadFile(..., BUFSIZE) means "wait until the program writes BUFSIZE bytes, or closes it's end of the pipe". The program is writing just a small number of bytes, and then waiting for more input, which you aren't providing. If you close the write pipe, it knows there's no more input, and quits, at which point your ReadFile knows there's no more input and returns. You need to find a way to read only as many bytes as are in the pipe.

这里的神奇之处是 PeekNamedPipe ,它告诉您程序输出了多少数据,从而可以无阻塞地读取多少数据.请注意,您必须不时检查一下,以查看自上次检查以来该程序是否写入了更多字节.

The magic piece here is PeekNamedPipe, which tells you how much data the program has output, and thus how much you can read without blocking. Note that you'll have to keep checking every once in a while to see if the program wrote more bytes since the last time you checked.

这篇关于使用管道从子进程进行I/O重定向-WinAPI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆