Есть консольное приложение, и я пытаюсь его вывод представить в виде объекта с одним методом Read (метод не обязан возвращать все запрашиваемые данные, но должен вернуть хотя бы 1 байт, 0 байт — конец потока).
| Код |
| function TdecStream.Read(AData: Pointer; ASize: Cardinal; AProcessedSize: PCardinal): HRESULT;
var
ExitCode: DWORD;
PipeAvailableSize: DWORD;
Read: DWORD;
begin
try
Result := S_OK;
if Assigned(AProcessedSize) then
AProcessedSize^ := 0;
if ASize = 0 then Exit;
if not PeekNamedPipe(FChildStd_OUT_RD, nil, 0, nil, @PipeAvailableSize, nil) then
RaiseLastOSError;
if not GetExitCodeProcess(ProcessInformation.hProcess, ExitCode) then
RaiseLastOSError;
if ExitCode <> STILL_ACTIVE then
if PipeAvailableSize = 0 then Exit;
// Здесь есть гонка
if PipeAvailableSize = 0 then
PipeAvailableSize := 1;
if ASize > PipeAvailableSize then
ASize := PipeAvailableSize;
if not ReadFile(FChildStd_OUT_RD, AData^, ASize, Read, nil) then
RaiseLastOSError;
if Assigned(AProcessedSize) then
AProcessedSize^ := Read;
except
on E: Exception do
Result := HResultFromException(E);
end;
end;
|
| |
Но есть проблема, которую я ни как не могу решить. Если дочерний процесс завершился, то ReadFile зависает навсегда, поскольку ждет данные из pipe. В коде есть попытка отловить статус STILL_ACTIVE, но возникает гонка, в которой процесс завершается после запроса состояния. Как мне корректно узнать, что в в pipe больше нет и не будет данных.