Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2023-12

TProcess and redirection of StdIn/Out (e.g. from/to files)

10 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Martin Frb

If I am right the TProcess currently does not allow redirection of StdOut/In to/from a file (or other handle provided).

If it does, and I have been missing the "how to", then please enlighten me and disregard the remainder of the mail.

The code for setting up redirection to pipes (to be read/write by the parent process) already exists. So this is mainly a call to add properties to explicitly set those handles.
Or provide some other method.

Is this something that should be added? (I.e. a feature request to be added) If yes, should there just be 3 properties for the handles? A callback to create/provide them? A virtual method?
Should there be a flag?

What should be the resolving order if handles are give, but other flags (pipes/input) are set?

Reply by email

Michael Van Canneyt
to Martin Frb
Martin Frb wrote 5 lines
If I am right the TProcess currently does not allow redirection of StdOut/In to/from a file (or other handle provided). If it does, and I have been missing the "how to", then please enlighten me and disregard the remainder of the mail.

It does not exist out in the open :-)

Show quoted text 11 lines
The code for setting up redirection to pipes (to be read/write by the parent process) already exists. So this is mainly a call to add properties to explicitly set those handles. Or provide some other method. Is this something that should be added? (I.e. a feature request to be added) If yes, should there just be 3 properties for the handles? A callback to create/provide them? A virtual method? Should there be a flag?

Actually, I already started an implementation of an extension half a year ago. (although I have the design in mind since several years. Time constraints...)

It's nearly finished, there are still some corner cases that need testing.

The idea is a property of type TIODescriptor (reduced code for readability):

TIOType = (iotNone,iotPipe,iotFIle,iotHandle,iotProcess);
TIODescriptor = class(Tpersistent)
Public
   Property Handle : THandle;
Published
   property IOType: TIOType;
   property FileName : string;
   property OnGetHandle : TGetHandleEvent;
   property Process : TProcess;
end;
uses as
TProcess = Class()
// ...
Published
   Property InputDescriptor : TIODescriptor;
   Property OutputDescriptor : TIODescriptor;
   Property ErrorDescriptor : TIODescriptor;
end;
What should be the resolving order if handles are give, but other flags (pipes/input) are set?

Backwards compatibility first and foremost. Setting the poUsePipes option switches all descriptors to IOType = iotPipe.

I'll see if I can finish the implementation ASAP.

Michael.

Reply by email

Marco van de Voort
to Martin Frb: If I am right the TProcess currently does not allow redirection of StdOut/In to/from a…

Op 14-12-2023 om 17:30 schreef Martin Frb via fpc-devel:

If I am right the TProcess currently does not allow redirection of StdOut/In to/from a file (or other handle provided).

It does, if you need a runcommandloop like routine that writes to file. Partially this can be even simplified by inheriting TProcess and overriding readinputstream

If it does, and I have been missing the "how to", then please enlighten me and disregard the remainder of the mail.

The piping to memo (afaik since 3.2.0 or 3.0.4) should be analogues, you just need functions to write to disk, see e.g.

https://forum.lazarus.freepascal.org/index.php/topic,42385.msg443351.html#msg443351

Show quoted text 7 lines
Is this something that should be added? (I.e. a feature request to be added) If yes, should there just be 3 properties for the handles? A callback to create/provide them? A virtual method? Should there be a flag?

Maybe you can create a predefined derivative that does this with less additional code, but this should already be possible.

Reply by email

Martin Frb
to Marco van de Voort
Marco van de Voort wrote 8 lines
Op 14-12-2023 om 17:30 schreef Martin Frb via fpc-devel: > If I am right the TProcess currently does not allow redirection of > StdOut/In to/from a file (or other handle provided). It does, if you need a runcommandloop like routine that writes to file. Partially this can be even simplified by inheriting TProcess and overriding readinputstream

But that means the parent process has to read the data (from the file) and forward it.
Also not sure how to simulate an EOF in that case....

Show quoted text 11 lines
> > Is this something that should be added? (I.e. a feature request to be > added) > If yes, should there just be 3 properties for the handles? A callback > to create/provide them? A virtual method? > Should there be a flag? > Maybe you can create a predefined derivative that does this with less additional code, but this should already be possible.

Afaik, only if the parent process does the forwarding.

If the parent process is busy the child process will need to wait... If the parent process wants to launch the child, and the parent then exits....

Reply by email

Marco van de Voort
to Martin Frb

Op 14-12-2023 om 20:29 schreef Martin Frb via fpc-devel:

Show quoted text 9 lines
 Op 14-12-2023 om 17:30 schreef Martin Frb via fpc-devel: >> If I am right the TProcess currently does not allow redirection of >> StdOut/In to/from a file (or other handle provided). > > It does, if you need a runcommandloop like routine that writes to > file. Partially this can be even simplified by inheriting TProcess > and overriding readinputstream But that means the parent process has to read the data (from the file) and forward it.

Without a shell that always needs to happen. How else ? Keep in mind that TProcess is a kernel and not a shell level concept.

Also not sure how to simulate an EOF in that case....

Probably close the pipe.

Anyway the full project is here:
http://www.stack.nl/~marcov/files/processmemodemo.zip

It is slightly different, a TProcess based application that tries to instrument a secondary binary.

Reply by email

Martin Frb
to Marco van de Voort
Marco van de Voort wrote 14 lines
Op 14-12-2023 om 20:29 schreef Martin Frb via fpc-devel: >  Op 14-12-2023 om 17:30 schreef Martin Frb via fpc-devel: >>> If I am right the TProcess currently does not allow redirection of >>> StdOut/In to/from a file (or other handle provided). >> >> It does, if you need a runcommandloop like routine that writes to >> file. Partially this can be even simplified by inheriting TProcess >> and overriding readinputstream > But that means the parent process has to read the data (from the > file) and forward it. Without a shell that always needs to happen. How else ? Keep in mind that TProcess is a kernel and not a shell level concept.

At least on Windows you can give a handle that is to be used as StdIn.

And on Linux that handle is currently setup after the fork event, in the new process => and currently it either is a pipe or (I think) a copy of the parent stdin. But nothing stops it to be a filehandle. But afaik StdIn is just a handle. This handle can be a tty (usually if there is a shell), but it can be /dev/nil or a file or ...

I am actually pretty sure, on Linux, I can get what I want by doing it in the "OnFork" event of TProcess.
But on Windows it is well hidden away in the "Execute" method, nothing virtual that could be intercepted.

Show quoted text 11 lines
> Also not sure how to simulate an EOF in that case.... > Probably close the pipe. Anyway the full project is here: http://www.stack.nl/~marcov/files/processmemodemo.zip It is slightly different, a TProcess based application that tries to instrument a secondary binary.

Thanks, but I consider that a worst case work around.

I'd rather copy the entire TProcess, so I can make a few tiny changes in TProcess.Execute.
I already done a proof of concept on win:
- get the handle to the file
- pass it to the WinAPI for creating the process
=> works.

Haven't yet should be even easier.

-----

The reason I ask is, that if there is a chance of a future solution in FPC, then I like to avoid my own solution now until I can at least do my own solution in a compatible manner.
For that I would have to know enough details on that future solution.

Well depending on the amount of changes, I may still do my own incompatible....

Reply by email

Marco van de Voort
to Martin Frb

Op 14-12-2023 om 21:27 schreef Martin Frb via fpc-devel:

Show quoted text 5 lines
I am actually pretty sure, on Linux, I can get what I want by doing it in the "OnFork" event of TProcess. But on Windows it is well hidden away in the "Execute" method, nothing virtual that could be intercepted.

Change the input handle and use popassinput ?

But I wonder if this is not too specialistic. It depends on how well you can abstract it into TProcess, and preferably in a somewhat similar way for all OSes.

Reply by email

Martin Frb
to Marco van de Voort
Marco van de Voort wrote 9 lines
Op 14-12-2023 om 21:27 schreef Martin Frb via fpc-devel: > > I am actually pretty sure, on Linux, I can get what I want by doing > it in the "OnFork" event of TProcess. > But on Windows it is well hidden away in the "Execute" method, > nothing virtual that could be intercepted. Change the input handle and use popassinput ?

As I said, not possible (unless I make a copy of the entire TProcess code).  There is no way to intercept "Execute", and it must be done before the Windows API is called to create the process.

But I wonder if this is not too specialistic. It depends on how well you can abstract it into TProcess, and preferably in a somewhat similar way for all OSes.

Well Michael's answer looks like he is about to have what I need. Depends on the when...

Reply by email

Michael Van Canneyt
to Martin Frb
Martin Frb wrote 21 lines
On 14/12/2023 21:33, Marco van de Voort via fpc-devel wrote: > > Op 14-12-2023 om 21:27 schreef Martin Frb via fpc-devel: >> >> I am actually pretty sure, on Linux, I can get what I want by doing >> it in the "OnFork" event of TProcess. >> But on Windows it is well hidden away in the "Execute" method, >> nothing virtual that could be intercepted. > > Change the input handle and use popassinput ? As I said, not possible (unless I make a copy of the entire TProcess code).  There is no way to intercept "Execute", and it must be done before the Windows API is called to create the process. > > But I wonder if this is not too specialistic. It depends on how well > you can abstract it into TProcess, and preferably in a somewhat > similar way for all OSes. Well Michael's answer looks like he is about to have what I need. Depends on the when...

I pushed what I have to the extended_process branch. I tested on linux. Most simple scenarios I threw at it seem to work OK but I need to do some more testing for correct pipelines, for example:

ProcessA | ProcessB > out.txt

(so yes, we should be able to make a good 'pascal shell' :-))

Windows compiles and in code does what it takes, but needs more testing.

(in particular: when opening a file for input/output, does the parent need to close the file just as it does for pipes ?)

Note that there are still writeln() stements in it, this is WIP.

You're of course welcome to provide patches if I messed something up :)

Michael.

Reply by email