1{
2 /***************************************************************************
3                               AsyncProcess.pp
4                               ---------------
5                   Initial Revision  : Tue Dec 06 09:00:00 CET 2005
6
7
8 ***************************************************************************/
9
10 *****************************************************************************
11  This file is part of the Lazarus Component Library (LCL)
12
13  See the file COPYING.modifiedLGPL.txt, included in this distribution,
14  for details about the license.
15 *****************************************************************************
16}
17
18unit AsyncProcess;
19
20{$mode objfpc}{$H+}
21
22interface
23
24uses
25  Classes, Process,
26  // LazUtils
27  FileUtil, UTF8Process,
28  // LCL
29  InterfaceBase, LCLIntf;
30
31type
32
33  { TAsyncProcess }
34
35  TAsyncProcess = class(TProcessUTF8)
36  private
37    FPipeHandler: PPipeEventHandler;
38    FProcessHandler: PProcessEventHandler;
39    FOnReadData: TNotifyEvent;
40    FOnTerminate: TNotifyEvent;
41  protected
42    function GetNumBytesAvailable: dword;
43    procedure HandlePipeInput(AData: PtrInt; AReasons: TPipeReasons);
44    procedure HandleProcessTermination(AData: PtrInt; AReason: TChildExitReason; AInfo: dword);
45    procedure UnhookPipeHandle;
46    procedure UnhookProcessHandle;
47  public
48    procedure Execute; override;
49    destructor Destroy; override;
50    property NumBytesAvailable: dword read GetNumBytesAvailable;
51  published
52    property OnReadData: TNotifyEvent read FOnReadData write FOnReadData;// You must read all the data in this event. Otherwise it is called again.
53    property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate;
54  end;
55
56procedure Register;
57
58implementation
59
60function TAsyncProcess.GetNumBytesAvailable: dword;
61begin
62  if not (poUsePipes in Options) then
63    Result := 0
64  else
65    Result := Output.NumBytesAvailable;
66end;
67
68destructor TAsyncProcess.Destroy;
69begin
70  UnhookProcessHandle;
71  UnhookPipeHandle;
72  inherited;
73end;
74
75procedure TAsyncProcess.UnhookProcessHandle;
76begin
77  if FProcessHandler <> nil then
78    RemoveProcessEventHandler(FProcessHandler);
79end;
80
81procedure TAsyncProcess.UnhookPipeHandle;
82begin
83  if FPipeHandler <> nil then
84    RemovePipeEventHandler(FPipeHandler);
85end;
86
87procedure TAsyncProcess.HandlePipeInput(AData: PtrInt; AReasons: TPipeReasons);
88begin
89  if prBroken in AReasons then
90    UnhookPipeHandle;
91  if prDataAvailable in AReasons then
92    if FOnReadData <> nil then
93      FOnReadData(Self);
94end;
95
96procedure TAsyncProcess.HandleProcessTermination(AData: PtrInt; AReason: TChildExitReason; AInfo: dword);
97begin
98  UnhookProcessHandle;
99  UnhookPipeHandle;
100  if FOnTerminate <> nil then
101    FOnTerminate(Self);
102end;
103
104procedure TAsyncProcess.Execute;
105begin
106  inherited Execute;
107
108  if poUsePipes in Options then
109    FPipeHandler := AddPipeEventHandler(Output.Handle, @HandlePipeInput, 0);
110  FProcessHandler := AddProcessEventHandler(ProcessHandle, @HandleProcessTermination, 0);
111end;
112
113procedure Register;
114begin
115  RegisterComponents('System',[TAsyncProcess]);
116end;
117
118end.
119