Recent

Author Topic: Interactive process with TProcess  (Read 6353 times)

Leledumbo

  • Hero Member
  • *****
  • Posts: 8757
  • Programming + Glam Metal + Tae Kwon Do = Me
Interactive process with TProcess
« on: November 28, 2008, 05:11:18 am »
I'd like to create some kind of command prompt, embedded in my project's form. I use CmdLine package (with TCmdBox component) and I run the process with TProcess. I use example given here as the skeleton. Since I want the process to be interactive, I can't just buffer everything and flush it once in the end. That wouldn't make sense when the process has this kind of statement:
Code: [Select]

...
Write('What''s your name?');
ReadLn(Name);
...

The question won't be displayed while ReadLn stays blocking, users might even think that a deadlock has occured. Anyway, here's the complete code (without input processing):
Code: [Select]

procedure TMainForm.CmdBoxInput(ACmdBox: TCmdBox; InputStr: String);
const
  READ_BYTES = 2048;
var
  CmdProcess: TProcess;
  MemStr: TMemoryStream;
  StrList: TStringList;
  n: Integer;
  ErrMsg: PChar;
begin
  try
    CmdProcess:=TProcess.Create(nil);
    MemStr:=TMemoryStream.Create;
    StrList:=TStringList.Create;
    MemStr.SetSize(READ_BYTES);
    with CmdProcess do begin
      CommandLine:=InputStr;
      Options:=[poUsePipes,poStderrToOutPut];
      ShowWindow:=swoHide;
      Execute;
      while Running do begin
        n:=Output.Read(MemStr.Memory^,READ_BYTES);
        if n>0 then begin
          StrList.LoadFromStream(MemStr);
          CmdBox.Write(StrList.Text); // CmdBox.WriteStream causes Access Violation
          MemStr.Clear;
        end else
          Sleep(100);
      end;
    end;
  except
    on e: EProcess do begin
      {$IFDEF Windows}
      FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM,
        nil,GetLastError,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
        @ErrMsg,0,nil
      );
      {$ELSE}
      ErrMsg:=@e.Message[1];
      {$ENDIF}
      CmdBox.WriteLn(ErrMsg);
      SetCmdBoxPrompt(FPath+'>');
      Exit;
    end;
  on e: Exception do begin
      MessageDlg('Error',e.Message,mtError,[mbOK],0);
      Exit;
    end;
  end;
  repeat
    n:=CmdProcess.Output.Read(MemStr.Memory^,READ_BYTES);
    if n>0 then CmdBox.WriteStream(MemStr);
  until n<=0;
  StrList.Free;
  MemStr.Free;
  CmdProcess.Free;
  SetCmdBoxPrompt(FPath+'>');
end;

But it fails for any program that requires interaction or has large output. I don't really know how to use TMemoryStream and only know a common use of TProcess, perhaps I misunderstood something here.

 

TinyPortal © 2005-2018