Recent

Author Topic: How to re use a process  (Read 452 times)

nikel

  • Sr. Member
  • ****
  • Posts: 252
How to re use a process
« on: April 29, 2025, 07:03:14 pm »
Hello, I'm trying to use a process multiple times in my console program. The second time I run it doesn't work. I don't remember whether it gave me error. I had to create a new process add
Code: Pascal  [Select][+][-]
  1. poStderrToOutPut
in options. Here's my first process.

Code: Pascal  [Select][+][-]
  1. // Find the key and set var
  2. AProcess:=TProcess.Create(nil);
  3. with AProcess do
  4. begin
  5.   Executable:='keyfinder-cli';
  6.   with Parameters do
  7.   begin
  8.     Add('-n');
  9.     Add('standard');
  10.     Add(Song.GetPath());
  11.   end;
  12.   CurrentDirectory:='/usr/local/bin/';
  13.   Options:=AProcess.Options + [poUsePipes, poWaitOnExit];
  14.   Execute;
  15. end;
  16. ListOfOutput.LoadFromStream(AProcess.Output);
  17. AProcess:=nil;
  18. AProcess.Free;
  19. if (Length(ListOfOutput.CommaText) <= 5) then
  20. begin
  21.   Song.SetKey(ListOfOutput.CommaText);
  22. end;
  23. ListOfOutput.Clear;

How can I use the process multiple times correctly?

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1505
    • Lebeau Software
Re: How to re use a process
« Reply #1 on: April 29, 2025, 07:12:17 pm »
Hello, I'm trying to use a process multiple times in my console program. The second time I run it doesn't work.

Can you be more specific? WHAT doesn't work, exactly?

I don't remember whether it gave me error.

Can you run it again and find out?



On a side note:

Code: Pascal  [Select][+][-]
  1. AProcess:=nil;
  2. AProcess.Free;

This causes a memory leak.  You need to reverse the order of these lines.
« Last Edit: April 29, 2025, 10:48:55 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

nikel

  • Sr. Member
  • ****
  • Posts: 252
Re: How to re use a process
« Reply #2 on: April 29, 2025, 07:19:46 pm »
Thank you for your reply. I notice it doesn't give me error anymore after poStderrToOutPut.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1505
    • Lebeau Software
Re: How to re use a process
« Reply #3 on: April 29, 2025, 10:49:36 pm »
Thank you for your reply. I notice it doesn't give me error anymore after poStderrToOutPut.

Are you sure the process actually attempts to write anything to stderr in the first place?
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Thaddy

  • Hero Member
  • *****
  • Posts: 16937
  • Ceterum censeo Trump esse delendam
Re: How to re use a process
« Reply #4 on: April 30, 2025, 10:10:46 am »
I think he means that stderr should not write to stdout,
He needs to configure stderr to redirect to file or a stream that can be used with a error reporting component. AFAIK there are several examples on the form. It is a recurring issue.
The Lazarus IDE uses this redirection itself.
If there is no redirection then the only way is to redirect stderr to stdout.
Here's a utility unit I wrote that extends CreatePipeStream with a third writestream for stdErr:
Code: Pascal  [Select][+][-]
  1. unit ExtendedPipes;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   {$ifdef unix}baseunix,unix,{$endif}{$ifdef mswindows}jwaWindows,{$endif}Classes, SysUtils, Pipes,streamio;
  9.  
  10. procedure CreateExtPipeStreams(out ReadPipe: TInputPipeStream;
  11.                              out WritePipe: TOutputPipeStream;
  12.                              out ErrWritePipe: TOutputPipeStream);
  13. implementation
  14.  
  15. procedure CreateExtPipeStreams(out ReadPipe: TInputPipeStream;
  16.                              out WritePipe: TOutputPipeStream;
  17.                              out ErrWritePipe: TOutputPipeStream);
  18. var
  19.   Pipe1Read, Pipe1Write: THandle;
  20.   Pipe2Read, Pipe2Write: THandle;
  21. begin
  22.   // Create first pipe (normal input/output)
  23.   if not CreatePipeHandles(Pipe1Read, Pipe1Write) then
  24.     raise EPipeError.Create('Failed to create primary pipe');
  25.    
  26.   // Create second pipe (for stderr)
  27.   if not CreatePipeHandles(Pipe2Read, Pipe2Write) then
  28.   begin
  29.     CloseHandle(Pipe1Read);
  30.     CloseHandle(Pipe1Write);
  31.     raise EPipeError.Create('Failed to create stderr pipe');
  32.   end;
  33.  
  34.   try
  35.     // Create the pipe stream objects
  36.     ReadPipe := TInputPipeStream.Create(Pipe1Read);
  37.     WritePipe := TOutputPipeStream.Create(Pipe1Write);
  38.     ErrWritePipe := TOutputPipeStream.Create(Pipe2Write);
  39.  
  40.     // Redirect stderr to our error pipe
  41.     AssignStream(ErrOutput, ErrWritePipe);
  42.     Rewrite(ErrOutput);
  43.   except
  44.     // Cleanup if something goes wrong
  45.     CloseHandle(Pipe1Read);
  46.     CloseHandle(Pipe1Write);
  47.     CloseHandle(Pipe2Read);
  48.     CloseHandle(Pipe2Write);
  49.     raise;
  50.   end;
  51. end;
  52.  
  53. end.

(I always had the plan to write that, this looked like a good opportunity to finally do it. I had a little help from deepseek, but quite a few manual changes necessary)

Use is the same as for CreatePipeStream, except stderr now has its own stream.

« Last Edit: April 30, 2025, 12:47:53 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

 

TinyPortal © 2005-2018