diff options
Diffstat (limited to 'lib/process.nim')
-rwxr-xr-x | lib/process.nim | 1009 |
1 files changed, 1009 insertions, 0 deletions
diff --git a/lib/process.nim b/lib/process.nim new file mode 100755 index 000000000..ebeeb3f47 --- /dev/null +++ b/lib/process.nim @@ -0,0 +1,1009 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2006 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + + +interface + +type + TProcess = opaque + +proc + open(out p: TProcess, command, workingDir: string, + +implementation + + +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 + TProcess = Class (TComponent) + Private + FProcessOptions : TProcessOptions; + FStartupOptions : TStartupOptions; + FProcessID : Integer; + FThreadID : Integer; + FProcessHandle : Thandle; + FThreadHandle : Thandle; + FFillAttribute : Cardinal; + FApplicationName : string; + FConsoleTitle : String; + FCommandLine : String; + FCurrentDirectory : String; + FDeskTop : String; + FEnvironment : Tstrings; + FExitCode : Cardinal; + FShowWindow : TShowWindowOptions; + FInherithandles : Boolean; + FInputSTream : TOutputPipeStream; + FOutputStream : TInPutPipeStream; + FStdErrStream : TInputPipeStream; + FRunning : Boolean; + FPRocessPriority : TProcessPriority; + dwXCountchars, + dwXSize, + dwYsize, + dwx, + dwYcountChars, + dwy : Cardinal; + Procedure FreeStreams; + Function GetExitStatus : Integer; + Function GetRunning : Boolean; + Function GetWindowRect : TRect; + 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 CreateStreams(InHandle,OutHandle,Errhandle : Longint); + procedure SetApplicationname(const Value: String); + procedure SetProcessOptions(const Value: TProcessOptions); + procedure SetActive(const Value: Boolean); + procedure SetEnvironment(const Value: TStrings); + function PeekExitStatus: Boolean; + procedure CloseProcessHandles; + Public + Constructor Create (AOwner : TComponent);override; + Destructor Destroy; override; + Procedure Execute; virtual; + Function Resume : Integer; virtual; + Function Suspend : Integer; virtual; + Function Terminate (AExitCode : Integer): Boolean; virtual; + Function WaitOnExit : DWord; + 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; + Published + Property Active : Boolean Read Getrunning Write SetActive; + Property ApplicationName : String Read FApplicationname Write SetApplicationname; + Property CommandLine : String Read FCommandLine Write FCommandLine; + 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; + end; + +implementation + +{ + Win32 Process .inc. +} + +uses Windows; + +Const + PriorityConstants : Array [TProcessPriority] of Cardinal = + (HIGH_PRIORITY_CLASS,IDLE_PRIORITY_CLASS, + NORMAL_PRIORITY_CLASS,REALTIME_PRIORITY_CLASS); + +procedure TProcess.CloseProcessHandles; +begin + if (FProcessHandle<>0) then + CloseHandle(FProcessHandle); + if (FThreadHandle<>0) then + CloseHandle(FThreadHandle); +end; + +Function TProcess.PeekExitStatus : Boolean; + +begin + GetExitCodeProcess(ProcessHandle,FExitCode); + Result:=(FExitCode<>Still_Active); +end; + +Function GetStartupFlags (P : TProcess): Cardinal; + +begin + With P do + begin + Result:=0; + if poUsePipes in FProcessOptions then + Result:=Result or Startf_UseStdHandles; + if suoUseShowWindow in FStartupOptions then + Result:=Result or startf_USESHOWWINDOW; + if suoUSESIZE in FStartupOptions then + Result:=Result or startf_usesize; + if suoUsePosition in FStartupOptions then + Result:=Result or startf_USEPOSITION; + if suoUSECOUNTCHARS in FStartupoptions then + Result:=Result or startf_usecountchars; + if suoUsefIllAttribute in FStartupOptions then + Result:=Result or startf_USEFILLATTRIBUTE; + end; +end; + +Function GetCreationFlags(P : TProcess) : Cardinal; + +begin + With P do + begin + Result:=0; + if poNoConsole in FProcessOptions then + Result:=Result or Detached_Process; + if poNewConsole in FProcessOptions then + Result:=Result or Create_new_console; + if poNewProcessGroup in FProcessOptions then + Result:=Result or CREATE_NEW_PROCESS_GROUP; + If poRunSuspended in FProcessOptions Then + Result:=Result or Create_Suspended; + if poDebugProcess in FProcessOptions Then + Result:=Result or DEBUG_PROCESS; + if poDebugOnlyThisProcess in FProcessOptions Then + Result:=Result or DEBUG_ONLY_THIS_PROCESS; + if poDefaultErrorMode in FProcessOptions Then + Result:=Result or CREATE_DEFAULT_ERROR_MODE; + result:=result or PriorityConstants[FProcessPriority]; + end; +end; + +Function StringsToPChars(List : TStrings): pointer; + +var + EnvBlock: string; + I: Integer; + +begin + EnvBlock := ''; + For I:=0 to List.Count-1 do + EnvBlock := EnvBlock + List[i] + #0; + EnvBlock := EnvBlock + #0; + GetMem(Result, Length(EnvBlock)); + CopyMemory(Result, @EnvBlock[1], Length(EnvBlock)); +end; + +Procedure InitProcessAttributes(P : TProcess; Var PA : TSecurityAttributes); + +begin + FillChar(PA,SizeOf(PA),0); + PA.nLength := SizeOf(PA); +end; + +Procedure InitThreadAttributes(P : TProcess; Var TA : TSecurityAttributes); + +begin + FillChar(TA,SizeOf(TA),0); + TA.nLength := SizeOf(TA); +end; + +Procedure InitStartupInfo(P : TProcess; Var SI : STARTUPINFO); + +Const + SWC : Array [TShowWindowOptions] of Cardinal = + (0,SW_HIDE,SW_Maximize,SW_Minimize,SW_Restore,SW_Show, + SW_ShowDefault,SW_ShowMaximized,SW_ShowMinimized, + SW_showMinNOActive,SW_ShowNA,SW_ShowNoActivate,SW_ShowNormal); + +begin + FillChar(SI,SizeOf(SI),0); + With SI do + begin + dwFlags:=GetStartupFlags(P); + if P.FShowWindow<>swoNone then + dwFlags:=dwFlags or Startf_UseShowWindow + else + dwFlags:=dwFlags and not Startf_UseShowWindow; + wShowWindow:=SWC[P.FShowWindow]; + if (poUsePipes in P.Options) then + begin + dwFlags:=dwFlags or Startf_UseStdHandles; + end; + if P.FillAttribute<>0 then + begin + dwFlags:=dwFlags or Startf_UseFillAttribute; + dwFillAttribute:=P.FillAttribute; + end; + dwXCountChars:=P.WindowColumns; + dwYCountChars:=P.WindowRows; + dwYsize:=P.WindowHeight; + dwXsize:=P.WindowWidth; + dwy:=P.WindowTop; + dwX:=P.WindowLeft; + end; +end; + +Procedure CreatePipes(Var HI,HO,HE : Thandle; Var SI : TStartupInfo; CE : Boolean); + + Procedure DoCreatePipeHandles(Var H1,H2 : THandle); + + Var + I,O : Longint; + + begin + CreatePipeHandles(I,O); + H1:=Thandle(I); + H2:=THandle(O); + end; + + + + +begin + DoCreatePipeHandles(SI.hStdInput,HI); + DoCreatePipeHandles(HO,Si.hStdOutput); + if CE then + DoCreatePipeHandles(HE,SI.hStdError) + else + begin + SI.hStdError:=SI.hStdOutput; + HE:=HO; + end; +end; + + +Procedure TProcess.Execute; + + +Var + PName,PDir,PCommandLine : PChar; + FEnv: pointer; + FCreationFlags : Cardinal; + FProcessAttributes : TSecurityAttributes; + FThreadAttributes : TSecurityAttributes; + FProcessInformation : TProcessInformation; + FStartupInfo : STARTUPINFO; + HI,HO,HE : THandle; + +begin + FInheritHandles:=True; + PName:=Nil; + PCommandLine:=Nil; + PDir:=Nil; + If FApplicationName<>'' then + PName:=Pchar(FApplicationName); + If FCommandLine<>'' then + PCommandLine:=Pchar(FCommandLine); + If FCurrentDirectory<>'' then + PDir:=Pchar(FCurrentDirectory); + if FEnvironment.Count<>0 then + FEnv:=StringsToPChars(FEnvironment) + else + FEnv:=Nil; + Try + FCreationFlags:=GetCreationFlags(Self); + InitProcessAttributes(Self,FProcessAttributes); + InitThreadAttributes(Self,FThreadAttributes); + InitStartupInfo(Self,FStartUpInfo); + If poUsePipes in FProcessOptions then + CreatePipes(HI,HO,HE,FStartupInfo,Not(poStdErrToOutPut in FProcessOptions)); + Try + If Not CreateProcess (PName,PCommandLine,@FProcessAttributes,@FThreadAttributes, + FInheritHandles,FCreationFlags,FEnv,PDir,FStartupInfo, + fProcessInformation) then + Raise Exception.CreateFmt('Failed to execute %s : %d',[FCommandLine,GetLastError]); + FProcessHandle:=FProcessInformation.hProcess; + FThreadHandle:=FProcessInformation.hThread; + FProcessID:=FProcessINformation.dwProcessID; + Finally + if POUsePipes in FProcessOptions then + begin + FileClose(FStartupInfo.hStdInput); + FileClose(FStartupInfo.hStdOutput); + if Not (poStdErrToOutPut in FProcessOptions) then + FileClose(FStartupInfo.hStdError); + CreateStreams(HI,HO,HE); + end; + end; + FRunning:=True; + Finally + If FEnv<>Nil then + FreeMem(FEnv); + end; + if not (csDesigning in ComponentState) and // This would hang the IDE ! + (poWaitOnExit in FProcessOptions) and + not (poRunSuspended in FProcessOptions) then + WaitOnExit; +end; + +Function TProcess.WaitOnExit : Dword; + +begin + Result:=WaitForSingleObject (FProcessHandle,Infinite); + If Result<>Wait_Failed then + GetExitStatus; + FRunning:=False; +end; + +Function TProcess.Suspend : Longint; + +begin + Result:=SuspendThread(ThreadHandle); +end; + +Function TProcess.Resume : LongInt; + +begin + Result:=ResumeThread(ThreadHandle); +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; + +begin + Result:=False; + If ExitStatus=Still_active then + Result:=TerminateProcess(Handle,AexitCode); +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); + + +begin + FShowWindow:=Value; +end; + +// ---------------------------- end of platform dependant code -------------- + +{ + Unix Process .inc. +} + +uses + Unix, + Baseunix; + + + +Const + PriorityConstants : Array [TProcessPriority] of Integer = + (20,20,0,-20); + +Const + GeometryOption : String = '-geometry'; + TitleOption : String ='-title'; + + + +procedure TProcess.CloseProcessHandles; + +begin + // Do nothing. Win32 call. +end; + +Function TProcess.PeekExitStatus : Boolean; + +begin + Result:=fpWaitPid(Handle,@FExitCode,WNOHANG)=Handle; + If Result then + FExitCode:=wexitstatus(FExitCode) + else + FexitCode:=0; +end; + +Type + TPCharArray = Array[Word] of pchar; + PPCharArray = ^TPcharArray; + +Function StringsToPCharList(List : TStrings) : PPChar; + +Var + I : Integer; + S : String; + +begin + I:=(List.Count)+1; + GetMem(Result,I*sizeOf(PChar)); + PPCharArray(Result)^[List.Count]:=Nil; + For I:=0 to List.Count-1 do + begin + S:=List[i]; + Result[i]:=StrNew(PChar(S)); + end; +end; + +Procedure FreePCharList(List : PPChar); + +Var + I : integer; + +begin + I:=0; + While List[i]<>Nil do + begin + StrDispose(List[i]); + Inc(I); + end; + FreeMem(List); +end; + + +Procedure CommandToList(S : String; List : TStrings); + + Function GetNextWord : String; + + Const + WhiteSpace = [' ',#8,#10]; + 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); + Result:=StringReplace(Result,'"','',[rfReplaceAll]); + Result:=StringReplace(Result,'''','',[rfReplaceAll]); + 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; + + +Function MakeCommand(P : TProcess) : PPchar; + +Const + SNoCommandLine = 'Cannot execute empty command-line'; + +Var + Cmd : String; + S : TStringList; + G : String; + +begin + if (P.ApplicationName='') then + begin + If (P.CommandLine='') then + Raise Exception.Create(SNoCommandline); + Cmd:=P.CommandLine; + end + else + begin + If (P.CommandLine='') then + Cmd:=P.ApplicationName + else + Cmd:=P.CommandLine; + end; + S:=TStringList.Create; + try + CommandToList(Cmd,S); + if poNewConsole in P.Options then + begin + S.Insert(0,'-e'); + If (P.ApplicationName<>'') then + begin + S.Insert(0,P.ApplicationName); + S.Insert(0,'-title'); + end; + if suoUseCountChars in P.StartupOptions then + begin + S.Insert(0,Format('%dx%d',[P.dwXCountChars,P.dwYCountChars])); + S.Insert(0,'-geometry'); + end; + S.Insert(0,'xterm'); + end; + if (P.ApplicationName<>'') then + begin + S.Add(TitleOption); + S.Add(P.ApplicationName); + end; + G:=''; + if (suoUseSize in P.StartupOptions) then + g:=format('%dx%d',[P.dwXSize,P.dwYsize]); + if (suoUsePosition in P.StartupOptions) then + g:=g+Format('+%d+%d',[P.dwX,P.dwY]); + if G<>'' then + begin + S.Add(GeometryOption); + S.Add(g); + end; + Result:=StringsToPcharList(S); + Finally + S.free; + end; +end; + +Function GetLastError : Integer; + +begin + Result:=-1; +end; + +Type + TPipeEnd = (peRead,peWrite); + TPipePair = Array[TPipeEnd] of Integer; + +Procedure CreatePipes(Var HI,HO,HE : TPipePair; CE : Boolean); + + Procedure CreatePair(Var P : TPipePair); + + begin + If not CreatePipeHandles(P[peRead],P[peWrite]) then + Raise Exception.Create('Failed to create pipes'); + end; + + Procedure ClosePair(Var P : TPipePair); + + begin + if (P[peRead]<>-1) then + FileClose(P[peRead]); + if (P[peWrite]<>-1) then + FileClose(P[peWrite]); + end; + +begin + HO[peRead]:=-1;HO[peWrite]:=-1; + HI[peRead]:=-1;HI[peWrite]:=-1; + HE[peRead]:=-1;HE[peWrite]:=-1; + Try + CreatePair(HO); + CreatePair(HI); + If CE then + CreatePair(HE); + except + ClosePair(HO); + ClosePair(HI); + If CE then + ClosePair(HE); + Raise; + end; +end; + +Procedure TProcess.Execute; + +Var + HI,HO,HE : TPipePair; + PID : Longint; + FEnv : PPChar; + Argv : PPChar; + fd : Integer; + PName : String; + +begin + If (poUsePipes in FProcessOptions) then + CreatePipes(HI,HO,HE,Not (poStdErrToOutPut in FProcessOptions)); + Try + if FEnvironment.Count<>0 then + FEnv:=StringsToPcharList(FEnvironment) + else + FEnv:=Nil; + Try + Argv:=MakeCommand(Self); + Try + If (Argv<>Nil) and (ArgV[0]<>Nil) then + PName:=StrPas(Argv[0]) + else + begin + // This should never happen, actually. + PName:=ApplicationName; + If (PName='') then + PName:=CommandLine; + end; + if (pos('/',PName)<>1) then + PName:=FileSearch(Pname,fpgetenv('PATH')); + Pid:=fpfork; + if Pid<0 then + Raise Exception.Create('Failed to Fork process'); + if (PID>0) then + begin + // Parent process. Copy process information. + FProcessHandle:=PID; + FThreadHandle:=PID; + FProcessId:=PID; + //FThreadId:=PID; + end + else + begin + { We're in the child } + if (FCurrentDirectory<>'') then + ChDir(FCurrentDirectory); + if PoUsePipes in Options then + begin + fpdup2(HI[peRead],0); + fpdup2(HO[peWrite],1); + if (poStdErrToOutPut in Options) then + fpdup2(HO[peWrite],2) + else + fpdup2(HE[peWrite],2); + end + else if poNoConsole in Options then + begin + fd:=FileOpen('/dev/null',fmOpenReadWrite); + fpdup2(fd,0); + fpdup2(fd,1); + fpdup2(fd,2); + end; + if (poRunSuspended in Options) then + sigraise(SIGSTOP); + if FEnv<>Nil then + fpexecve(PName,Argv,Fenv) + else + fpexecv(PName,argv); + Halt(127); + end + Finally + FreePcharList(Argv); + end; + Finally + If (FEnv<>Nil) then + FreePCharList(FEnv); + end; + Finally + if POUsePipes in FProcessOptions then + begin + FileClose(HO[peWrite]); + FileClose(HI[peRead]); + if Not (poStdErrToOutPut in FProcessOptions) then + FileClose(HE[peWrite]); + CreateStreams(HI[peWrite],HO[peRead],HE[peRead]); + end; + end; + FRunning:=True; + if not (csDesigning in ComponentState) and // This would hang the IDE ! + (poWaitOnExit in FProcessOptions) and + not (poRunSuspended in FProcessOptions) then + WaitOnExit; +end; + +Function TProcess.WaitOnExit : Dword; + +begin + Result:=fpWaitPid(Handle,@FExitCode,0); + If Result=Handle then + FExitCode:=WexitStatus(FExitCode); + FRunning:=False; +end; + +Function TProcess.Suspend : Longint; + +begin + If fpkill(Handle,SIGSTOP)<>0 then + Result:=-1 + else + Result:=1; +end; + +Function TProcess.Resume : LongInt; + +begin + If fpKill(Handle,SIGCONT)<>0 then + Result:=-1 + else + Result:=0; +end; + +Function TProcess.Terminate(AExitCode : Integer) : Boolean; + +begin + Result:=False; + Result:=fpkill(Handle,SIGTERM)=0; + If Result then + begin + If Running then + Result:=fpkill(Handle,SIGKILL)=0; + end; + GetExitStatus; +end; + +Procedure TProcess.SetShowWindow (Value : TShowWindowOptions); + +begin + FShowWindow:=Value; +end; + +// --------------------------------------------------------------------------- + + +Constructor TProcess.Create (AOwner : TComponent); +begin + Inherited; + FProcessPriority:=ppNormal; + FShowWindow:=swoNone; + FInheritHandles:=True; + FEnvironment:=TStringList.Create; +end; + +Destructor TProcess.Destroy; + +begin + FEnvironment.Free; + FreeStreams; + CloseProcessHandles; + Inherited Destroy; +end; + +Procedure TProcess.FreeStreams; + + procedure FreeStream(var S: THandleStream); + + begin + if (S<>Nil) then + begin + FileClose(S.Handle); + FreeAndNil(S); + end; + end; + +begin + If FStdErrStream<>FOutputStream then + FreeStream(FStdErrStream); + FreeStream(FOutputStream); + FreeStream(FInputStream); +end; + + +Function TProcess.GetExitStatus : Integer; + +begin + If FRunning then + PeekExitStatus; + 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.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.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; + +function CallProcess(const command: string): string; +const + READ_BYTES = 2048; +// executes the command and returns the program's output +var + M: TMemoryStream; + P: TProcess; + n: LongInt; + BytesRead: LongInt; +begin + // We cannot use poWaitOnExit here since we don't + // know the size of the output. On Linux the size of the + // output pipe is 2 kB. If the output data is more, we + // need to read the data. This isn't possible since we are + // waiting. So we get a deadlock here. + // + // A temp Memorystream is used to buffer the output + + M := TMemoryStream.Create; + BytesRead := 0; + + P := TProcess.Create(nil); + P.CommandLine := Command; + P.Options := [poUsePipes]; + P.Execute; + while P.Running do begin + // make sure we have room + M.SetSize(BytesRead + READ_BYTES); + + // try reading it + n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES); + if n > 0 then + Inc(BytesRead, n) + else + // no data, wait 100 ms + Sleep(100) + end; + // read last part + repeat + // make sure we have room + M.SetSize(BytesRead + READ_BYTES); + // try reading it + n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES); + if n > 0 then Inc(BytesRead, n) + until n <= 0; + M.SetSize(BytesRead); + + setLength(result, bytesRead); + m.read(result[1], bytesRead); + P.Free; M.Free; +end; + +end. |