process.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. unit process;
  14. interface
  15. Uses Classes,
  16. pipes,
  17. {$ifdef Unix}
  18. {$ifdef ver1_0}
  19. Linux,
  20. {$else}
  21. Baseunix,unix,
  22. {$endif}
  23. {$else}
  24. Windows,
  25. {$endif}
  26. SysUtils;
  27. Type
  28. TProcessOption = (poRunSuspended,poWaitOnExit,
  29. poUsePipes,poStderrToOutPut,
  30. poNoConsole,poNewConsole,
  31. poDefaultErrorMode,poNewProcessGroup,
  32. poDebugProcess,poDebugOnlyThisProcess);
  33. TShowWindowOptions = (swoNone,swoHIDE,swoMaximize,swoMinimize,swoRestore,swoShow,
  34. swoShowDefault,swoShowMaximized,swoShowMinimized,
  35. swoshowMinNOActive,swoShowNA,swoShowNoActivate,swoShowNormal);
  36. TStartupOption = (suoUseShowWindow,suoUseSize,suoUsePosition,
  37. suoUseCountChars,suoUseFillAttribute);
  38. TProcessPriority = (ppHigh,ppIdle,ppNormal,ppRealTime);
  39. TProcessOptions = Set of TPRocessOption;
  40. TstartUpoptions = set of TStartupOption;
  41. {$ifdef unix}
  42. Const
  43. STARTF_USESHOWWINDOW = 1; // Ignored
  44. STARTF_USESIZE = 2;
  45. STARTF_USEPOSITION = 4;
  46. STARTF_USECOUNTCHARS = 8; // Ignored
  47. STARTF_USEFILLATTRIBUTE = $10;
  48. STARTF_RUNFULLSCREEN = $20; // Ignored
  49. STARTF_FORCEONFEEDBACK = $40; // Ignored
  50. STARTF_FORCEOFFFEEDBACK = $80; // Ignored
  51. STARTF_USESTDHANDLES = $100; // Ignored
  52. STARTF_USEHOTKEY = $200; // Ignored
  53. Type
  54. PProcessInformation = ^TProcessInformation;
  55. TProcessInformation = record
  56. hProcess: THandle;
  57. hThread: THandle;
  58. dwProcessId: DWORD;
  59. dwThreadId: DWORD;
  60. end;
  61. PStartupInfo = ^TStartupInfo;
  62. TStartupInfo = Record
  63. cb: DWORD;
  64. lpReserved: Pointer;
  65. lpDesktop: Pointer;
  66. lpTitle: Pointer;
  67. dwX: DWORD;
  68. dwY: DWORD;
  69. dwXSize: DWORD;
  70. dwYSize: DWORD;
  71. dwXCountChars: DWORD;
  72. dwYCountChars: DWORD;
  73. dwFillAttribute: DWORD;
  74. dwFlags: DWORD;
  75. wShowWindow: Word;
  76. cbReserved2: Word;
  77. lpReserved2: PByte;
  78. hStdInput: THandle;
  79. hStdOutput: THandle;
  80. hStdError: THandle;
  81. end;
  82. PSecurityAttributes = ^TSecurityAttributes;
  83. TSecurityAttributes = Record
  84. nlength : Integer;
  85. lpSecurityDescriptor : Pointer;
  86. BinheritHandle : Boolean;
  87. end;
  88. Const piInheritablePipe : TSecurityAttributes = (
  89. nlength:SizeOF(TSecurityAttributes);
  90. lpSecurityDescriptor:Nil;
  91. Binherithandle:True);
  92. piNonInheritablePipe : TSecurityAttributes = (
  93. nlength:SizeOF(TSecurityAttributes);
  94. lpSecurityDescriptor:Nil;
  95. Binherithandle:False);
  96. {$endif}
  97. Type
  98. TProcess = Class (TComponent)
  99. Private
  100. {$ifndef unix}
  101. FAccess : Cardinal;
  102. {$endif}
  103. FApplicationName : string;
  104. FChildErrorStream : TOutPutPipeStream;
  105. FChildInputSTream : TInputPipeStream;
  106. FChildOutPutStream : TOutPutPipeStream;
  107. FConsoleTitle : String;
  108. FProcessOptions : TProcessOptions;
  109. FStartUpOptions : TStartupOptions;
  110. FCommandLine : String;
  111. FCurrentDirectory : String;
  112. FDeskTop : String;
  113. FEnvironment : Tstrings;
  114. FExitCode : Cardinal;
  115. FHandle : THandle;
  116. FShowWindow : TShowWindowOptions;
  117. FInherithandles : LongBool;
  118. FParentErrorStream : TInputPipeStream;
  119. FParentInputSTream : TInputPipeStream;
  120. FParentOutputStream : TOutPutPipeStream;
  121. FRunning : Boolean;
  122. FThreadAttributes : PSecurityAttributes;
  123. FProcessAttributes : PSecurityAttributes;
  124. FProcessInformation : TProcessInformation;
  125. FPRocessPriority : TProcessPriority;
  126. FStartupInfo : TStartupInfo;
  127. Procedure FreeStreams;
  128. Function GetExitStatus : Integer;
  129. Function GetHandle : THandle;
  130. Function GetRunning : Boolean;
  131. Function GetProcessAttributes : TSecurityAttributes;
  132. Function GetThreadAttributes : TSecurityAttributes;
  133. Procedure SetProcessAttributes (Value : TSecurityAttributes);
  134. Procedure SetThreadAttributes (Value : TSecurityAttributes);
  135. Function GetWindowRect : TRect;
  136. Procedure SetWindowRect (Value : TRect);
  137. Procedure SetFillAttribute (Value : Cardinal);
  138. Procedure SetShowWindow (Value : TShowWindowOptions);
  139. Procedure SetWindowColumns (Value : Cardinal);
  140. Procedure SetWindowHeight (Value : Cardinal);
  141. Procedure SetWindowLeft (Value : Cardinal);
  142. Procedure SetWindowRows (Value : Cardinal);
  143. Procedure SetWindowTop (Value : Cardinal);
  144. Procedure SetWindowWidth (Value : Cardinal);
  145. procedure CreateStreams;
  146. function GetCreationFlags: Cardinal;
  147. function GetStartupFlags: Cardinal;
  148. procedure SetApplicationname(const Value: String);
  149. procedure SetPRocessOptions(const Value: TProcessOptions);
  150. procedure SetActive(const Value: Boolean);
  151. procedure SetEnvironment(const Value: TStrings);
  152. {$ifdef unix}
  153. function PeekLinuxExitStatus: Boolean;
  154. {$endif}
  155. Public
  156. Constructor Create (AOwner : TComponent);override;
  157. Destructor Destroy; override;
  158. Procedure Execute; virtual;
  159. Function Resume : Integer; virtual;
  160. Function Suspend : Integer; virtual;
  161. Function Terminate (AExitCode : Integer): Boolean; virtual;
  162. Function WaitOnExit : DWord;
  163. Property WindowRect : Trect Read GetWindowRect Write SetWindowRect;
  164. Property StartupInfo : TStartupInfo Read FStartupInfo;
  165. Property ProcessAttributes : TSecurityAttributes Read GetProcessAttributes Write SetProcessAttributes;
  166. Property ProcessInformation : TProcessInformation Read FPRocessInformation;
  167. Property Handle : THandle Read FProcessInformation.hProcess;
  168. Property ThreadHandle : THandle Read FprocessInformation.hThread;
  169. Property Input : TOutPutPipeStream Read FParentOutPutStream;
  170. Property OutPut : TInputPipeStream Read FParentInputStream;
  171. Property StdErr : TinputPipeStream Read FParentErrorStream;
  172. Property ExitStatus : Integer Read GetExitStatus;
  173. Property InheritHandles : LongBool Read FInheritHandles Write FInheritHandles;
  174. Property ThreadAttributes : TSecurityAttributes Read GetThreadAttributes Write SetThreadAttributes;
  175. Published
  176. Property Active : Boolean Read Getrunning Write SetActive;
  177. Property ApplicationName : String Read FApplicationname Write SetApplicationname;
  178. Property CommandLine : String Read FCommandLine Write FCommandLine;
  179. Property ConsoleTitle : String Read FConsoleTitle Write FConsoleTitle;
  180. Property CurrentDirectory : String Read FCurrentDirectory Write FCurrentDirectory;
  181. Property DeskTop : String Read FDeskTop Write FDeskTop;
  182. Property Environment : TStrings Read FEnvironment Write SetEnvironment;
  183. Property FillAttribute : Cardinal Read FStartupInfo.dwFillAttribute Write SetFillAttribute;
  184. Property Options : TProcessOptions Read FProcessOptions Write SetPRocessOptions;
  185. Property Priority : TProcessPriority Read FProcessPriority Write FProcessPriority;
  186. Property StartUpOptions : TStartUpOptions Read FStartUpOptions Write FStartupOptions;
  187. Property Running : Boolean Read GetRunning;
  188. Property ShowWindow : TShowWindowOptions Read FShowWindow Write SetShowWindow;
  189. Property WindowColumns : Cardinal Read FStartupInfo.dwXCountchars Write SetWindowColumns;
  190. Property WindowHeight : Cardinal Read FStartupInfo.dwYsize Write SetWindowHeight;
  191. Property WindowLeft : Cardinal Read FStartupInfo.dwx Write SetWindowLeft;
  192. Property WindowRows : Cardinal Read FStartupInfo.dwYcountChars Write SetWindowRows;
  193. Property WindowTop : Cardinal Read FStartupInfo.dwy Write SetWindowTop ;
  194. Property WindowWidth : Cardinal Read FStartupInfo.dwXsize Write SetWindowWidth;
  195. end;
  196. {$ifdef unix}
  197. Const
  198. PriorityConstants : Array [TProcessPriority] of Integer =
  199. (20,20,0,-20);
  200. Const
  201. GeometryOption : String = '-geometry';
  202. TitleOption : String ='-title';
  203. {$else}
  204. Const
  205. PriorityConstants : Array [TProcessPriority] of Cardinal =
  206. (HIGH_PRIORITY_CLASS,IDLE_PRIORITY_CLASS,
  207. NORMAL_PRIORITY_CLASS,REALTIME_PRIORITY_CLASS);
  208. {$endif}
  209. implementation
  210. Constructor TProcess.Create (AOwner : TComponent);
  211. begin
  212. Inherited;
  213. {$ifndef unix}
  214. FAccess:=PROCESS_ALL_ACCESS;
  215. {$endif}
  216. FProcessPriority:=ppNormal;
  217. FShowWindow:=swoNone;
  218. FStartupInfo.cb:=SizeOf(TStartupInfo);
  219. FInheritHandles:=True;
  220. FEnvironment:=TStringList.Create;
  221. end;
  222. Destructor TProcess.Destroy;
  223. begin
  224. If assigned (FProcessAttributes) then Dispose (FPRocessAttributes);
  225. If assigned (FThreadAttributes) then Dispose (FThreadAttributes);
  226. FEnvironment.Free;
  227. FreeStreams;
  228. Inherited Destroy;
  229. end;
  230. Procedure TProcess.FreeStreams;
  231. var FreedStreams: TList;
  232. procedure FreeStream(var AnObject: THandleStream);
  233. begin
  234. if (AnObject<>Nil) and (FreedStreams.IndexOf(AnObject)<0) then
  235. begin
  236. FileClose(AnObject.Handle);
  237. FreedStreams.Add(AnObject);
  238. AnObject.Free;
  239. end;
  240. AnObject:=nil;
  241. end;
  242. begin
  243. FreedStreams:=TList.Create;
  244. try
  245. FreeStream(FParentErrorStream);
  246. FreeStream(FParentInputStream);
  247. FreeStream(FParentOutputStream);
  248. FreeStream(FChildErrorStream);
  249. FreeStream(FChildInputStream);
  250. FreeStream(FChildOutputStream);
  251. finally
  252. FreedStreams.Free;
  253. end;
  254. end;
  255. Function TProcess.GetExitStatus : Integer;
  256. begin
  257. If FRunning then
  258. {$ifdef unix}
  259. PeekLinuxExitStatus;
  260. {$else}
  261. GetExitCodeProcess(Handle,FExitCode);
  262. {$endif}
  263. Result:=FExitCode;
  264. end;
  265. Function TProcess.GetHandle : THandle;
  266. begin
  267. {$ifndef unix}
  268. If FHandle=0 Then
  269. FHandle:=OpenProcess (FAccess,True,FProcessInformation.dwProcessId);
  270. {$endif}
  271. Result:=FHandle
  272. end;
  273. Function TProcess.GetProcessAttributes : TSecurityAttributes;
  274. Var P : PSecurityAttributes;
  275. begin
  276. IF not Assigned(FProcessAttributes) then
  277. begin
  278. // Provide empty dummy value;
  279. New(p);
  280. Fillchar(p^,Sizeof(TSecurityAttributes),0);
  281. Result:=p^;
  282. end
  283. else
  284. REsult:=FProcessAttributes^;
  285. end;
  286. {$ifdef unix}
  287. Function TProcess.PeekLinuxExitStatus : Boolean;
  288. begin
  289. Result:={$ifdef VER1_0}WaitPID{$else}fpWaitPid{$endif}(Handle,@FExitCode,WNOHANG)=Handle;
  290. If Result then
  291. FExitCode:=wexitstatus(FExitCode)
  292. else
  293. FexitCode:=0;
  294. end;
  295. {$endif}
  296. Function TProcess.GetRunning : Boolean;
  297. begin
  298. IF FRunning then
  299. begin
  300. {$ifdef unix}
  301. FRunning:=Not PeekLinuxExitStatus;
  302. {$else}
  303. Frunning:=GetExitStatus=Still_Active;
  304. {$endif}
  305. end;
  306. Result:=FRunning;
  307. end;
  308. Function TProcess.GetThreadAttributes : TSecurityAttributes;
  309. Var P : PSecurityAttributes;
  310. begin
  311. IF not Assigned(FThreadAttributes) then
  312. begin
  313. // Provide empty dummy value;
  314. New(p);
  315. Fillchar(p^,Sizeof(TSecurityAttributes),0);
  316. Result:=p^;
  317. end
  318. else
  319. Result:=FThreadAttributes^;
  320. end;
  321. Procedure TProcess.SetProcessAttributes (Value : TSecurityAttributes);
  322. begin
  323. If not Assigned (FProcessAttributes) then
  324. New(FProcessAttributes);
  325. FPRocessAttributes^:=VAlue;
  326. end;
  327. Procedure TProcess.SetThreadAttributes (Value : TSecurityAttributes);
  328. begin
  329. If not Assigned (FThreadAttributes) then
  330. New(FThreadAttributes);
  331. FThreadAttributes^:=VAlue;
  332. end;
  333. Procedure TProcess.CreateStreams;
  334. begin
  335. FreeStreams;
  336. CreatePipeStreams (FChildInputSTream,FParentOutPutStream); //,@piInheritablePipe,1024);
  337. CreatePipeStreams (FParentInputStream,FChildOutPutStream); //,@piInheritablePipe,1024);
  338. if Not (poStdErrToOutPut in FProcessOptions) then
  339. CreatePipeStreams (FParentErrorStream,FChildErrorStream) //,@piInheritablePipe,1024)
  340. else
  341. begin
  342. FChildErrorStream:=FChildOutPutStream;
  343. FParentErrorStream:=FParentInputStream;
  344. end;
  345. FStartupInfo.dwFlags:=FStartupInfo.dwFlags or Startf_UseStdHandles;
  346. FStartupInfo.hStdInput:=FChildInputStream.Handle;
  347. FStartupInfo.hStdOutput:=FChildOutPutStream.Handle;
  348. FStartupInfo.hStdError:=FChildErrorStream.Handle;
  349. end;
  350. Function TProcess.GetCreationFlags : Cardinal;
  351. begin
  352. Result:=0;
  353. {$ifndef unix}
  354. if poNoConsole in FProcessOptions then
  355. Result:=Result or Detached_Process;
  356. if poNewConsole in FProcessOptions then
  357. Result:=Result or Create_new_console;
  358. if poNewProcessGroup in FProcessOptions then
  359. Result:=Result or CREATE_NEW_PROCESS_GROUP;
  360. If poRunSuspended in FProcessOptions Then
  361. Result:=Result or Create_Suspended;
  362. if poDebugProcess in FProcessOptions Then
  363. Result:=Result or DEBUG_PROCESS;
  364. if poDebugOnlyThisProcess in FProcessOptions Then
  365. Result:=Result or DEBUG_ONLY_THIS_PROCESS;
  366. if poDefaultErrorMode in FProcessOptions Then
  367. Result:=Result or CREATE_DEFAULT_ERROR_MODE;
  368. result:=result or PriorityConstants[FProcessPriority];
  369. {$endif}
  370. end;
  371. Function TProcess.GetStartupFlags : Cardinal;
  372. begin
  373. Result:=0;
  374. if poUsePipes in FProcessOptions then
  375. Result:=Result or Startf_UseStdHandles;
  376. if suoUseShowWindow in FStartupOptions then
  377. Result:=Result or startf_USESHOWWINDOW;
  378. if suoUSESIZE in FStartupOptions then
  379. Result:=Result or startf_usesize;
  380. if suoUsePosition in FStartupOptions then
  381. Result:=Result or startf_USEPOSITION;
  382. if suoUSECOUNTCHARS in FStartupoptions then
  383. Result:=Result or startf_usecountchars;
  384. if suoUsefIllAttribute in FStartupOptions then
  385. Result:=Result or startf_USEFILLATTRIBUTE;
  386. end;
  387. Type
  388. {$ifndef unix}
  389. PPChar = ^PChar;
  390. {$endif}
  391. TPCharArray = Array[Word] of pchar;
  392. PPCharArray = ^TPcharArray;
  393. Function StringsToPCharList(List : TStrings) : PPChar;
  394. Var
  395. I : Integer;
  396. S : String;
  397. begin
  398. I:=(List.Count)+1;
  399. GetMem(Result,I*sizeOf(PChar));
  400. PPCharArray(Result)^[List.Count]:=Nil;
  401. For I:=0 to List.Count-1 do
  402. begin
  403. S:=List[i];
  404. Result[i]:=StrNew(PChar(S));
  405. end;
  406. end;
  407. Procedure FreePCharList(List : PPChar);
  408. Var
  409. I : integer;
  410. begin
  411. I:=0;
  412. While List[i]<>Nil do
  413. begin
  414. StrDispose(List[i]);
  415. Inc(I);
  416. end;
  417. FreeMem(List);
  418. end;
  419. {$ifdef unix}
  420. Procedure CommandToList(S : String; List : TStrings);
  421. Function GetNextWord : String;
  422. Const
  423. WhiteSpace = [' ',#8,#10];
  424. Literals = ['"',''''];
  425. Var
  426. Wstart,wend : Integer;
  427. InLiteral : Boolean;
  428. LastLiteral : char;
  429. begin
  430. WStart:=1;
  431. While (WStart<=Length(S)) and (S[WStart] in WhiteSpace) do
  432. Inc(WStart);
  433. WEnd:=WStart;
  434. InLiteral:=False;
  435. LastLiteral:=#0;
  436. While (Wend<=Length(S)) and (Not (S[Wend] in WhiteSpace) or InLiteral) do
  437. begin
  438. if S[Wend] in Literals then
  439. If InLiteral then
  440. InLiteral:=Not (S[Wend]=LastLiteral)
  441. else
  442. begin
  443. InLiteral:=True;
  444. LastLiteral:=S[Wend];
  445. end;
  446. inc(wend);
  447. end;
  448. Result:=Copy(S,WStart,WEnd-WStart);
  449. Result:=StringReplace(Result,'"','',[rfReplaceAll]);
  450. Result:=StringReplace(Result,'''','',[rfReplaceAll]);
  451. While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
  452. inc(Wend);
  453. Delete(S,1,WEnd-1);
  454. end;
  455. Var
  456. W : String;
  457. begin
  458. While Length(S)>0 do
  459. begin
  460. W:=GetNextWord;
  461. If (W<>'') then
  462. List.Add(W);
  463. end;
  464. end;
  465. Function MakeCommand(Var AppName,CommandLine : String;
  466. StartupOptions : TStartUpOptions;
  467. ProcessOptions : TProcessOptions;
  468. StartupInfo : TStartupInfo) : PPchar;
  469. Const
  470. SNoCommandLine = 'Cannot execute empty command-line';
  471. Var
  472. S : TStringList;
  473. G : String;
  474. begin
  475. if (AppName='') then
  476. begin
  477. If (CommandLine='') then
  478. Raise Exception.Create(SNoCommandline)
  479. end
  480. else
  481. begin
  482. If (CommandLine='') then
  483. CommandLine:=AppName;
  484. end;
  485. S:=TStringList.Create;
  486. try
  487. CommandToList(CommandLine,S);
  488. if poNewConsole in ProcessOptions then
  489. begin
  490. S.Insert(0,'-e');
  491. If (AppName<>'') then
  492. begin
  493. S.Insert(0,AppName);
  494. S.Insert(0,'-title');
  495. end;
  496. if suoUseCountChars in StartupOptions then
  497. With StartupInfo do
  498. begin
  499. S.Insert(0,Format('%dx%d',[dwXCountChars,dwYCountChars]));
  500. S.Insert(0,'-geometry');
  501. end;
  502. S.Insert(0,'xterm');
  503. end;
  504. if (AppName<>'') then
  505. begin
  506. S.Add(TitleOption);
  507. S.Add(AppName);
  508. end;
  509. With StartupInfo do
  510. begin
  511. G:='';
  512. if (suoUseSize in StartupOptions) then
  513. g:=format('%dx%d',[dwXSize,dwYsize]);
  514. if (suoUsePosition in StartupOptions) then
  515. g:=g+Format('+%d+%d',[dwX,dwY]);
  516. if G<>'' then
  517. begin
  518. S.Add(GeometryOption);
  519. S.Add(g);
  520. end;
  521. end;
  522. Result:=StringsToPcharList(S);
  523. AppName:=S[0];
  524. Finally
  525. S.free;
  526. end;
  527. end;
  528. Function CreateProcess (PName,PCommandLine,PDir : String;
  529. FEnv : PPChar;
  530. StartupOptions : TStartupOptions;
  531. ProcessOptions : TProcessOptions;
  532. const FStartupInfo : TStartupInfo;
  533. Var ProcessInfo : TProcessInformation) : boolean;
  534. Var
  535. PID : Longint;
  536. Argv : PPChar;
  537. fd : Integer;
  538. begin
  539. Result:=True;
  540. Argv:=MakeCommand(Pname,PCommandLine,StartupOptions,ProcessOptions,FStartupInfo);
  541. if (pos('/',PName)<>1) then
  542. PName:=FileSearch(Pname,{$ifdef ver1_0}GetEnv{$else}fpgetenv{$endif}('PATH'));
  543. Pid:={$ifdef ver1_0}fork;{$else}fpfork;{$endif}
  544. if Pid=0 then
  545. begin
  546. { We're in the child }
  547. if (PDir<>'') then
  548. ChDir(PDir);
  549. if PoUsePipes in ProcessOptions then
  550. begin
  551. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(FStartupInfo.hStdInput,0);
  552. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(FStartupInfo.hStdOutput,1);
  553. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(FStartupInfo.hStdError,2);
  554. end
  555. else if poNoConsole in ProcessOptions then
  556. begin
  557. fd:=FileOpen('/dev/null',fmOpenReadWrite);
  558. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(fd,0);
  559. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(fd,1);
  560. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(fd,2);
  561. end;
  562. if (poRunSuspended in ProcessOptions) then
  563. sigraise(SIGSTOP);
  564. if FEnv<>Nil then
  565. {$ifdef ver1_0}execve{$else}fpexecve{$endif}(PChar(PName),Argv,Fenv)
  566. else
  567. {$ifdef ver1_0}execv{$else}fpexecv{$endif}(Pchar(PName),argv);
  568. Halt(127);
  569. end
  570. else
  571. begin
  572. FreePcharList(Argv);
  573. // Copy process information.
  574. ProcessInfo.hProcess:=PID;
  575. ProcessInfo.hThread:=PID;
  576. ProcessInfo.dwProcessId:=PID;
  577. ProcessInfo.dwThreadId:=PID;
  578. end;
  579. end;
  580. {$endif}
  581. {$ifdef unix}
  582. Function GetLastError : Integer;
  583. begin
  584. Result:=-1;
  585. end;
  586. {$endif}
  587. Procedure TProcess.Execute;
  588. Var
  589. {$ifndef unix}
  590. PName,PDir,PCommandLine : PChar;
  591. {$endif}
  592. FEnv : PPChar;
  593. FCreationFlags : Cardinal;
  594. begin
  595. If poUsePipes in FProcessOptions then
  596. CreateStreams;
  597. FCreationFlags:=GetCreationFlags;
  598. FStartupInfo.dwFlags:=GetStartupFlags;
  599. {$ifndef unix}
  600. PName:=Nil;
  601. PCommandLine:=Nil;
  602. PDir:=Nil;
  603. If FApplicationName<>'' then
  604. PName:=Pchar(FApplicationName);
  605. If FCommandLine<>'' then
  606. PCommandLine:=Pchar(FCommandLine);
  607. If FCurrentDirectory<>'' then
  608. PDir:=Pchar(FCurrentDirectory);
  609. {$endif}
  610. if FEnvironment.Count<>0 then
  611. FEnv:=StringsToPcharList(FEnvironment)
  612. else
  613. FEnv:=Nil;
  614. FInheritHandles:=True;
  615. {$ifdef unix}
  616. if Not CreateProcess (FApplicationName,FCommandLine,FCurrentDirectory,FEnv,
  617. FStartupOptions,FProcessOptions,FStartupInfo,
  618. fProcessInformation) then
  619. {$else}
  620. If Not CreateProcess (PName,PCommandLine,FProcessAttributes,FThreadAttributes,
  621. FInheritHandles,FCreationFlags,FEnv,PDir,FStartupInfo,
  622. fProcessInformation) then
  623. {$endif}
  624. Raise Exception.CreateFmt('Failed to execute %s : %d',[FCommandLine,GetLastError]);
  625. if POUsePipes in FProcessOptions then
  626. begin
  627. FileClose(FStartupInfo.hStdInput);
  628. FileClose(FStartupInfo.hStdOutput);
  629. if Not (poStdErrToOutPut in FProcessOptions) then
  630. FileClose(FStartupInfo.hStdError);
  631. end;
  632. {$ifdef unix}
  633. Fhandle:=fprocessinformation.hProcess;
  634. {$endif}
  635. FRunning:=True;
  636. If FEnv<>Nil then
  637. FreePCharList(FEnv);
  638. if not (csDesigning in ComponentState) and // This would hang the IDE !
  639. (poWaitOnExit in FProcessOptions) and
  640. not (poRunSuspended in FProcessOptions) then
  641. WaitOnExit;
  642. end;
  643. Function TProcess.WaitOnExit : Dword;
  644. begin
  645. {$ifdef unix}
  646. Result:=Dword({$ifdef ver1_0}WaitPid{$else}fpWaitPid{$endif}(Handle,@FExitCode,0));
  647. If Result=Handle then
  648. FExitCode:=WexitStatus(FExitCode);
  649. {$else}
  650. Result:=WaitForSingleObject (FprocessInformation.hProcess,Infinite);
  651. If Result<>Wait_Failed then
  652. GetExitStatus;
  653. {$endif}
  654. FRunning:=False;
  655. end;
  656. Function TProcess.Suspend : Longint;
  657. begin
  658. {$ifdef unix}
  659. If {$ifdef ver1_0}kill{$else}fpkill{$endif}(Handle,SIGSTOP)<>0 then
  660. Result:=-1
  661. else
  662. Result:=1;
  663. {$else}
  664. Result:=SuspendThread(ThreadHandle);
  665. {$endif}
  666. end;
  667. Function TProcess.Resume : LongInt;
  668. begin
  669. {$ifdef unix}
  670. If {$ifdef ver1_0}kill{$else}fpkill{$endif}(Handle,SIGCONT)<>0 then
  671. Result:=-1
  672. else
  673. Result:=0;
  674. {$else}
  675. Result:=ResumeThread(ThreadHandle);
  676. {$endif}
  677. end;
  678. Function TProcess.Terminate(AExitCode : Integer) : Boolean;
  679. begin
  680. Result:=False;
  681. {$ifdef unix}
  682. Result:={$ifdef ver1_0}kill{$else}fpkill{$endif}(Handle,SIGTERM)=0;
  683. If Result then
  684. begin
  685. If Running then
  686. Result:={$ifdef ver1_0}kill{$else}fpkill{$endif}(Handle,SIGKILL)=0;
  687. end;
  688. GetExitStatus;
  689. {$else}
  690. If ExitStatus=Still_active then
  691. Result:=TerminateProcess(Handle,AexitCode);
  692. {$endif}
  693. end;
  694. Procedure TProcess.SetFillAttribute (Value : Cardinal);
  695. begin
  696. FStartupInfo.dwFlags:=FStartupInfo.dwFlags or Startf_UseFillAttribute;
  697. FStartupInfo.dwFillAttribute:=Value;
  698. end;
  699. Procedure TProcess.SetShowWindow (Value : TShowWindowOptions);
  700. {$ifndef unix}
  701. Const
  702. SWC : Array [TShowWindowOptions] of Cardinal =
  703. (0,SW_HIDE,SW_Maximize,SW_Minimize,SW_Restore,SW_Show,
  704. SW_ShowDefault,SW_ShowMaximized,SW_ShowMinimized,
  705. SW_showMinNOActive,SW_ShowNA,SW_ShowNoActivate,SW_ShowNormal);
  706. {$endif}
  707. begin
  708. FShowWindow:=Value;
  709. if Value<>swoNone then
  710. FStartupInfo.dwFlags:=FStartupInfo.dwFlags or Startf_UseShowWindow
  711. else
  712. FStartupInfo.dwFlags:=FStartupInfo.dwFlags and not Startf_UseShowWindow;
  713. {$ifndef unix}
  714. FStartupInfo.wShowWindow:=SWC[Value];
  715. {$endif}
  716. end;
  717. Procedure TProcess.SetWindowColumns (Value : Cardinal);
  718. begin
  719. if Value<>0 then
  720. Include(FStartUpOptions,suoUseCountChars);
  721. FStartupInfo.dwXCountChars:=Value;
  722. end;
  723. Procedure TProcess.SetWindowHeight (Value : Cardinal);
  724. begin
  725. if Value<>0 then
  726. include(FStartUpOptions,suoUsePosition);
  727. FStartupInfo.dwYsize:=Value;
  728. end;
  729. Procedure TProcess.SetWindowLeft (Value : Cardinal);
  730. begin
  731. if Value<>0 then
  732. Include(FStartUpOptions,suoUseSize);
  733. FStartupInfo.dwx:=Value;
  734. end;
  735. Procedure TProcess.SetWindowTop (Value : Cardinal);
  736. begin
  737. if Value<>0 then
  738. Include(FStartUpOptions,suoUsePosition);
  739. FStartupInfo.dwy:=Value;
  740. end;
  741. Procedure TProcess.SetWindowWidth (Value : Cardinal);
  742. begin
  743. If (Value<>0) then
  744. Include(FStartUpOptions,suoUseSize);
  745. FStartupInfo.dwxsize:=Value;
  746. end;
  747. Function TProcess.GetWindowRect : TRect;
  748. begin
  749. With Result do
  750. With FStartupInfo do
  751. begin
  752. Left:=dwx;
  753. Right:=dwx+dwxSize;
  754. Top:=dwy;
  755. Bottom:=dwy+dwysize;
  756. end;
  757. end;
  758. Procedure TProcess.SetWindowRect (Value : Trect);
  759. begin
  760. Include(FStartupOptions,suouseSize);
  761. Include(FStartupOptions,suoUsePosition);
  762. With Value do
  763. With FStartupInfo do
  764. begin
  765. dwx:=Left;
  766. dwxSize:=Right-Left;
  767. dwy:=Top;
  768. dwySize:=Bottom-top;
  769. end;
  770. end;
  771. Procedure TProcess.SetWindowRows (Value : Cardinal);
  772. begin
  773. FStartupInfo.dwFlags:=FStartupInfo.dwFlags or Startf_UseCountChars;
  774. FStartupInfo.dwYCountChars:=Value;
  775. end;
  776. procedure TProcess.SetApplicationname(const Value: String);
  777. begin
  778. FApplicationname := Value;
  779. If (csdesigning in ComponentState) and
  780. (FCommandLine='') then
  781. FCommandLine:=Value;
  782. end;
  783. procedure TProcess.SetProcessOptions(const Value: TProcessOptions);
  784. begin
  785. FProcessOptions := Value;
  786. If poNewConsole in FPRocessOptions then
  787. Exclude(FProcessoptions,poNoConsole);
  788. if poRunSuspended in FProcessOptions then
  789. Exclude(FPRocessoptions,poWaitOnExit);
  790. end;
  791. procedure TProcess.SetActive(const Value: Boolean);
  792. begin
  793. if (Value<>GetRunning) then
  794. If Value then
  795. Execute
  796. else
  797. Terminate(0);
  798. end;
  799. procedure TProcess.SetEnvironment(const Value: TStrings);
  800. begin
  801. FEnvironment.Assign(Value);
  802. end;
  803. end.
  804. {
  805. $Log$
  806. Revision 1.18 2003-10-30 20:34:47 florian
  807. * fixed inherited destroy; call of tprocess
  808. Revision 1.17 2003/09/20 12:38:29 marco
  809. * FCL now compiles for FreeBSD with new 1.1. Now Linux.
  810. Revision 1.16 2003/08/12 13:49:42 michael
  811. + Freed streams were not closed correctly
  812. Revision 1.15 2003/05/08 20:04:16 armin
  813. * Dont close FStartupInfo.hStdError if options include poStdErrToOutPut
  814. Revision 1.14 2003/04/27 21:21:42 sg
  815. * Added typecast to prevent range check error in TProcess.WaitOnExit
  816. Revision 1.13 2002/09/07 15:15:25 peter
  817. * old logs removed and tabs fixed
  818. }