123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575 |
- {
- This file is part of the Free Component Library (FCL)
- Copyright (c) 1999-2000 by the Free Pascal development team
- See the file COPYING.FPC, 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.
- **********************************************************************}
- {$mode objfpc}
- {$h+}
- unit process;
- interface
- Uses Classes,
- pipes,
- SysUtils;
- Type
- TProcessOption = (poRunSuspended,poWaitOnExit,
- poUsePipes,poStderrToOutPut,
- poNoConsole,poNewConsole,
- poDefaultErrorMode,poNewProcessGroup,
- poDebugProcess,poDebugOnlyThisProcess);
- TShowWindowOptions = (swoNone,swoHIDE,swoMaximize,swoMinimize,swoRestore,swoShow,
- swoShowDefault,swoShowMaximized,swoShowMinimized,
- swoshowMinNOActive,swoShowNA,swoShowNoActivate,swoShowNormal);
- TStartupOption = (suoUseShowWindow,suoUseSize,suoUsePosition,
- suoUseCountChars,suoUseFillAttribute);
- TProcessPriority = (ppHigh,ppIdle,ppNormal,ppRealTime);
- TProcessOptions = set of TProcessOption;
- TStartupOptions = set of TStartupOption;
- Type
- {$ifdef UNIX}
- TProcessForkEvent = procedure;
- {$endif UNIX}
- { TProcess }
- TProcess = Class (TComponent)
- Private
- FProcessOptions : TProcessOptions;
- FStartupOptions : TStartupOptions;
- FProcessID : Integer;
- FTerminalProgram: String;
- FThreadID : Integer;
- FProcessHandle : Thandle;
- FThreadHandle : Thandle;
- FFillAttribute : Cardinal;
- FApplicationName : string;
- FConsoleTitle : String;
- FCommandLine : String;
- FCurrentDirectory : String;
- FDesktop : String;
- FEnvironment : Tstrings;
- FExecutable : String;
- FParameters : TStrings;
- FShowWindow : TShowWindowOptions;
- FInherithandles : Boolean;
- {$ifdef UNIX}
- FForkEvent : TProcessForkEvent;
- {$endif UNIX}
- FProcessPriority : TProcessPriority;
- dwXCountchars,
- dwXSize,
- dwYsize,
- dwx,
- dwYcountChars,
- dwy : Cardinal;
- FXTermProgram: String;
- FPipeBufferSize : cardinal;
- Procedure FreeStreams;
- Function GetExitStatus : Integer;
- Function GetRunning : Boolean;
- Function GetWindowRect : TRect;
- procedure SetCommandLine(const AValue: String);
- procedure SetParameters(const AValue: TStrings);
- Procedure SetWindowRect (Value : TRect);
- Procedure SetShowWindow (Value : TShowWindowOptions);
- Procedure SetWindowColumns (Value : Cardinal);
- Procedure SetWindowHeight (Value : Cardinal);
- Procedure SetWindowLeft (Value : Cardinal);
- Procedure SetWindowRows (Value : Cardinal);
- Procedure SetWindowTop (Value : Cardinal);
- Procedure SetWindowWidth (Value : Cardinal);
- procedure SetApplicationName(const Value: String);
- procedure SetProcessOptions(const Value: TProcessOptions);
- procedure SetActive(const Value: Boolean);
- procedure SetEnvironment(const Value: TStrings);
- Procedure ConvertCommandLine;
- function PeekExitStatus: Boolean;
- Protected
- FRunning : Boolean;
- FExitCode : Cardinal;
- FInputStream : TOutputPipeStream;
- FOutputStream : TInputPipeStream;
- FStderrStream : TInputPipeStream;
- procedure CloseProcessHandles; virtual;
- Procedure CreateStreams(InHandle,OutHandle,ErrHandle : Longint);virtual;
- procedure FreeStream(var AStream: THandleStream);
- procedure Loaded; override;
- Public
- Constructor Create (AOwner : TComponent);override;
- Destructor Destroy; override;
- Procedure Execute; virtual;
- procedure CloseInput; virtual;
- procedure CloseOutput; virtual;
- procedure CloseStderr; virtual;
- Function Resume : Integer; virtual;
- Function Suspend : Integer; virtual;
- Function Terminate (AExitCode : Integer): Boolean; virtual;
- Function WaitOnExit : Boolean;
- Property WindowRect : Trect Read GetWindowRect Write SetWindowRect;
- Property Handle : THandle Read FProcessHandle;
- Property ProcessHandle : THandle Read FProcessHandle;
- Property ThreadHandle : THandle Read FThreadHandle;
- Property ProcessID : Integer Read FProcessID;
- Property ThreadID : Integer Read FThreadID;
- Property Input : TOutputPipeStream Read FInputStream;
- Property Output : TInputPipeStream Read FOutputStream;
- Property Stderr : TinputPipeStream Read FStderrStream;
- Property ExitStatus : Integer Read GetExitStatus;
- Property InheritHandles : Boolean Read FInheritHandles Write FInheritHandles;
- {$ifdef UNIX}
- property OnForkEvent : TProcessForkEvent Read FForkEvent Write FForkEvent;
- {$endif UNIX}
- Published
- property PipeBufferSize : cardinal read FPipeBufferSize write FPipeBufferSize default 1024;
- Property Active : Boolean Read GetRunning Write SetActive;
- Property ApplicationName : String Read FApplicationName Write SetApplicationName; deprecated;
- Property CommandLine : String Read FCommandLine Write SetCommandLine ; deprecated;
- Property Executable : String Read FExecutable Write FExecutable;
- Property Parameters : TStrings Read FParameters Write SetParameters;
- Property ConsoleTitle : String Read FConsoleTitle Write FConsoleTitle;
- Property CurrentDirectory : String Read FCurrentDirectory Write FCurrentDirectory;
- Property Desktop : String Read FDesktop Write FDesktop;
- Property Environment : TStrings Read FEnvironment Write SetEnvironment;
- Property Options : TProcessOptions Read FProcessOptions Write SetProcessOptions;
- Property Priority : TProcessPriority Read FProcessPriority Write FProcessPriority;
- Property StartupOptions : TStartupOptions Read FStartupOptions Write FStartupOptions;
- Property Running : Boolean Read GetRunning;
- Property ShowWindow : TShowWindowOptions Read FShowWindow Write SetShowWindow;
- Property WindowColumns : Cardinal Read dwXCountChars Write SetWindowColumns;
- Property WindowHeight : Cardinal Read dwYSize Write SetWindowHeight;
- Property WindowLeft : Cardinal Read dwX Write SetWindowLeft;
- Property WindowRows : Cardinal Read dwYCountChars Write SetWindowRows;
- Property WindowTop : Cardinal Read dwY Write SetWindowTop ;
- Property WindowWidth : Cardinal Read dwXSize Write SetWindowWidth;
- Property FillAttribute : Cardinal read FFillAttribute Write FFillAttribute;
- Property XTermProgram : String Read FXTermProgram Write FXTermProgram;
- end;
- EProcess = Class(Exception);
- Procedure CommandToList(S : String; List : TStrings);
- {$ifdef unix}
- Var
- TryTerminals : Array of string;
- XTermProgram : String;
- Function DetectXTerm : String;
- {$endif unix}
- function RunCommandIndir(const curdir:string;const exename:string;const commands:array of string;var outputstring:string;var exitstatus:integer):integer;
- function RunCommandIndir(const curdir:string;const exename:string;const commands:array of string;var outputstring:string):boolean;
- function RunCommandInDir(const curdir,cmdline:string;var outputstring:string):boolean; deprecated;
- function RunCommand(const exename:string;const commands:array of string;var outputstring:string):boolean;
- function RunCommand(const cmdline:string;var outputstring:string):boolean; deprecated;
- implementation
- {$i process.inc}
- Procedure CommandToList(S : String; List : TStrings);
- Function GetNextWord : String;
- Const
- WhiteSpace = [' ',#9,#10,#13];
- Literals = ['"',''''];
- Var
- Wstart,wend : Integer;
- InLiteral : Boolean;
- LastLiteral : char;
- begin
- WStart:=1;
- While (WStart<=Length(S)) and (S[WStart] in WhiteSpace) do
- Inc(WStart);
- WEnd:=WStart;
- InLiteral:=False;
- LastLiteral:=#0;
- While (Wend<=Length(S)) and (Not (S[Wend] in WhiteSpace) or InLiteral) do
- begin
- if S[Wend] in Literals then
- If InLiteral then
- InLiteral:=Not (S[Wend]=LastLiteral)
- else
- begin
- InLiteral:=True;
- LastLiteral:=S[Wend];
- end;
- inc(wend);
- end;
- Result:=Copy(S,WStart,WEnd-WStart);
- if (Length(Result) > 0)
- and (Result[1] = Result[Length(Result)]) // if 1st char = last char and..
- and (Result[1] in Literals) then // it's one of the literals, then
- Result:=Copy(Result, 2, Length(Result) - 2); //delete the 2 (but not others in it)
- While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
- inc(Wend);
- Delete(S,1,WEnd-1);
- end;
- Var
- W : String;
- begin
- While Length(S)>0 do
- begin
- W:=GetNextWord;
- If (W<>'') then
- List.Add(W);
- end;
- end;
- Constructor TProcess.Create (AOwner : TComponent);
- begin
- Inherited;
- FProcessPriority:=ppNormal;
- FShowWindow:=swoNone;
- FInheritHandles:=True;
- {$ifdef UNIX}
- FForkEvent:=nil;
- {$endif UNIX}
- FPipeBufferSize := 1024;
- FEnvironment:=TStringList.Create;
- FParameters:=TStringList.Create;
- end;
- Destructor TProcess.Destroy;
- begin
- FParameters.Free;
- FEnvironment.Free;
- FreeStreams;
- CloseProcessHandles;
- Inherited Destroy;
- end;
- Procedure TProcess.FreeStreams;
- begin
- If FStderrStream<>FOutputStream then
- FreeStream(THandleStream(FStderrStream));
- FreeStream(THandleStream(FOutputStream));
- FreeStream(THandleStream(FInputStream));
- end;
- Function TProcess.GetExitStatus : Integer;
- begin
- GetRunning;
- Result:=FExitCode;
- end;
- Function TProcess.GetRunning : Boolean;
- begin
- IF FRunning then
- FRunning:=Not PeekExitStatus;
- Result:=FRunning;
- end;
- Procedure TProcess.CreateStreams(InHandle,OutHandle,ErrHandle : Longint);
- begin
- FreeStreams;
- FInputStream:=TOutputPipeStream.Create (InHandle);
- FOutputStream:=TInputPipeStream.Create (OutHandle);
- if Not (poStderrToOutput in FProcessOptions) then
- FStderrStream:=TInputPipeStream.Create(ErrHandle);
- end;
- procedure TProcess.FreeStream(var AStream: THandleStream);
- begin
- if AStream = nil then exit;
- FreeAndNil(AStream);
- end;
- procedure TProcess.Loaded;
- begin
- inherited Loaded;
- If (csDesigning in ComponentState) and (CommandLine<>'') then
- ConvertCommandLine;
- end;
- procedure TProcess.CloseInput;
- begin
- FreeStream(THandleStream(FInputStream));
- end;
- procedure TProcess.CloseOutput;
- begin
- FreeStream(THandleStream(FOutputStream));
- end;
- procedure TProcess.CloseStderr;
- begin
- FreeStream(THandleStream(FStderrStream));
- end;
- Procedure TProcess.SetWindowColumns (Value : Cardinal);
- begin
- if Value<>0 then
- Include(FStartupOptions,suoUseCountChars);
- dwXCountChars:=Value;
- end;
- Procedure TProcess.SetWindowHeight (Value : Cardinal);
- begin
- if Value<>0 then
- include(FStartupOptions,suoUsePosition);
- dwYSize:=Value;
- end;
- Procedure TProcess.SetWindowLeft (Value : Cardinal);
- begin
- if Value<>0 then
- Include(FStartupOptions,suoUseSize);
- dwx:=Value;
- end;
- Procedure TProcess.SetWindowTop (Value : Cardinal);
- begin
- if Value<>0 then
- Include(FStartupOptions,suoUsePosition);
- dwy:=Value;
- end;
- Procedure TProcess.SetWindowWidth (Value : Cardinal);
- begin
- If (Value<>0) then
- Include(FStartupOptions,suoUseSize);
- dwXSize:=Value;
- end;
- Function TProcess.GetWindowRect : TRect;
- begin
- With Result do
- begin
- Left:=dwx;
- Right:=dwx+dwxSize;
- Top:=dwy;
- Bottom:=dwy+dwysize;
- end;
- end;
- procedure TProcess.SetCommandLine(const AValue: String);
- begin
- if FCommandLine=AValue then exit;
- FCommandLine:=AValue;
- If Not (csLoading in ComponentState) then
- ConvertCommandLine;
- end;
- procedure TProcess.SetParameters(const AValue: TStrings);
- begin
- FParameters.Assign(AValue);
- end;
- Procedure TProcess.SetWindowRect (Value : Trect);
- begin
- Include(FStartupOptions,suoUseSize);
- Include(FStartupOptions,suoUsePosition);
- With Value do
- begin
- dwx:=Left;
- dwxSize:=Right-Left;
- dwy:=Top;
- dwySize:=Bottom-top;
- end;
- end;
- Procedure TProcess.SetWindowRows (Value : Cardinal);
- begin
- if Value<>0 then
- Include(FStartupOptions,suoUseCountChars);
- dwYCountChars:=Value;
- end;
- procedure TProcess.SetApplicationName(const Value: String);
- begin
- FApplicationName := Value;
- If (csDesigning in ComponentState) and
- (FCommandLine='') then
- FCommandLine:=Value;
- end;
- procedure TProcess.SetProcessOptions(const Value: TProcessOptions);
- begin
- FProcessOptions := Value;
- If poNewConsole in FProcessOptions then
- Exclude(FProcessOptions,poNoConsole);
- if poRunSuspended in FProcessOptions then
- Exclude(FProcessOptions,poWaitOnExit);
- end;
- procedure TProcess.SetActive(const Value: Boolean);
- begin
- if (Value<>GetRunning) then
- If Value then
- Execute
- else
- Terminate(0);
- end;
- procedure TProcess.SetEnvironment(const Value: TStrings);
- begin
- FEnvironment.Assign(Value);
- end;
- procedure TProcess.ConvertCommandLine;
- begin
- FParameters.Clear;
- CommandToList(CommandLine,FParameters);
- If FParameters.Count>0 then
- begin
- Executable:=FParameters[0];
- FParameters.Delete(0);
- end;
- end;
- Const
- READ_BYTES = 65536; // not too small to avoid fragmentation when reading large files.
- // helperfunction that does the bulk of the work.
- function internalRuncommand(p:TProcess;var outputstring:string;var exitstatus:integer):integer;
- var
- numbytes,bytesread : integer;
- begin
- result:=-1;
- try
- try
- p.Options := [poUsePipes];
- bytesread:=0;
- p.Execute;
- while p.Running do
- begin
- Setlength(outputstring,BytesRead + READ_BYTES);
- NumBytes := p.Output.Read(outputstring[1+bytesread], READ_BYTES);
- if NumBytes > 0 then
- Inc(BytesRead, NumBytes)
- else
- Sleep(100);
- end;
- repeat
- Setlength(outputstring,BytesRead + READ_BYTES);
- NumBytes := p.Output.Read(outputstring[1+bytesread], READ_BYTES);
- if NumBytes > 0 then
- Inc(BytesRead, NumBytes);
- until NumBytes <= 0;
- setlength(outputstring,BytesRead);
- exitstatus:=p.exitstatus;
- result:=0; // we came to here, document that.
- except
- on e : Exception do
- begin
- result:=1;
- setlength(outputstring,BytesRead);
- end;
- end;
- finally
- p.free;
- end;
- end;
- function RunCommandIndir(const curdir:string;const exename:string;const commands:array of string;var outputstring:string;var exitstatus:integer):integer;
- Var
- p : TProcess;
- i : integer;
- begin
- p:=TProcess.create(nil);
- p.Executable:=exename;
- if curdir<>'' then
- p.CurrentDirectory:=curdir;
- if high(commands)>=0 then
- for i:=low(commands) to high(commands) do
- p.Parameters.add(commands[i]);
- result:=internalruncommand(p,outputstring,exitstatus);
- end;
- function RunCommandInDir(const curdir,cmdline:string;var outputstring:string):boolean; deprecated;
- Var
- p : TProcess;
- exitstatus : integer;
- begin
- p:=TProcess.create(nil);
- p.commandline:=cmdline;
- if curdir<>'' then
- p.CurrentDirectory:=curdir;
- result:=internalruncommand(p,outputstring,exitstatus)=0;
- if exitstatus<>0 then result:=false;
- end;
- function RunCommandIndir(const curdir:string;const exename:string;const commands:array of string;var outputstring:string):boolean;
- Var
- p : TProcess;
- i,
- exitstatus : integer;
- begin
- p:=TProcess.create(nil);
- p.Executable:=exename;
- if curdir<>'' then
- p.CurrentDirectory:=curdir;
- if high(commands)>=0 then
- for i:=low(commands) to high(commands) do
- p.Parameters.add(commands[i]);
- result:=internalruncommand(p,outputstring,exitstatus)=0;
- if exitstatus<>0 then result:=false;
- end;
- function RunCommand(const cmdline:string;var outputstring:string):boolean; deprecated;
- Var
- p : TProcess;
- exitstatus : integer;
- begin
- p:=TProcess.create(nil);
- p.commandline:=cmdline;
- result:=internalruncommand(p,outputstring,exitstatus)=0;
- if exitstatus<>0 then result:=false;
- end;
- function RunCommand(const exename:string;const commands:array of string;var outputstring:string):boolean;
- Var
- p : TProcess;
- i,
- exitstatus : integer;
- begin
- p:=TProcess.create(nil);
- p.Executable:=exename;
- if high(commands)>=0 then
- for i:=low(commands) to high(commands) do
- p.Parameters.add(commands[i]);
- result:=internalruncommand(p,outputstring,exitstatus)=0;
- if exitstatus<>0 then result:=false;
- end;
- end.
|