process.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969
  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. {$ifdef unix}
  388. Type
  389. TPCharArray = Array[Word] of pchar;
  390. PPCharArray = ^TPcharArray;
  391. Function StringsToPCharList(List : TStrings) : PPChar;
  392. Var
  393. I : Integer;
  394. S : String;
  395. begin
  396. I:=(List.Count)+1;
  397. GetMem(Result,I*sizeOf(PChar));
  398. PPCharArray(Result)^[List.Count]:=Nil;
  399. For I:=0 to List.Count-1 do
  400. begin
  401. S:=List[i];
  402. Result[i]:=StrNew(PChar(S));
  403. end;
  404. end;
  405. Procedure FreePCharList(List : PPChar);
  406. Var
  407. I : integer;
  408. begin
  409. I:=0;
  410. While List[i]<>Nil do
  411. begin
  412. StrDispose(List[i]);
  413. Inc(I);
  414. end;
  415. FreeMem(List);
  416. end;
  417. {$else}
  418. Function StringsToPChars(List : TStrings): pointer;
  419. var
  420. EnvBlock: string;
  421. I: Integer;
  422. begin
  423. EnvBlock := '';
  424. For I:=0 to List.Count-1 do
  425. EnvBlock := EnvBlock + List[i] + #0;
  426. EnvBlock := EnvBlock + #0;
  427. GetMem(Result, Length(EnvBlock));
  428. CopyMemory(Result, @EnvBlock[1], Length(EnvBlock));
  429. end;
  430. {$endif}
  431. {$ifdef unix}
  432. Procedure CommandToList(S : String; List : TStrings);
  433. Function GetNextWord : String;
  434. Const
  435. WhiteSpace = [' ',#8,#10];
  436. Literals = ['"',''''];
  437. Var
  438. Wstart,wend : Integer;
  439. InLiteral : Boolean;
  440. LastLiteral : char;
  441. begin
  442. WStart:=1;
  443. While (WStart<=Length(S)) and (S[WStart] in WhiteSpace) do
  444. Inc(WStart);
  445. WEnd:=WStart;
  446. InLiteral:=False;
  447. LastLiteral:=#0;
  448. While (Wend<=Length(S)) and (Not (S[Wend] in WhiteSpace) or InLiteral) do
  449. begin
  450. if S[Wend] in Literals then
  451. If InLiteral then
  452. InLiteral:=Not (S[Wend]=LastLiteral)
  453. else
  454. begin
  455. InLiteral:=True;
  456. LastLiteral:=S[Wend];
  457. end;
  458. inc(wend);
  459. end;
  460. Result:=Copy(S,WStart,WEnd-WStart);
  461. Result:=StringReplace(Result,'"','',[rfReplaceAll]);
  462. Result:=StringReplace(Result,'''','',[rfReplaceAll]);
  463. While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
  464. inc(Wend);
  465. Delete(S,1,WEnd-1);
  466. end;
  467. Var
  468. W : String;
  469. begin
  470. While Length(S)>0 do
  471. begin
  472. W:=GetNextWord;
  473. If (W<>'') then
  474. List.Add(W);
  475. end;
  476. end;
  477. Function MakeCommand(Var AppName,CommandLine : String;
  478. StartupOptions : TStartUpOptions;
  479. ProcessOptions : TProcessOptions;
  480. StartupInfo : TStartupInfo) : PPchar;
  481. Const
  482. SNoCommandLine = 'Cannot execute empty command-line';
  483. Var
  484. S : TStringList;
  485. G : String;
  486. begin
  487. if (AppName='') then
  488. begin
  489. If (CommandLine='') then
  490. Raise Exception.Create(SNoCommandline)
  491. end
  492. else
  493. begin
  494. If (CommandLine='') then
  495. CommandLine:=AppName;
  496. end;
  497. S:=TStringList.Create;
  498. try
  499. CommandToList(CommandLine,S);
  500. if poNewConsole in ProcessOptions then
  501. begin
  502. S.Insert(0,'-e');
  503. If (AppName<>'') then
  504. begin
  505. S.Insert(0,AppName);
  506. S.Insert(0,'-title');
  507. end;
  508. if suoUseCountChars in StartupOptions then
  509. With StartupInfo do
  510. begin
  511. S.Insert(0,Format('%dx%d',[dwXCountChars,dwYCountChars]));
  512. S.Insert(0,'-geometry');
  513. end;
  514. S.Insert(0,'xterm');
  515. end;
  516. if (AppName<>'') then
  517. begin
  518. S.Add(TitleOption);
  519. S.Add(AppName);
  520. end;
  521. With StartupInfo do
  522. begin
  523. G:='';
  524. if (suoUseSize in StartupOptions) then
  525. g:=format('%dx%d',[dwXSize,dwYsize]);
  526. if (suoUsePosition in StartupOptions) then
  527. g:=g+Format('+%d+%d',[dwX,dwY]);
  528. if G<>'' then
  529. begin
  530. S.Add(GeometryOption);
  531. S.Add(g);
  532. end;
  533. end;
  534. Result:=StringsToPcharList(S);
  535. AppName:=S[0];
  536. Finally
  537. S.free;
  538. end;
  539. end;
  540. Function CreateProcess (PName,PCommandLine,PDir : String;
  541. FEnv : PPChar;
  542. StartupOptions : TStartupOptions;
  543. ProcessOptions : TProcessOptions;
  544. const FStartupInfo : TStartupInfo;
  545. Var ProcessInfo : TProcessInformation) : boolean;
  546. Var
  547. PID : Longint;
  548. Argv : PPChar;
  549. fd : Integer;
  550. begin
  551. Result:=True;
  552. Argv:=MakeCommand(Pname,PCommandLine,StartupOptions,ProcessOptions,FStartupInfo);
  553. if (pos('/',PName)<>1) then
  554. PName:=FileSearch(Pname,{$ifdef ver1_0}GetEnv{$else}fpgetenv{$endif}('PATH'));
  555. Pid:={$ifdef ver1_0}fork;{$else}fpfork;{$endif}
  556. if Pid=0 then
  557. begin
  558. { We're in the child }
  559. if (PDir<>'') then
  560. ChDir(PDir);
  561. if PoUsePipes in ProcessOptions then
  562. begin
  563. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(FStartupInfo.hStdInput,0);
  564. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(FStartupInfo.hStdOutput,1);
  565. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(FStartupInfo.hStdError,2);
  566. end
  567. else if poNoConsole in ProcessOptions then
  568. begin
  569. fd:=FileOpen('/dev/null',fmOpenReadWrite);
  570. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(fd,0);
  571. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(fd,1);
  572. {$ifdef ver1_0}dup2{$else}fpdup2{$endif}(fd,2);
  573. end;
  574. if (poRunSuspended in ProcessOptions) then
  575. sigraise(SIGSTOP);
  576. if FEnv<>Nil then
  577. {$ifdef ver1_0}execve{$else}fpexecve{$endif}(PChar(PName),Argv,Fenv)
  578. else
  579. {$ifdef ver1_0}execv{$else}fpexecv{$endif}(Pchar(PName),argv);
  580. Halt(127);
  581. end
  582. else
  583. begin
  584. FreePcharList(Argv);
  585. // Copy process information.
  586. ProcessInfo.hProcess:=PID;
  587. ProcessInfo.hThread:=PID;
  588. ProcessInfo.dwProcessId:=PID;
  589. ProcessInfo.dwThreadId:=PID;
  590. end;
  591. end;
  592. {$endif}
  593. {$ifdef unix}
  594. Function GetLastError : Integer;
  595. begin
  596. Result:=-1;
  597. end;
  598. {$endif}
  599. Procedure TProcess.Execute;
  600. Var
  601. {$ifndef unix}
  602. PName,PDir,PCommandLine : PChar;
  603. FEnv: pointer;
  604. {$else}
  605. FEnv : PPChar;
  606. {$endif}
  607. FCreationFlags : Cardinal;
  608. begin
  609. If poUsePipes in FProcessOptions then
  610. CreateStreams;
  611. FCreationFlags:=GetCreationFlags;
  612. FStartupInfo.dwFlags:=GetStartupFlags;
  613. {$ifndef unix}
  614. PName:=Nil;
  615. PCommandLine:=Nil;
  616. PDir:=Nil;
  617. If FApplicationName<>'' then
  618. PName:=Pchar(FApplicationName);
  619. If FCommandLine<>'' then
  620. PCommandLine:=Pchar(FCommandLine);
  621. If FCurrentDirectory<>'' then
  622. PDir:=Pchar(FCurrentDirectory);
  623. {$endif}
  624. if FEnvironment.Count<>0 then
  625. {$ifdef unix}
  626. FEnv:=StringsToPcharList(FEnvironment)
  627. {$else}
  628. FEnv:=StringsToPChars(FEnvironment)
  629. {$endif}
  630. else
  631. FEnv:=Nil;
  632. FInheritHandles:=True;
  633. {$ifdef unix}
  634. if Not CreateProcess (FApplicationName,FCommandLine,FCurrentDirectory,FEnv,
  635. FStartupOptions,FProcessOptions,FStartupInfo,
  636. fProcessInformation) then
  637. {$else}
  638. If Not CreateProcess (PName,PCommandLine,FProcessAttributes,FThreadAttributes,
  639. FInheritHandles,FCreationFlags,FEnv,PDir,FStartupInfo,
  640. fProcessInformation) then
  641. {$endif}
  642. Raise Exception.CreateFmt('Failed to execute %s : %d',[FCommandLine,GetLastError]);
  643. if POUsePipes in FProcessOptions then
  644. begin
  645. FileClose(FStartupInfo.hStdInput);
  646. FileClose(FStartupInfo.hStdOutput);
  647. if Not (poStdErrToOutPut in FProcessOptions) then
  648. FileClose(FStartupInfo.hStdError);
  649. end;
  650. {$ifdef unix}
  651. Fhandle:=fprocessinformation.hProcess;
  652. {$endif}
  653. FRunning:=True;
  654. If FEnv<>Nil then
  655. {$ifdef unix}
  656. FreePCharList(FEnv);
  657. {$else}
  658. FreeMem(FEnv);
  659. {$endif}
  660. if not (csDesigning in ComponentState) and // This would hang the IDE !
  661. (poWaitOnExit in FProcessOptions) and
  662. not (poRunSuspended in FProcessOptions) then
  663. WaitOnExit;
  664. end;
  665. Function TProcess.WaitOnExit : Dword;
  666. begin
  667. {$ifdef unix}
  668. Result:=Dword({$ifdef ver1_0}WaitPid{$else}fpWaitPid{$endif}(Handle,@FExitCode,0));
  669. If Result=Handle then
  670. FExitCode:=WexitStatus(FExitCode);
  671. {$else}
  672. Result:=WaitForSingleObject (FprocessInformation.hProcess,Infinite);
  673. If Result<>Wait_Failed then
  674. GetExitStatus;
  675. {$endif}
  676. FRunning:=False;
  677. end;
  678. Function TProcess.Suspend : Longint;
  679. begin
  680. {$ifdef unix}
  681. If {$ifdef ver1_0}kill{$else}fpkill{$endif}(Handle,SIGSTOP)<>0 then
  682. Result:=-1
  683. else
  684. Result:=1;
  685. {$else}
  686. Result:=SuspendThread(ThreadHandle);
  687. {$endif}
  688. end;
  689. Function TProcess.Resume : LongInt;
  690. begin
  691. {$ifdef unix}
  692. If {$ifdef ver1_0}kill{$else}fpkill{$endif}(Handle,SIGCONT)<>0 then
  693. Result:=-1
  694. else
  695. Result:=0;
  696. {$else}
  697. Result:=ResumeThread(ThreadHandle);
  698. {$endif}
  699. end;
  700. Function TProcess.Terminate(AExitCode : Integer) : Boolean;
  701. begin
  702. Result:=False;
  703. {$ifdef unix}
  704. Result:={$ifdef ver1_0}kill{$else}fpkill{$endif}(Handle,SIGTERM)=0;
  705. If Result then
  706. begin
  707. If Running then
  708. Result:={$ifdef ver1_0}kill{$else}fpkill{$endif}(Handle,SIGKILL)=0;
  709. end;
  710. GetExitStatus;
  711. {$else}
  712. If ExitStatus=Still_active then
  713. Result:=TerminateProcess(Handle,AexitCode);
  714. {$endif}
  715. end;
  716. Procedure TProcess.SetFillAttribute (Value : Cardinal);
  717. begin
  718. FStartupInfo.dwFlags:=FStartupInfo.dwFlags or Startf_UseFillAttribute;
  719. FStartupInfo.dwFillAttribute:=Value;
  720. end;
  721. Procedure TProcess.SetShowWindow (Value : TShowWindowOptions);
  722. {$ifndef unix}
  723. Const
  724. SWC : Array [TShowWindowOptions] of Cardinal =
  725. (0,SW_HIDE,SW_Maximize,SW_Minimize,SW_Restore,SW_Show,
  726. SW_ShowDefault,SW_ShowMaximized,SW_ShowMinimized,
  727. SW_showMinNOActive,SW_ShowNA,SW_ShowNoActivate,SW_ShowNormal);
  728. {$endif}
  729. begin
  730. FShowWindow:=Value;
  731. if Value<>swoNone then
  732. FStartupInfo.dwFlags:=FStartupInfo.dwFlags or Startf_UseShowWindow
  733. else
  734. FStartupInfo.dwFlags:=FStartupInfo.dwFlags and not Startf_UseShowWindow;
  735. {$ifndef unix}
  736. FStartupInfo.wShowWindow:=SWC[Value];
  737. {$endif}
  738. end;
  739. Procedure TProcess.SetWindowColumns (Value : Cardinal);
  740. begin
  741. if Value<>0 then
  742. Include(FStartUpOptions,suoUseCountChars);
  743. FStartupInfo.dwXCountChars:=Value;
  744. end;
  745. Procedure TProcess.SetWindowHeight (Value : Cardinal);
  746. begin
  747. if Value<>0 then
  748. include(FStartUpOptions,suoUsePosition);
  749. FStartupInfo.dwYsize:=Value;
  750. end;
  751. Procedure TProcess.SetWindowLeft (Value : Cardinal);
  752. begin
  753. if Value<>0 then
  754. Include(FStartUpOptions,suoUseSize);
  755. FStartupInfo.dwx:=Value;
  756. end;
  757. Procedure TProcess.SetWindowTop (Value : Cardinal);
  758. begin
  759. if Value<>0 then
  760. Include(FStartUpOptions,suoUsePosition);
  761. FStartupInfo.dwy:=Value;
  762. end;
  763. Procedure TProcess.SetWindowWidth (Value : Cardinal);
  764. begin
  765. If (Value<>0) then
  766. Include(FStartUpOptions,suoUseSize);
  767. FStartupInfo.dwxsize:=Value;
  768. end;
  769. Function TProcess.GetWindowRect : TRect;
  770. begin
  771. With Result do
  772. With FStartupInfo do
  773. begin
  774. Left:=dwx;
  775. Right:=dwx+dwxSize;
  776. Top:=dwy;
  777. Bottom:=dwy+dwysize;
  778. end;
  779. end;
  780. Procedure TProcess.SetWindowRect (Value : Trect);
  781. begin
  782. Include(FStartupOptions,suouseSize);
  783. Include(FStartupOptions,suoUsePosition);
  784. With Value do
  785. With FStartupInfo do
  786. begin
  787. dwx:=Left;
  788. dwxSize:=Right-Left;
  789. dwy:=Top;
  790. dwySize:=Bottom-top;
  791. end;
  792. end;
  793. Procedure TProcess.SetWindowRows (Value : Cardinal);
  794. begin
  795. FStartupInfo.dwFlags:=FStartupInfo.dwFlags or Startf_UseCountChars;
  796. FStartupInfo.dwYCountChars:=Value;
  797. end;
  798. procedure TProcess.SetApplicationname(const Value: String);
  799. begin
  800. FApplicationname := Value;
  801. If (csdesigning in ComponentState) and
  802. (FCommandLine='') then
  803. FCommandLine:=Value;
  804. end;
  805. procedure TProcess.SetProcessOptions(const Value: TProcessOptions);
  806. begin
  807. FProcessOptions := Value;
  808. If poNewConsole in FPRocessOptions then
  809. Exclude(FProcessoptions,poNoConsole);
  810. if poRunSuspended in FProcessOptions then
  811. Exclude(FPRocessoptions,poWaitOnExit);
  812. end;
  813. procedure TProcess.SetActive(const Value: Boolean);
  814. begin
  815. if (Value<>GetRunning) then
  816. If Value then
  817. Execute
  818. else
  819. Terminate(0);
  820. end;
  821. procedure TProcess.SetEnvironment(const Value: TStrings);
  822. begin
  823. FEnvironment.Assign(Value);
  824. end;
  825. end.
  826. {
  827. $Log$
  828. Revision 1.19 2004-02-03 08:12:22 michael
  829. + Patch from Vincent Snijders to fix passing environment vars in win32
  830. Revision 1.18 2003/10/30 20:34:47 florian
  831. * fixed inherited destroy; call of tprocess
  832. Revision 1.17 2003/09/20 12:38:29 marco
  833. * FCL now compiles for FreeBSD with new 1.1. Now Linux.
  834. Revision 1.16 2003/08/12 13:49:42 michael
  835. + Freed streams were not closed correctly
  836. Revision 1.15 2003/05/08 20:04:16 armin
  837. * Dont close FStartupInfo.hStdError if options include poStdErrToOutPut
  838. Revision 1.14 2003/04/27 21:21:42 sg
  839. * Added typecast to prevent range check error in TProcess.WaitOnExit
  840. Revision 1.13 2002/09/07 15:15:25 peter
  841. * old logs removed and tabs fixed
  842. }