Recent

Author Topic: Tprocess capturing progress  (Read 842 times)

domasz

  • Hero Member
  • *****
  • Posts: 553
Tprocess capturing progress
« on: October 10, 2024, 05:34:40 pm »
A command line application does an operation and prints a progress bar as X%.
It prints that value in the same position on screen- erases previous value and puts new one in the same place.

How can I use TProcess to capture that values? Normal way with pipes and a loop just captures how the console looks when it gets to 100%.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8045
Re: Tprocess capturing progress
« Reply #1 on: October 10, 2024, 06:45:35 pm »
You'll need to capture all output, and interpret the ANSI (or whatever) escape sequences that handle screen positioning.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: Tprocess capturing progress
« Reply #2 on: October 10, 2024, 07:09:27 pm »
Hi
I use this procedure to move the cursor in console:
Code: Pascal  [Select][+][-]
  1. procedure MoveCursor(X, Y: integer);
  2. begin
  3.   Write(Format(#27'[%d;%dH', [Y, X])); //<- ansi esc codes
  4. end;
Maybe you can find this sequence in tprocess' output stream...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

domasz

  • Hero Member
  • *****
  • Posts: 553
Re: Tprocess capturing progress
« Reply #3 on: October 10, 2024, 07:22:16 pm »
I use this code from the Wiki and it captures no such sequences
Code: Pascal  [Select][+][-]
  1. const
  2.   BUF_SIZE = 2; // Buffer size for reading the output in chunks
  3.  
  4. var
  5.   AProcess     : TProcess;
  6.   OutputStream : TStream;
  7.   BytesRead    : longint;
  8.   Buffer       : array[1..BUF_SIZE] of byte;
  9.  
  10. procedure Run;
  11. begin
  12.   AProcess := TProcess.Create(nil);
  13.  
  14.   AProcess.Executable := 'prog.exe';
  15.   AProcess.Parameters.Add('p=1');
  16.  
  17.   AProcess.Options := [poUsePipes,poStderrToOutPut];
  18.  
  19.   AProcess.Execute;
  20.  
  21.   OutputStream := TMemoryStream.Create;
  22.  
  23.   repeat
  24.     BytesRead := AProcess.Output.Read(Buffer, BUF_SIZE);
  25.     OutputStream.Write(Buffer, BytesRead)
  26.   until BytesRead = 0;
  27.  
  28.   AProcess.Free;
  29.  
  30.   with TFileStream.Create('output.txt', fmCreate) do
  31.   begin
  32.     OutputStream.Position := 0;
  33.     CopyFrom(OutputStream, OutputStream.Size);
  34.     Free
  35.   end;
  36.  
  37.   with TStringList.Create do
  38.   begin
  39.     OutputStream.Position := 0;
  40.     LoadFromStream(OutputStream);
  41.  
  42.     Free
  43.   end;
  44.  
  45.   OutputStream.Free;
  46. end;

Bart

  • Hero Member
  • *****
  • Posts: 5469
    • Bart en Mariska's Webstek
Re: Tprocess capturing progress
« Reply #4 on: October 10, 2024, 07:30:06 pm »
If "prog.exe" is a fpc program using Crt unit, I think you're out of luck.

Bart

domasz

  • Hero Member
  • *****
  • Posts: 553
Re: Tprocess capturing progress
« Reply #5 on: October 10, 2024, 10:17:04 pm »
I found the application has a switch to force it to render progress normally to stdout.

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1254
Re: Tprocess capturing progress
« Reply #6 on: October 11, 2024, 05:27:32 am »
Hello,
is  your console application writes on console like that you can see in my attachment ?
code :
Code: Pascal  [Select][+][-]
  1. program percentage;
  2. uses sysutils;
  3. var
  4.   total: integer;
  5.   current: integer;
  6.  
  7. begin
  8.   total := 100;
  9.   current := 0;
  10.  
  11.   writeln('in progress...');
  12.   while current < total do
  13.   begin
  14.     current := current + 10;
  15.     write('[');
  16.     write(current);
  17.     write('%]');
  18.     write(#13);
  19.     flush(output);
  20.     Sleep(1000);
  21.   end;
  22.   writeln('Terminated!');
  23. end.
                 

Where to you want to capture output ? Gui application ? Console Application ?

Friendly, J.P
« Last Edit: October 11, 2024, 05:52:48 am by Jurassic Pork »
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

domasz

  • Hero Member
  • *****
  • Posts: 553
Re: Tprocess capturing progress
« Reply #7 on: October 11, 2024, 11:15:38 am »
It is something like this. You know how to capture in this case?

MarkMLl

  • Hero Member
  • *****
  • Posts: 8045
Re: Tprocess capturing progress
« Reply #8 on: October 11, 2024, 11:20:27 am »
You need to look at /everything/ that's being piped out of the program via the TProcess. I suspect that you think you're only seeing the final state, when in actual fact it is (by careful design) overlaying the older stuff.

If nothing relevant is being piped out, i.e. it's using the Crt unit or similar, then there's not much you can do.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

domasz

  • Hero Member
  • *****
  • Posts: 553
Re: Tprocess capturing progress
« Reply #9 on: October 11, 2024, 01:11:57 pm »
Here's the working code

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Run;
  2. const  BUF_SIZE = 50;
  3. var AProcess: TProcess;
  4.     OutputStream: TStream;
  5.     BytesRead: longint;
  6.     Buffer: array[1..BUF_SIZE] of Char;
  7.     Buffer2: String;
  8.     P, size: Integer;
  9.     i: Integer;
  10.     Percent: String;
  11. begin
  12.   AProcess := TProcess.Create(nil);
  13.  
  14.   AProcess.Executable := '7za.exe';
  15.   AProcess.Parameters.Add('a');
  16.   AProcess.Parameters.Add('-t7z');
  17.   AProcess.Parameters.Add(OutputArchiveName);
  18.   AProcess.Parameters.Add(FilenameToCompress);
  19.   AProcess.Parameters.Add('-m0=ppmd');
  20.   AProcess.Parameters.Add('-mx=9');
  21.   AProcess.Parameters.Add('-bsp1'); //switch to show %
  22.  
  23.   AProcess.Options := [poUsePipes,poNoConsole];
  24.  
  25.   AProcess.Execute;
  26.  
  27.   OutputStream := TMemoryStream.Create;
  28.  
  29.   repeat
  30.     BytesRead := AProcess.Output.Read(Buffer, BUF_SIZE);
  31.     OutputStream.Write(Buffer, BytesRead);
  32.     OutputStream.Position := 0;
  33.  
  34.     Size := OutputStream.Size;
  35.     SetLength(Buffer2, Size);
  36.     OutputStream.Read(Buffer2[1], Size);
  37.     OutputStream.Position := Size;
  38.  
  39.     //get percent
  40.     P := RPos('%', Buffer2);
  41.     for i:=P-1 downto 1 do
  42.       if Buffer2[i] = ' ' then begin
  43.         Percent := Trim(Copy(Buffer2, i, P-i));
  44.         break;
  45.       end;
  46.  
  47.     Application.ProcessMessages;
  48.  
  49.     ProgressBar1.Position := StrToIntDef(Percent, 0);
  50.  
  51.     if Cancel then break;
  52.   until BytesRead = 0;
  53.  
  54.   if Cancel then
  55.   AProcess.Terminate(0);
  56.  
  57.   AProcess.Free;
  58.  
  59.   OutputStream.Free;
  60. end;  

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1254
Re: Tprocess capturing progress
« Reply #10 on: October 12, 2024, 03:31:05 am »
Hello,
It is something like this. You know how to capture in this case?
code for this :
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics,
  9.   Dialogs, StdCtrls, LazUtf8, Processutils;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     BtGo: TButton;
  17.     MemConsole: TMemo;
  18.     procedure BtGoClick(Sender: TObject);
  19.   private
  20.  
  21.   public
  22.     procedure ProcessOutput(Sender:TProcessEx; output:string);
  23.     procedure ProcessError(Sender:TProcessEx; {%H-}IsException:boolean);
  24.   end;
  25.  
  26. var
  27.   Form1: TForm1;
  28.  
  29. implementation
  30.  
  31. {$R *.lfm}
  32.  
  33. { TForm1 }
  34.  
  35. procedure TForm1.BtGoClick(Sender: TObject);
  36. var Proc: TProcessEx;
  37. begin
  38.    try
  39.    Proc := TProcessEx.Create(nil);
  40.    Proc.Executable := '/home/jurassic/Lazarus/projets/biglines_output/biglines';
  41.    Proc.OnErrorM:=@(ProcessError);
  42.    Proc.OnOutputM:=@(ProcessOutput);
  43.    Proc.Execute();
  44.    finally
  45.      Proc.Free;
  46.    end;
  47. end;
  48.  
  49. procedure TForm1.ProcessError(Sender: TProcessEx; IsException: boolean);
  50. begin
  51.    MemConsole.Lines.Append('Error ! ' + Sender.ExceptionInfo);
  52. end;
  53.  
  54. procedure TForm1.ProcessOutput(Sender: TProcessEx; output : String);
  55. begin
  56.  MemConsole.Lines.Text :=  MemConsole.Lines.Text + output;
  57.   // if you have encoding problem on windows
  58.   //MemConsole.Lines.Text := MemConsole.Lines.Text + ConsoleToUtf8(output);
  59.   // for automatic scrolling
  60.   MemConsole.SelStart := Length(MemConsole.Lines.Text)-1;
  61.   MemConsole.SelLength:=0;
  62. end;
  63.  
  64. end.

unit processutils is here from fpcupdeluxe project.

Friendly, J.P
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

domasz

  • Hero Member
  • *****
  • Posts: 553
Re: Tprocess capturing progress
« Reply #11 on: October 14, 2024, 05:38:59 pm »
Thanks!

 

TinyPortal © 2005-2018