codice:
procedure TRedirector.ReadStdOutput;
var
  BytesRead: DWord;
  Buffer: Pointer;
begin
  GetMem(Buffer, FAvailable);
  try
    if not ReadFile(FPipeOutput.hRead, Buffer^, FAvailable, BytesRead, nil) then
    begin
      FThread.Terminate;
      WinError('Error reading STDOUT pipe : ');
    end;
    if Assigned(FOnData) then
      FOnData(Self, Buffer, BytesRead);
  finally
    FreeMem(Buffer);
  end;
end;

procedure TRedirector.ReadStdError;
var
  BytesRead: DWord;
  Buffer: Pointer;
begin
  GetMem(Buffer, FAvailable);
  try
    if not ReadFile(FPipeError.hRead, Buffer^, FAvailable, BytesRead, nil) then
    begin
      FThread.Terminate;
      WinError('Error reading STDERR pipe : ');
    end;
    if Assigned(FOnErrorData) then
      FOnErrorData(Self, Buffer, BytesRead);
  finally
    FreeMem(Buffer);
  end;
end;

procedure TRedirector.ProcessTerminated;
begin
  FThread.Terminate;
  ClosePipes;
  CloseHandle(FProcessInfo.hProcess);
  CloseHandle(FProcessInfo.hThread);
  FillChar(FProcessInfo, SizeOf(FProcessInfo), 0);
  if Assigned(FOnTerminated) then FOnTerminated(Self);  //-- moved from 2nd line to last line! (hdo, 2001-09-02)
end;

////////////////////////////////////////////////////////////////////////////////
// Public methods
////////////////////////////////////////////////////////////////////////////////

procedure TRedirector.Terminate(dwExitCode: Integer);
begin
  if Running
    then
    TerminateProcess(ProcessHandle, dwExitCode)
  else
    Error('Cannot Terminate an inactive process');
end;

procedure TRedirector.Execute;
var
  StartupInfo: TStartupInfo;
  szExecutable, szCommandline, szDirectory: PChar;
  liPriorityClass: Integer;
begin
  if Running then Error('Process is already active');
  if Trim(CommandLine) = '' then Error('No commandline to run');
  FLastData := false;
  try
    CreatePipes;

    FillChar(StartupInfo, SizeOf(StartupInfo), 0);
    StartupInfo.cb := SizeOf(StartupInfo);

    StartupInfo.wShowWindow := FShowWindow;
    StartupInfo.hStdInput := FPipeInput.hRead;
    StartupInfo.hStdOutput := FPipeOutput.hWrite;
    StartupInfo.hStdError := FPipeError.hWrite;
    StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;

    if Trim(Executable) = '' then
      szExecutable := nil
    else
      szExecutable := PChar(FExecutable);
    if Trim(Commandline) = '' then
      szCommandline := nil
    else
      szCommandline := PChar(FCommandline);
    if Trim(Directory) = '' then
      szDirectory := nil
    else
      szDirectory := PChar(FDirectory);

    liPriorityClass := 0;
    case FInitialPriority of
      pcIdle: liPriorityClass := IDLE_PRIORITY_CLASS;
      pcNormal: liPriorityClass := NORMAL_PRIORITY_CLASS;
      pcHigh: liPriorityClass := HIGH_PRIORITY_CLASS;
      pcRealtime: liPriorityClass := REALTIME_PRIORITY_CLASS;
    end;

    if CreateProcess(szExecutable, szCommandline, nil, nil, true,
      (CREATE_DEFAULT_ERROR_MODE and Integer(FDefaultErrorMode))
      or (CREATE_SUSPENDED and Integer(FStartSuspended) or liPriorityClass),
      Environment, szDirectory, StartupInfo, FProcessInfo)
      then
    begin
      FThread := TRedirectorThread.Create(Self);
    end
    else
      WinError('Error creating process : ');
  except
    on Exception do
    begin
      ClosePipes;
      CloseHandle(FProcessInfo.hProcess);
      CloseHandle(FProcessInfo.hThread);
      FillChar(FProcessInfo, SizeOf(FProcessInfo), 0);
      raise;
    end;
  end;
end;

procedure TRedirector.SendData(Buffer: Pointer; BufferSize: Integer);
var
  BytesWritten: DWord;
begin
  if not Running then Error('Can''t send data to an inactive process');
  if not WriteFile(FPipeInput.hWrite, Buffer^, BufferSize, BytesWritten, nil)
    then WinError('Error writing to STDIN pipe : ');
end;

procedure TRedirector.SendText(s: string);
begin
  SendData(PChar(s), Length(s));
end;

destructor TRedirector.Destroy;
begin
  if Running and KillOnDestroy then
  begin
    FOnTerminated := nil;
    FThread.Terminate;
    Terminate(0);
  end;
  inherited Destroy;
end;

constructor TRedirectorThread.Create(ARedirector: TRedirector);
begin
  FRedirector := ARedirector;
  inherited Create(false);
end;

procedure TRedirectorThread.Execute;
var
  Idle: Boolean;
begin
  FreeOnTerminate := true;
  repeat
    Idle := true;

    //-- check for StdOutout-Pipe
    if PeekNamedPipe(FRedirector.FPipeOutput.hRead, nil, 0, nil,
      @FRedirector.FAvailable, nil) and (FRedirector.FAvailable > 0) then
    begin
      Synchronize(FRedirector.ReadStdOutput);
      Idle := false;
    end;

    //-- check for StdErr-Pipe
    if PeekNamedPipe(FRedirector.FPipeError.hRead, nil, 0, nil,
      @FRedirector.FAvailable, nil) and (FRedirector.FAvailable > 0) then
    begin
      Synchronize(FRedirector.ReadStdError);
      Idle := false;
    end;

    //-- check if process terminated
    if Idle and (WaitForSingleObject(FRedirector.ProcessHandle,
      100) = WAIT_OBJECT_0) then
    begin
      FRedirector.FLastData := true;

      //-- process has finished, read pipes until they are empty
      repeat
        Idle := true;

        //-- check for StdOutout-Pipe a last time
        if PeekNamedPipe(FRedirector.FPipeOutput.hRead, nil, 0, nil,
          @FRedirector.FAvailable, nil) and (FRedirector.FAvailable > 0) then
        begin
          Synchronize(FRedirector.ReadStdOutput);
          Idle := false;
        end;

        //-- check for StdErr-Pipe a last time
        if PeekNamedPipe(FRedirector.FPipeError.hRead, nil, 0, nil,
          @FRedirector.FAvailable, nil) and (FRedirector.FAvailable > 0) then
        begin
          Synchronize(FRedirector.ReadStdError);
          Idle := false;
        end;

      until Idle;

      //-- self-destruct
      if not Terminated then Synchronize(FRedirector.ProcessTerminated);
    end;

  until Terminated and Idle;
end;

end.
Salva il tutto in un file redirect.pas ed usa i metodi della classe TRedirector.