File: test5_1asyncprocess.lpr

package info (click to toggle)
lazarus 2.2.6%2Bdfsg2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 219,980 kB
  • sloc: pascal: 1,944,919; xml: 357,634; makefile: 270,608; cpp: 57,115; sh: 3,249; java: 609; perl: 297; sql: 222; ansic: 137
file content (190 lines) | stat: -rw-r--r-- 5,931 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
{
 *****************************************************************************
 *                                                                           *
 *  This file is part of the Lazarus Component Library (LCL)                 *
 *                                                                           *
 *  See the file COPYING.LCL, included in this distribution,                 *
 *  for details about the copyright.                                         *
 *                                                                           *
 *  This program is distributed in the hope that it will be useful,          *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                     *
 *                                                                           *
 *****************************************************************************

  LCL Test 5_1 for TAsyncProcess

  Showing a form and starting via TAsyncProcess test5_1worker.
  
  Requirements:
    1. Compile LCL with TAsyncProcess support: -dUseAsyncProcess
    2. Compile test5_1worker.pas.
}
program test5_1asyncprocess;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, Math, Classes, SysUtils, Process, LCLProc, DynQueue, FileUtil,
  Forms, Controls, AsyncProcess;

type

  { TForm1 }

  TForm1 = class(TForm)
    procedure Form1Idle(Sender: TObject; var Done: Boolean);
    procedure OnAsyncReadData(Sender: TObject);
    procedure OnAsyncTerminate(Sender: TObject);
  private
    FAsyncProcessTerminated: Boolean;
    FStopExecute: Boolean;
    FTheProcess: TProcess;
    FAsyncOutput: TDynamicDataQueue;
    FUseAsyncProcess: Boolean;
  public
    constructor Create(TheOwner: TComponent); override;
    property AsyncProcessTerminated: boolean read FAsyncProcessTerminated;
    property StopExecute: Boolean read FStopExecute write FStopExecute;
    property TheProcess: TProcess read FTheProcess;
    property UseAsyncProcess: Boolean read FUseAsyncProcess write FUseAsyncProcess;
  end;

var
  Form1: TForm1;

{ TForm1 }

procedure TForm1.Form1Idle(Sender: TObject; var Done: Boolean);
const
  BufSize = 1024;
var
  i, Count, LineStart : longint;
  OutputLine, Buf : String;
  TheAsyncProcess: TAsyncProcess;
begin
  DebugLn(['TForm1.Form1Idle START']);
  if UseAsyncProcess then
    FTheProcess:=TAsyncProcess.Create(nil)
  else
    FTheProcess:=TProcess.Create(nil);
  TheProcess.CommandLine:=AppendPathDelim(GetCurrentDir)+'test5_1worker';
  if not FileExists(TheProcess.CommandLine) then begin
    DebugLn(['TForm1.Form1Idle File not found: ',TheProcess.CommandLine]);
    exit;
  end;
  TheProcess.Options:= [poUsePipes,poStdErrToOutPut];
  TheProcess.ShowWindow := swoHide;

  SetLength(Buf,BufSize);

  OutputLine:='';

  if TheProcess is TAsyncProcess then begin
    TheAsyncProcess:=TAsyncProcess(TheProcess);
    TheAsyncProcess.OnReadData:=@OnAsyncReadData;
    TheAsyncProcess.OnTerminate:=@OnAsyncTerminate;
    FAsyncOutput:=TDynamicDataQueue.Create;
  end else
    TheAsyncProcess:=nil;

  TheProcess.Execute;
  DebugLn(['TForm1.Form1Idle start looping ...']);
  repeat
    Application.ProcessMessages;
    DebugLn(['TForm1.Form1Idle looping ...']);
    if StopExecute then begin
      DebugLn(['TForm1.Form1Idle Aborting...']);
      TheProcess.Terminate(0);
      DebugLn(['TForm1.Form1Idle Aborted']);
      break;
    end;

    Count:=0;
    if (TheAsyncProcess<>nil) then begin
      // using non blocking TAsyncProcess
      Count:=FAsyncOutput.Size;
      DebugLn(['TForm1.Form1Idle Count=',Count]);
      if (Count=0) and AsyncProcessTerminated then break;
      if Count>0 then
        Count:=FAsyncOutput.Pop(Buf[1],Min(Count,length(Buf)))
      else
        Sleep(100);
    end;
    if (TheAsyncProcess=nil) and (TheProcess.Output<>nil) then begin
      // using a blocking TProcess
      DebugLn(['TForm1.Form1Idle reading ...']);
      Count:=TheProcess.Output.Read(Buf[1],length(Buf));
      DebugLn(['TForm1.Form1Idle read ',Count]);
      if Count=0 then begin
        // no output on blocking means, process has ended
        break;
      end;
    end;

    LineStart:=1;
    i:=1;
    while i<=Count do begin
      if Buf[i] in [#10,#13] then begin
        OutputLine:=OutputLine+copy(Buf,LineStart,i-LineStart);
        DebugLn(['TForm1.Form1Idle OutputLine="',OutputLine,'"']);
        OutputLine:='';
        if (i<Count) and (Buf[i+1] in [#10,#13]) and (Buf[i]<>Buf[i+1])
        then
          inc(i);
        LineStart:=i+1;
      end;
      inc(i);
    end;
    OutputLine:=OutputLine+copy(Buf,LineStart,Count-LineStart+1);
  until false;
  DebugLn('TForm1.Form1Idle After Loop');
  TheProcess.WaitOnExit;
  DebugLn('TForm1.Form1Idle TheProcess.ExitStatus=',dbgs(TheProcess.ExitStatus));

  TheProcess.Free;
  fTheProcess:=nil;
  FAsyncOutput.Free;
  FAsyncOutput:=nil;
end;

procedure TForm1.OnAsyncReadData(Sender: TObject);
var
  Count: LongWord;
  s: string;
begin
  Count:=TAsyncProcess(TheProcess).NumBytesAvailable;
  s:='';
  if Count>0 then begin
    FAsyncOutput.Push(TStream(TAsyncProcess(TheProcess).Output),Count);
    DebugLn(['TForm1.OnAsyncReadData Size=',FAsyncOutput.Size,' ',DbgSName(TAsyncProcess(TheProcess).Output)]);
    SetLength(s,Count);
    FAsyncOutput.Top(s[1],Count);
  end;
  DebugLn(['TForm1.OnAsyncReadData ',Count,' ',TAsyncProcess(TheProcess).NumBytesAvailable]);
  DebugLn(DbgStr(s));
  DumpStack;
end;

procedure TForm1.OnAsyncTerminate(Sender: TObject);
begin
  DebugLn(['TForm1.OnAsyncTerminate ']);
  FAsyncProcessTerminated:=true;
end;

constructor TForm1.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  Application.OnIdle:=@Form1Idle;
end;

begin
  Application.Initialize;
  Application.CreateForm(TForm1,Form1);
  Form1.UseAsyncProcess:=ParamStr(1)<>'process';
  Application.Run;
end.