#winapi #stdout #stderr #readfile #io-redirection
#winapi #стандартный вывод #stderr #readfile #io-перенаправление
Вопрос:
Я пытаюсь создать дочерний процесс, выполняющий любую exe-команду, и перенаправить все его stdio и stderr в мой родительский процесс через анонимный канал. Но когда мой родительский процесс пытается выполнить ReadFile() на конце чтения анонимного канала после завершения дочернего процесса, он просто блокируется вместо возврата ошибки.
Вот код:
#include "windows.h"
//==================================================
void createChildPipes(PHANDLE phRead, PHANDLE phWrite){
SECURITY_ATTRIBUTES sa={sizeof(SECURITY_ATTRIBUTES) ,NULL,TRUE};
if ( !CreatePipe(phRead, phWrite, amp;sa, 2048) ) { //... }
}
//==================================================
void setupStartupInfo(LPSTARTUPINFO lpsi, HANDLE hStdOutput, HANDLE hStdError) {
lpsi->cb = sizeof(STARTUPINFO);
lpsi->lpReserved=NULL;
lpsi->lpDesktop=NULL;
lpsi->lpTitle=NULL;
lpsi->dwX=0;
lpsi->dwY=0;
lpsi->dwXSize=200;
lpsi->dwYSize=500;
lpsi->dwFlags=STARTF_USESTDHANDLES;
lpsi->cbReserved2=0;
lpsi->lpReserved2=NULL;
lpsi->hStdInput=GetStdHandle(STD_INPUT_HANDLE);
lpsi->hStdError= hStdError;
lpsi->hStdOutput=hStdOutput;
}
//==================================================
void createChildProcess(PHANDLE phOutRead, PHANDLE phOutWrite, PHANDLE phErrRead, PHANDLE phErrWrite) {
TCHAR name[]=_T("cl.exe");
createChildPipes(phOutRead, phOutWrite);
STARTUPINFO si;
setupStartupInfo(amp;si, *phOutWrite, *phOutWrite);
PROCESS_INFORMATION pi;
if (!CreateProcess(NULL, name, NULL, NULL, true, 0, NULL, NULL, amp;si, amp;pi)) { //...}
}
//==================================================
void _tmain(int argc, _TCHAR* argv[]){
HANDLE hOutRead, hOutWrite, hErrRead, hErrWrite;
createChildProcess(amp;hOutRead, amp;hOutWrite, amp;hErrRead, amp;hErrWrite) ;
char buf[10];
BOOL readState;
for (;;) {
DWORD dwBytesRead;
memset(buf, '', sizeof(buf));
readState=ReadFile(hOutRead, buf, sizeof(buf)-2 , amp;dwBytesRead, NULL);
printf("%s", buf);
if (!readState)
break;
}
}
Это то, что делает мой код. Мой _tmain() создает дочерний процесс (я использую VC cl.exe команда в качестве теста) и перенаправляет ее stdio и stderr на ДЕСКРИПТОР записи анонимного канала. Мой родительский процесс считывает данные из ДЕСКРИПТОРА чтения того же канала.
Они печатаются my _tmain(), показывая, что канал может взаимодействовать между родительско-дочерними процессами. Это то, что мы ожидаем увидеть, если мы введем cl.exe в командной строке без каких-либо аргументов. Обратите внимание на своеобразное поведение cl.exe что первые 2 строки взяты из stderr из cl.exe и последняя строка взята из стандартного вывода.
Microsoft (R) 32-bit C/C Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
usage: cl [ option... ] filename... [ /link linkoption... ]
Теперь о проблеме, строка:
readState=ReadFile(hOutRead, buf, sizeof(buf)-2 , amp;dwBytesRead, NULL);
в _tmain() блокируется после дочернего элемента cl.exe процесс завершен. Но я ожидаю, что вызов ReadFile() вернется со статусом ошибки ERROR_BROKEN_PIPE и завершит родительский цикл вместо блокировки вызова ReadFile().
Почему ReadFile() блокируется при чтении анонимного канала?
Ответ №1:
Вы забыли закрыть дескрипторы канала в родительском процессе, поэтому канал еще не полностью закрыт.