Recent

Author Topic: [solved] macOS Process and Pipes  (Read 729 times)

Espectr0

  • Full Member
  • ***
  • Posts: 218
[solved] macOS Process and Pipes
« on: April 15, 2023, 12:47:27 pm »
Hola,

I want to run an app and receive the output texts, in windows it works correctly but in macOS I do not receive anything when executing the app.
What can be?

Code: Pascal  [Select][+][-]
  1. TUWProcessCB = procedure(const TimeElapsed: Double; var Cancel: Boolean);
  2.  
  3. procedure ExecuteAppEx(const AAppFileName: String; const AParams: TStringArray; var Output: TStringList; const ACB: TUWProcessCB = NIL);
  4. const
  5.   READ_BYTES = 2048;
  6.  
  7. var
  8.   AProcess: TProcess;
  9.   ACancel: Boolean;
  10.   ATimeElapsed: Double;
  11.   i: Integer;
  12.   MemStream: TMemoryStream;
  13.   NumBytes: LongInt;
  14.   BytesRead: LongInt;
  15. begin
  16.   AProcess := TProcess.Create(NIL);
  17.   try
  18.     AProcess.ShowWindow := swoHide;
  19.     AProcess.Executable := AAppFileName;
  20.     AProcess.Options    := AProcess.Options + [poUsePipes, poStderrToOutPut];
  21.  
  22.     for i := 0 to High(AParams) do
  23.       AProcess.Parameters.Add(AParams[i]);
  24.  
  25.     AProcess.Execute;
  26.  
  27.     ACancel      := False;
  28.     ATimeElapsed := 0;
  29.     BytesRead := 0;
  30.     MemStream := TMemoryStream.Create;
  31.     try
  32.       while AProcess.Running do
  33.       begin
  34.         MemStream.SetSize(BytesRead + READ_BYTES);
  35.  
  36.         NumBytes := AProcess.Output.Read((MemStream.Memory + BytesRead)^, READ_BYTES);
  37.         if NumBytes > 0 then
  38.           Inc(BytesRead, NumBytes)
  39.         else
  40.           Break;
  41.  
  42.         Application.ProcessMessages;
  43.         Sleep(100);
  44.         ATimeElapsed += 0.1;
  45.         if Assigned(ACB) then
  46.         begin
  47.           ACB(ATimeElapsed, ACancel);
  48.           Application.ProcessMessages;
  49.           if ACancel then AProcess.Terminate(-1);
  50.         end;
  51.       end;
  52.       MemStream.SetSize(BytesRead);
  53.       if not Assigned(Output) then  Output := TStringList.Create;
  54.       Output.LoadFromStream(MemStream);
  55.     finally
  56.       MemStream.Free;
  57.     end;
  58.   finally
  59.     AProcess.Free;
  60.   end;
  61. end;
  62.  

Thanks!
« Last Edit: April 23, 2023, 12:14:18 am by Espectr0 »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11459
  • FPC developer.
Re: macOS Process and Pipes
« Reply #1 on: April 15, 2023, 01:05:19 pm »
How do you check that you don't receive anything? Does it hang or finish?

OS behaviour can vary depending on the size of buffers and blocking behaviour of pipes.  A good guard against that is the way that runcommandloop does it by always first checking how many bytes are available and then read those.


Espectr0

  • Full Member
  • ***
  • Posts: 218
Re: macOS Process and Pipes
« Reply #2 on: April 15, 2023, 01:23:58 pm »
well the stringlist is empty.

I tried running the app, let's say "ffmpeg" in the terminal and there are texts but nothing when running in lazarus process.

Can you tell me that it is better to remove my Loop and use RunCommandLoop and possibly work? :)

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 1059
Re: macOS Process and Pipes
« Reply #3 on: April 15, 2023, 01:42:48 pm »
I think ffmpeg writes its output to stderr instead of stdout

Espectr0

  • Full Member
  • ***
  • Posts: 218
Re: macOS Process and Pipes
« Reply #4 on: April 15, 2023, 02:02:50 pm »
I'm not sure, but I use the "poStderrToOutPut" flag anyway.

JdeHaan

  • Full Member
  • ***
  • Posts: 121
Re: macOS Process and Pipes
« Reply #5 on: April 15, 2023, 03:00:10 pm »
This works for me under MacOs:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.ProjectRunExecute(Sender: TObject);
  2. const
  3.   BUF_SIZE = 2048;
  4. var
  5.   aProcess: TProcess;
  6.   aMessages, aErrors: TStringList;
  7.   OutputStream : TStream;
  8.   BytesRead    : longint;
  9.   Buffer       : array[1..BUF_SIZE] of byte;
  10. begin
  11.   try
  12.     aProcess := TProcess.Create(nil);
  13.     aMessages := TStringList.Create;
  14.     aErrors := TStringList.Create;
  15.     aProcess.Executable := your app;
  16.     aProcess.Parameters.Add(parameter);
  17.  
  18.     aProcess.Options := [poUsePipes, poStderrToOutPut];
  19.     try
  20.       aProcess.Execute;
  21.       OutputStream := TMemoryStream.Create;
  22.       repeat
  23.         BytesRead := AProcess.Output.Read(Buffer, BUF_SIZE);
  24.         OutputStream.Write(Buffer, BytesRead)
  25.       until BytesRead = 0;
  26.  
  27.       with aMessages do
  28.       begin
  29.         OutputStream.Position := 0; // Required to make sure all data is copied from the start
  30.         LoadFromStream(OutputStream);
  31.       end;
  32.  
  33.       // Clean up
  34.       OutputStream.Free;
  35.  
  36.     except
  37.       aErrors.LoadFromStream(aProcess.Stderr);
  38.       //MemoOutput.Text := aErrors.Text; // copy errors to a memo
  39.       ShowMessage('ExitStatus : ' + IntToStr(aProcess.ExitStatus));
  40.     end;
  41.   finally
  42.     aMessages.Free;
  43.     aProcess.Free;
  44.     aErrors.Free;
  45.   end;
  46.  
  47. end;
  48.  

 

TinyPortal © 2005-2018