Recent

Author Topic: [solved] run external app in thread process  (Read 1482 times)

Espectr0

  • Full Member
  • ***
  • Posts: 240
[solved] run external app in thread process
« on: August 19, 2023, 01:35:53 pm »
Hola,

I want to run an app in a thread process, so my app doesn't freeze, but it still hangs and closes on Windows.
What am I doing wrong?

Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   TUWOnProcess   = procedure(Output: String);
  4.  
  5.   TUWThreadProcess = class(TThread)
  6.   private
  7.     FFileName  : String;
  8.     FParams    : TStringArray;
  9.     FOnProcess : TUWOnProcess;
  10.     FOnDone    : TNotifyEvent;
  11.     procedure DataReceived;
  12.     procedure Done;
  13.   protected
  14.     procedure Execute; override;
  15.   public
  16.     TerminateProcess : Boolean;
  17.     OutputString     : String;
  18.     constructor Create(const AFileName: String; const AParams: TStringArray; AOnProcess: TUWOnProcess = NIL; AOnDone: TNotifyEvent = NIL);
  19.     property Terminated;
  20.   end;
  21.  
  22. constructor TUWThreadProcess.Create(const AFileName: String; const AParams: TStringArray; AOnProcess: TUWOnProcess = NIL; AOnDone: TNotifyEvent = NIL);
  23. begin
  24.   inherited Create(False);
  25.  
  26.   FFileName        := AFileName;
  27.   FParams          := AParams;
  28.   TerminateProcess := False;
  29.   FOnProcess       := AOnProcess;
  30.   FOnDone          := AOnDone;
  31.   OutputString     := '';
  32.  
  33.   FreeOnTerminate  := True;
  34. end;
  35.  
  36. procedure TUWThreadProcess.Execute;
  37. const
  38.   BUF_SIZE = 2048; // Buffer size for reading the output in chunks
  39.  
  40. var
  41.   AProcess  : TProcess;
  42.   BytesRead : LongInt;
  43.   Buffer    : array[1..BUF_SIZE] of Byte;
  44.   i         : Integer;
  45. begin
  46.   AProcess := TProcess.Create(NIL);
  47.   try
  48.     // Set up the process
  49.     AProcess.ShowWindow := swoHide;
  50.     AProcess.Executable := FFileName;
  51.  
  52.     // Process option poUsePipes has to be used so the output can be captured.
  53.     // Process option poWaitOnExit can not be used because that would block
  54.     // this program, preventing it from reading the output data of the process.
  55.     AProcess.Options := [poUsePipes, poStderrToOutPut];
  56.  
  57.     // Params
  58.     for i := 0 to High(FParams) do
  59.       AProcess.Parameters.Add(FParams[i]);
  60.  
  61.     try
  62.       // Start the process
  63.       AProcess.Execute;
  64.  
  65.       // All generated output from AProcess is read in a loop until no more data is available
  66.       while AProcess.Running do
  67.       begin
  68.         // Get the new data from the process to a maximum of the buffer size that was allocated.
  69.         // Note that all read(...) calls will block except for the last one, which returns 0 (zero).
  70.         BytesRead := AProcess.Output.Read(Buffer, BUF_SIZE);
  71.         SetLength(OutputString, BytesRead);
  72.         Move(Buffer[1], OutputString[1], BytesRead);
  73.  
  74.         if Assigned(FOnProcess) then
  75.           Synchronize(@DataReceived);
  76.  
  77.         if TerminateProcess then
  78.         begin
  79.           AProcess.Terminate(-1);
  80.           Exit;
  81.         end;
  82.  
  83.         if BytesRead = 0 then Break; // Stop if no more data is available
  84.       end;
  85.     except
  86.       on e: Exception do
  87.       begin
  88.       end;
  89.     end;
  90.   finally
  91.     // The process has finished so it can be cleaned up
  92.     AProcess.Free;
  93.     if Assigned(FOnDone) then
  94.       Synchronize(@Done);
  95.   end;
  96. end;
  97.  
  98. procedure TUWThreadProcess.DataReceived;
  99. begin
  100.   if Assigned(FOnProcess) then
  101.     FOnProcess(OutputString);
  102. end;
  103.  
  104. procedure TUWThreadProcess.Done;
  105. begin
  106.   if Assigned(FOnDone) then
  107.     FOnDone(Self);
  108. end;
  109.  

Thanks!
« Last Edit: August 20, 2023, 07:59:16 pm by Espectr0 »

aydın

  • Jr. Member
  • **
  • Posts: 86
Re: run external app in thread process
« Reply #1 on: August 19, 2023, 06:31:00 pm »
This is the code I use to run FPC and display its outputs in real-time.
I hope it's helpful for you.

Code: Pascal  [Select][+][-]
  1. Const
  2.   BUF_SIZE = 2048;
  3. Var
  4.   AProcess: TProcessUTF8;
  5.   BytesRead: LongInt;
  6.   Buffer: Array[1..BUF_SIZE] of Char;
  7. Begin
  8.   AProcess:= TProcessUTF8.Create(Nil);
  9.   AProcess.Executable:= 'C:\Lazarus\fpc\3.2.2\bin\x86_64-win64\fpc.exe';
  10.  
  11.   AProcess.Parameters.AddStrings([
  12.     'Main.pas',
  13.     '-Px86_64',
  14.     '-MObjFPC',
  15.     '-oMain.exe'
  16.   ]);
  17.  
  18.   AProcess.Options:= AProcess.Options +[poUsePipes];
  19.   AProcess.ShowWindow:= swoHIDE;
  20.  
  21.   AProcess.Execute;
  22.  
  23.   Repeat
  24.     Buffer:= '';
  25.     BytesRead:= AProcess.Output.Read(Buffer, BUF_SIZE);
  26.  
  27.     if String(Trim(Buffer)).IsEmpty then Continue;
  28.  
  29.     ErrorsList.Items.Add(Buffer);
  30.     ErrorsList.ItemIndex:= ErrorsList.Items.Count-1;
  31.   Until BytesRead = 0;
  32.  
  33.   //Result:= AProcess.ExitCode = 0;
  34.  
  35.   AProcess.Free;
  36. End;
  37.  
Lazarus 4.99, FPC 3.3.1 on Fedora 42

Espectr0

  • Full Member
  • ***
  • Posts: 240
Re: run external app in thread process
« Reply #2 on: August 20, 2023, 12:44:33 am »
Thanks for the answer, but the problem I have, is when executing the process in the tthread, if I use outside of it, it works correctly :S

jamie

  • Hero Member
  • *****
  • Posts: 7697
Re: run external app in thread process
« Reply #3 on: August 20, 2023, 12:51:44 am »
have you try running this without debugging?
The only true wisdom is knowing you know nothing

Espectr0

  • Full Member
  • ***
  • Posts: 240
Re: run external app in thread process
« Reply #4 on: August 20, 2023, 02:53:51 pm »
Yes, tested and I have the same problem, what can you tell me about the code, any possible bug?

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: run external app in thread process
« Reply #5 on: August 20, 2023, 02:59:10 pm »
....what can you tell me about the code, any possible bug?
impossible to tell as the code as shown is only part of the problem. It would be more beneficial to see how you invoke the code that you posted as in basics there seem to be nothing wrong with it (e.g. it works for me tm (linux x86_64)).
« Last Edit: August 20, 2023, 03:13:32 pm by TRon »
Today is tomorrow's yesterday.

jamie

  • Hero Member
  • *****
  • Posts: 7697
Re: run external app in thread process
« Reply #6 on: August 20, 2023, 04:53:49 pm »
I see this.

Code: Pascal  [Select][+][-]
  1. constructor TUWThreadProcess.Create(const AFileName: String; const AParams: TStringArray; AOnProcess: TUWOnProcess = NIL; AOnDone: TNotifyEvent = NIL);
  2. begin
  3.   inherited Create(False);  // <<< Should be True if you didn't complete the setup yet or do this at the end?
  4.  
  5.   FFileName        := AFileName;
  6.   FParams          := AParams;
  7.   TerminateProcess := False;
  8.   FOnProcess       := AOnProcess;
  9.   FOnDone          := AOnDone;
  10.   OutputString     := '';
  11.  
  12.   FreeOnTerminate  := True;
  13. end;
  14.  
  15.  

I also see dead people!  :o
The only true wisdom is knowing you know nothing

Espectr0

  • Full Member
  • ***
  • Posts: 240
Re: run external app in thread process
« Reply #7 on: August 20, 2023, 07:59:03 pm »
You are right @jamie, your sixth sense always helps :)

Thanks to all!

 

TinyPortal © 2005-2018