То, что я хотел бы сделать, аналогично тому, что Visual Studio делает в своем окне вывода или других редакторах в их окнах инструментов: запустить другой процесс B из моего процесса A и записать его вывод stdout / stderr.
До сих пор я работал с CreatePipe()
, но по какой-то причине вывод B не приходит в B сразу после записи. Он ведет себя как заполнение буфера какого-то рода, и когда он заполнен, все содержимое буфера сразу попадает в A. Я написал свою собственную тестовую программу, которая что-то выводит и делает fflush(stdout)
сразу после этого. Затем вывод напрямую приходит к A. Но я не могу изменить код всех процессов B, которые я хотел бы использовать таким образом. Попытка промыть трубу от А также не работает.
Как это должно работать?
Мой код инициализации и код потребления:
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
err = CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &sa, stdouthistory);
if (err == 0)
return 1;
err = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
GetCurrentProcess(), &hChildStdoutRdDup , 0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (err == 0)
return 3;
CloseHandle(hChildStdoutRd);
DWORD a, b, c;
a = PIPE_READMODE_BYTE | PIPE_NOWAIT;
b = 0;
c = 0;
SetNamedPipeHandleState(hChildStdoutRdDup, &a, &b, &c);
err = CreatePipe(&hChildStdinRd, &hChildStdinWr, &sa, stdinhistory);
if (err == 0)
return 1;
err = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
GetCurrentProcess(), &hChildStdinWrDup , 0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (err == 0)
return 4;
CloseHandle(hChildStdinWr);
a = PIPE_READMODE_BYTE | PIPE_NOWAIT;
b = 0;
c = 0;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.wShowWindow = SW_SHOW;
si.hStdOutput = hChildStdoutWr;
si.hStdError = hChildStdoutWr;
si.hStdInput = hChildStdinRd;
ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
err = CreateProcess(0, this->cmdline, 0, 0, true, CREATE_NO_WINDOW, 0, 0, &si, &pi);
if (err == 0)
return 4;
Потребление:
DWORD avail;
unsigned int ofs = 0;
if (PeekNamedPipe(hChildStdoutRdDup, NULL, 0, NULL, &avail, NULL))
{
if (avail != 0)
{
int err = ReadFile(hChildStdoutRdDup, s + ofs, slen, &threadbuffern, 0);
// Consume ...
}
}
Edit:
Я только что нашел этот вопрос: Постоянно читал из STDOUT внешнего процесса в Ruby . Это та же проблема, но в контексте Ruby. К сожалению, решение состояло в том, чтобы использовать некоторую библиотеку Ruby, которая просто заставляет ее работать. Как эта библиотека делает это? Что эквивалентно в Win32 / C ++?