Есть дочерний консольный процесс. Мой процесс пишет в его input handle и читает из его output handle и handle вывода ошибок через анонимные пйпы. При чтении таким образом DWORD written; while(true) { written=0; RtlZeroMemory(ReadBuf,4048); // ReadBuf - массив из 4048 байтов if((!ReadFile(hRead,ReadBuf,4048,&written,NULL))) { errmsg(); return; } if(!written) { return; } if(!ReadBuf[0]) { return; } else { /* Чтение из буфера */ } } программа виснет, вероятнее всего потому, что ReadFile натыкается на то, что консоль ждёт ввода, после чего останавливается. Как сделать так, чтоб программа не висла, а останавливалвсь? То есть как узнать завершил ли дочерний прцесс обработку введённого или нет?
Твоя программа ждет пока дочерний процесс выведет 4048 байт. В MSDN все описано и есть пример, как работать с анонимными каналами(pipes). То есть как узнать завершил ли дочерний прцесс обработку введённого или нет? Такого сделать нельзя. Но можно узнать сколько на данной момент байт было выведено на паток. PeekNamedPipe(hRead,nul, 0, &bread, &avail, nul); if (avail>0) { Читаем данные } В avail лижит число байт выведенных на поток. Проверяй на закрытие потока. exit=0; GetExitCodeProcess(pin.hProcess,exit); if (exit <> STILL_ACTIVE) { выходим из вечного цыкла }
q_q Процесс дочерний мой. Pavia То есть только с именованными пайпами или эта функция(PeekNamedPipe) и для анонимных работает?
Ага, прочёл, каюсь. Но вроде бы оно не до конца решает проблему ибо придётся ждать какое-то фиксированное время после того,как avail станет 0, а потом не обращать внимание на попытки дочернего процесса вывести ещё чего-н. Или я опять что-то пропустил?
Что-то я не понял. avail станет равным 0 после вызова ReadFile, которая и опустошит буфер трубы (pipe). . Используем ReadFile с заполненной структурой OVERLAPPED. В этом случае поток останавливается до тех пор, пока в трубе (pipe) не появятся данные. Этот момент сигнализируется двумя событиями: возвращается управление из ReadFile и сигнализируется событие (hEvent) в OVERLAPPED. Но нет гарантии, что консольная программа что-то выдаст и поток проснётся. Чтобы избежать этого, с PeekNamedPipe можно сделать так: Код (Text): // 1) посылаем данные в консоль. // нужно точно узнать, что именно ожидает консольная программа: // - некий завершающий символ (';','\r\n','\n'...) // - нажатие какой-то клавишы (редко, на бывает) bResult = WriteFile(hWrite,lpBuf,dwBuf,lpWritten,NULL); nAvail = 0; // пока не появятся данные в трубе while(!nAvail){ // делаем что-то полезное (следим за временем), просто спим Sleep(200); // проверяем наличие данных в трубе bResult = PeekNamedPipe(hRead,NULL, 0, &nRead, &nAvail, NULL); } // на то случай, если вышли из цикла по своей надобности if (nAvail){ // здесь читается буфер фиксированного размера // можно также читать сразу весь буфер трубы: // ReadFile(hRead,lpBuf,nAvail,&nRead,NULL); Result = ReadFile(hRead,lpBuf,dwBuf,&nRead,NULL); } Это зависит от самого процесса — как именно он завершает обработку введённого: начинает выводить результат сразу весь или потихоньку по чуть-чуть (например, показывая текущее состояние обработки). Средствами системы это не проверить, здесь нужно самому просматривать полученные данные на завершающий флаг (специальный символ/строку/символы переноса строки), проверять, не остались ли ещё невыбранные данные, если наш буфер оказался мал. Но все эти условия зависят от самого консольного приложения…
Привидённый выше пример кода меня несколько смущает, ибо прграмма так тоже зависнет, если консоль остановиться и будет ждать ввода.
Неужели я написал что-то такое, что настолько ошеломило всех своей гениальностью или тупостью, что никто не может ничего по этому поводу сказать?