Перенаправление ввода / вывода из дочернего процесса с использованием каналов — winapi

Я работаю с приложением, которое предлагает API, чтобы сценарии было проще. По сути, когда вы пишете правильный ввод, он выводит ответ. Я хотел бы использовать этот вывод для отправки большего ввода, например:

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

То, что я хотел бы сделать, — это программа, которая записывает в целевой процесс STDIN, а затем считывает выходные данные из его STDOUT. Для этого я в основном взял код оттуда:

Создание дочернего процесса с перенаправленным вводом и выводом (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 застрянет в тупике.

Любая помощь будет оценена, спасибо!

2

Решение

ReadFile(..., BUFSIZE) означает «ждать, пока программа пишет BUFSIZE байт, или закрывает конец канала «. Программа записывает только небольшое количество байтов, а затем ожидает большего ввода, который вы не предоставляете. Если вы закроете канал записи, он знает, что больше нет ввода, и завершает работу, после чего ваш ReadFile знает, что больше нет ввода и возврата. Вам нужно найти способ прочитать только столько байтов, сколько находится в канале.

Волшебная часть здесь PeekNamedPipe, который сообщает вам, сколько данных выводит программа, и, следовательно, сколько вы можете прочитать без блокировки. Обратите внимание, что вам придется периодически проверять, записывает ли программа больше байтов с момента последней проверки.

2

Другие решения


По вопросам рекламы [email protected]