Recent

Author Topic: can tprocess be made to do this?  (Read 2608 times)

toby

  • Sr. Member
  • ****
  • Posts: 251
can tprocess be made to do this?
« on: January 31, 2023, 09:24:20 pm »
Hi

can tprocess be made to be used like this to get stdout in the program into the aprocess.output

...
aprocess := tprocess.create(nil);
astringlist := tstringlist.create;
aprocess.options := aprocess.options + [powaitonexit, pousepipes];

writeln('can i get this to go to aprocess.output?');

astringlist.loadfromstream(aprocess.output); //
...

TRon

  • Hero Member
  • *****
  • Posts: 2435
Re: can tprocess be made to do this?
« Reply #1 on: February 01, 2023, 02:27:12 pm »
Could you elaborate ?

Right now the statements as written do not make any sense to me because you can catch the output from a command executed by TProcess f.e. in a stringlist and when that stringlist is returned you can add strings to that list (in principle that what you describe: "can i get this to go to aprocess.output").

However doing so does absolutely nothing other then simply adding strings to a stringlist.... and I assume that is not the functionality that you are looking for.

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: can tprocess be made to do this?
« Reply #2 on: February 01, 2023, 05:33:27 pm »
Toby, i thought I already showed you that? (poUsePipes). Does it not work for you?
Show me in a few lines of code, but as complete as possible, what you are trying to achieve.
« Last Edit: February 01, 2023, 06:13:26 pm by Thaddy »
Specialize a type, not a var.

toby

  • Sr. Member
  • ****
  • Posts: 251
Re: can tprocess be made to do this?
« Reply #3 on: February 01, 2023, 10:24:59 pm »

instead of executing an external program i want to get the writeln to go into the aprocess.output

TRon

  • Hero Member
  • *****
  • Posts: 2435
Re: can tprocess be made to do this?
« Reply #4 on: February 02, 2023, 06:54:04 am »
instead of executing an external program i want to get the writeln to go into the aprocess.output
1. You execute an external program using tprocess in order to access aprocess.output. Without the former there is no latter.

2. You explicitely mention that you wish to writeln to aprocess.out which does not make any sense to me because aprocess.output is a pipe (say buffer) that /retrieves/ all output from aprocess (in layman terms: if you have program x is executed by tprocess and that uses writeln's then the writeln's of program/process x (which normally end up in the terminal) will be written (because output is redirected) to aprocess.output.

Ofc. you can add your own strings/writeln's to that /retrieved/ output from program/process x but it is useless other then that you have adjusted the output from program/process x.

Did you perhaps meant that you wish to tell something to program/process x so that program/process x receives your writeln's as if you would have typed it with the keyboard in a terminal window ?

If so, then for that you would have to write to the input pipe of the process (it can perhaps be confusing but the output of your program is the input for process/program x, and vice verse).

If indeed the case then the following link contains an example of such method: https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/examples/process/

I have no idea if Thaddy showed you something similar but if he did then you can ofc. use his code as example as well.

Apologies in case this post comes across as being written by a 2 year old but I simply fail to find a better method to explain.



kapibara

  • Hero Member
  • *****
  • Posts: 610
Re: can tprocess be made to do this?
« Reply #5 on: February 02, 2023, 08:47:11 am »
Not sure I understand fully what you mean, but by chance I saw in another topic that you also use Python. Thats how I ran my processes in an app a few years ago.

It was possible to send strings to the process and have process response back to the fpc program or Lazarus gui app. Continously, all day long if you want. I found that TAsyncProcess was the best for this game of ping/pong between my GUI application and the process. TAsyncProcess was run from a separate thread reading incoming strings from the process. The external program itself was run within a python script.

Basically:
Application with TThread -> TAsyncProcess -> Python script -> External program.

Maybe this method is overkill here, but try start coding something and we'll help you along. Here's a bit code to send and receive data from the thread to start with.

Code: Pascal  [Select][+][-]
  1.   TProcessThread = class(TThread)
  2.   private
  3.     FAsyncProcess: TAsyncProcess;
  4.   public
  5.     constructor Create;
  6.     procedure ProcessReadData(Sender: TObject);
  7.     procedure SendMessageToProcess(s: string);
  8.   ...
  9.   end;
Code: Pascal  [Select][+][-]
  1. constructor TProcessThread.Create;
  2. begin
  3.   FreeOnTerminate:=True;
  4.   FAsyncProcess:= TAsyncProcess.Create(nil);
  5.   FAsyncProcess.OnReadData:=@ProcessReadData;
  6.   FAsyncProcess.Options := FAsyncProcess.Options + [poUsePipes, poStderrToOutPut];
  7.   inherited Create(True);
  8. end;
Code: Pascal  [Select][+][-]
  1. procedure TProcessThread.ProcessReadData(Sender: TObject);
  2. var
  3.   s: string = '';
  4.   sa: TStringArray;
  5.   BytesAvailable:integer;
  6. begin
  7.   try
  8.     BytesAvailable:= TAsyncProcess(Sender).Output.NumBytesAvailable;
  9.     setlength(s, BytesAvailable);
  10.     TAsyncProcess(Sender).Output.Read(s[1], BytesAvailable);
  11.     //Split output by cr/lf into separate strings
  12.     sa:= s.split(#13#10);
  13.     for s in sa do
  14.     begin
  15.       if s.Length > 0 then
  16.       begin
  17. //        SendMessage(s);
  18.       end;
  19.     end;
  20.    except
  21.      Application.MessageBox('TProcessThread.ProcessReadData',
  22.                              PChar(TimeToStr(Now)));
  23.   end;
  24. end;
Code: Pascal  [Select][+][-]
  1. procedure TProcessThread.SendMessageToProcess(s: string);
  2. begin
  3.   if Assigned(FAsyncProcess) and FAsyncProcess.Running then
  4.   begin
  5.     s:=s + LineEnding;
  6.     FAsyncProcess.Input.WriteBuffer(s[1], Length(s) );
  7.   end;
  8. end;
« Last Edit: February 02, 2023, 09:03:33 am by kapibara »
Lazarus trunk / fpc 3.2.2 / Kubuntu 22.04 - 64 bit

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: can tprocess be made to do this?
« Reply #6 on: February 02, 2023, 06:22:17 pm »
You don't need TProcess for this, StreamIO serves you fine:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   StreamIO,
  7.   Classes;
  8.  
  9. var
  10.   sl: TStringList;
  11.   ms: TMemoryStream;
  12. begin
  13.   ms := TMemoryStream.Create;
  14.   try
  15.     // Redirect output to MS
  16.     AssignStream(Output, ms);  
  17.     Rewrite(Output);
  18.     // This should now land in MS
  19.     WriteLn('Hello Stream');
  20.     // Read out MS into a string list
  21.     sl := TStringList.Create;
  22.     try
  23.       ms.Seek(0, soBeginning);
  24.       sl.LoadFromStream(ms);
  25.       // Check whats in SL:
  26.       // Print on ErrOut (because Output is redirected to MS)
  27.       WriteLn(ErrOutput, 'SL.Text: ', sl.Text);
  28.     finally
  29.       sl.Free;
  30.     end;
  31.   finally
  32.     ms.Free;
  33.   end;
  34. end.
  35.  
Output:
Code: Text  [Select][+][-]
  1. SL.Text: Hello Stream
  2.  

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: can tprocess be made to do this?
« Reply #7 on: February 02, 2023, 07:04:19 pm »
Indeed, but I told him so. Hence my bewilderment. (And in detail)
Specialize a type, not a var.

toby

  • Sr. Member
  • ****
  • Posts: 251
Re: can tprocess be made to do this?
« Reply #8 on: February 02, 2023, 11:02:29 pm »

thanks Warfley

this is just what i asked for : writeln to tstringlist

now if i add the following code
var ao : text;

and after your WriteLn('Hello Stream');
assign(ao, '/dev/stdout');
//assign(ao, 'ms1.tmp'); // writes data to ms1.tmp file good
rewrite(ao);
writeln(ao, 'aaaaaaa');
close(ao);

it writes the 'aaaaaaa' above the 'SL.Text:' output instead of to memorystream like the WriteLn('Hello Stream'); does

can you please advise me as to the problem/raason ?

thanks

toby

  • Sr. Member
  • ****
  • Posts: 251
Re: can tprocess be made to do this?
« Reply #9 on: February 02, 2023, 11:45:45 pm »
kapibara,

thanks you for your  reply but that code is way to complicated for me to try to work with
i'm pretty sure you would end up wishing you didn't post it if i attempt to learn or use it :)


Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: can tprocess be made to do this?
« Reply #10 on: February 02, 2023, 11:52:17 pm »
Yes this is very simple, the hook that is registered by StreamIO is on a specific TextFile level, meaning that if you open a new TextFile (which assign does) it does not get redirected to the stream.

In fact, your system will open a new file descriptor each time you open /dev/stdout, so for your program it looks like you are opening a new file each time. I'm also not aware of any system APIs that would let you perform a general hook to that pseudofile. So it's probably not really possible without some really dirty hacks.

One option you could try would be to open a temporary file, and then dup your stdout to that file using dup2 And then later read from that file
But because the opening of the /dev/stdout pseudofile results in a new handle and dup2 is based on handles I don't think it will work (but it's at least worth a try)
« Last Edit: February 02, 2023, 11:56:01 pm by Warfley »

toby

  • Sr. Member
  • ****
  • Posts: 251
Re: can tprocess be made to do this?
« Reply #11 on: February 03, 2023, 12:53:35 am »
Warfley

thank you for making this clear - it is very much appreciated

this is related to my other topic

https://forum.lazarus.freepascal.org/index.php/topic,61841.msg466721.html


i have been using the save 'the apl_exec stdout' to a temp file from inside apl_exec and then reading the file data back into am fpc tstringlist variable)

but wanting to avoid writing to a file (not really to save running time - but to minimize a potential system weak point)

i have tried writing the apl_exec output to /dev/stdout and thought if i could get the a writeln (to stdout) into a tsrimglist which you solved) then the apl_exec to stdout would also be gotten into the tstringlist)

but since as you have explained the 'ao' writeln is to a different file handle (right?) then the original one to the memorystream the apl_exec stdout would also do the same thing

if you look at the other topic you will see the code that Fred Vs posted that uses fpdup/fpdup2 using tfilestreanm - you mentioned dup2 (is this the fpdup2?)

the way things are going with this i'm gonna guess that fpdup2 can't be applied to a tmemorystream? :)

again thank you very much
« Last Edit: February 03, 2023, 01:05:16 am by toby »

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: can tprocess be made to do this?
« Reply #12 on: February 03, 2023, 01:32:42 am »
FpXXX are just the fpc provided versions of the POSIX function, so yes fpdup2 is just the pascal equivalent to dup2

You cannot directly use a memory stream, but you can use a pipe. You can dup the write side of that pipe to the output and then just read from the other side of the pipe as if it where a file. Basically through the dup all the output will be thrown into the pipe and you can then later read that output.
It's a bit more tedious, but you would avoid a file as everything goes through the pipe (which btw is nothing other than a nameless virtual file anyway), but does not occur in the filesystem

toby

  • Sr. Member
  • ****
  • Posts: 251
Re: can tprocess be made to do this?
« Reply #13 on: February 03, 2023, 09:17:26 pm »
thats the problem - the only thing apl_exec returns is an integer - hence wanting to capture the stdout

writeln(pipo, 'apl_exec : ', apl_exec('⍳4')); -> apl_exec : 0


can thandlestream be usefull for this?
« Last Edit: February 03, 2023, 09:46:54 pm by toby »

irawan

  • Newbie
  • Posts: 6
Re: can tprocess be made to do this?
« Reply #14 on: February 11, 2023, 02:46:10 am »
in past few years ago, i got help from skydevil in in this kind of problem using Delphi 2007.
what i want to do at that time is running an chess UCI engine and got its output.
in many threads i seached, they had to wait the process to be stopped and got the output.
working with UCI chess engine is different, the engine itself must not be stopped.

 

TinyPortal © 2005-2018