I/O 使用管道从子进程重定向 - winapi
I/O redirection from child process using pipes - winapi
我正在使用一个提供 api 的应用程序,以便编写脚本更容易。基本上,当您编写有效输入时,它会输出一个答案。我想使用该输出来发送更多输入,例如:
Input: <nodes>
Output: 1, 56, 23
Input <56>
Output: "Apple"
我想要做的是一个写入目标进程 STDIN,然后从它的 STDOUT 读取输出的程序。为此,我主要从那里获取代码:
Creating a Child Process with Redirected Input and Output (Windows) - MSDN
唯一的问题是,为了从子进程读取,我首先需要关闭用于写入它的父进程的句柄,这意味着我不能使用子进程的输出来往里面写更多东西。
这是从 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 陷入死锁。
任何帮助将不胜感激,谢谢!
ReadFile(..., BUFSIZE)
表示 "wait until the program writes BUFSIZE
bytes, or closes it's end of the pipe"。该程序只写入少量字节,然后等待您未提供的更多输入。如果你关闭写管道,它知道没有更多的输入,然后退出,此时你的 ReadFile 知道没有更多的输入和 returns。您需要找到一种方法来只读取管道中的字节数。
这里的神奇之处是 PeekNamedPipe,它告诉您程序输出了多少数据,因此您可以无阻塞地读取多少数据。请注意,您必须每隔一段时间检查一次,看看自上次检查以来程序是否写入了更多字节。
我正在使用一个提供 api 的应用程序,以便编写脚本更容易。基本上,当您编写有效输入时,它会输出一个答案。我想使用该输出来发送更多输入,例如:
Input: <nodes>
Output: 1, 56, 23
Input <56>
Output: "Apple"
我想要做的是一个写入目标进程 STDIN,然后从它的 STDOUT 读取输出的程序。为此,我主要从那里获取代码:
Creating a Child Process with Redirected Input and Output (Windows) - MSDN
唯一的问题是,为了从子进程读取,我首先需要关闭用于写入它的父进程的句柄,这意味着我不能使用子进程的输出来往里面写更多东西。
这是从 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 陷入死锁。
任何帮助将不胜感激,谢谢!
ReadFile(..., BUFSIZE)
表示 "wait until the program writes BUFSIZE
bytes, or closes it's end of the pipe"。该程序只写入少量字节,然后等待您未提供的更多输入。如果你关闭写管道,它知道没有更多的输入,然后退出,此时你的 ReadFile 知道没有更多的输入和 returns。您需要找到一种方法来只读取管道中的字节数。
这里的神奇之处是 PeekNamedPipe,它告诉您程序输出了多少数据,因此您可以无阻塞地读取多少数据。请注意,您必须每隔一段时间检查一次,看看自上次检查以来程序是否写入了更多字节。