sysutils.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Sysutils unit for OS/2
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit sysutils;
  13. interface
  14. {$MODE objfpc}
  15. {$MODESWITCH OUT}
  16. { force ansistrings }
  17. {$H+}
  18. {$DEFINE HAS_SLEEP}
  19. { Include platform independent interface part }
  20. {$i sysutilh.inc}
  21. implementation
  22. uses
  23. sysconst, DosCalls;
  24. type
  25. (* Necessary here due to a different definition of TDateTime in DosCalls. *)
  26. TDateTime = System.TDateTime;
  27. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  28. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  29. {$DEFINE FPC_FEXPAND_GETENV_PCHAR}
  30. {$DEFINE HAS_GETTICKCOUNT}
  31. {$DEFINE HAS_GETTICKCOUNT64}
  32. { Include platform independent implementation part }
  33. {$i sysutils.inc}
  34. {****************************************************************************
  35. File Functions
  36. ****************************************************************************}
  37. const
  38. ofRead = $0000; {Open for reading}
  39. ofWrite = $0001; {Open for writing}
  40. ofReadWrite = $0002; {Open for reading/writing}
  41. doDenyRW = $0010; {DenyAll (no sharing)}
  42. faCreateNew = $00010000; {Create if file does not exist}
  43. faOpenReplace = $00040000; {Truncate if file exists}
  44. faCreate = $00050000; {Create if file does not exist, truncate otherwise}
  45. FindResvdMask = $00003737; {Allowed bits in attribute
  46. specification for DosFindFirst call.}
  47. function FileOpen (const FileName: string; Mode: integer): THandle;
  48. Var
  49. Handle: THandle;
  50. Rc, Action: cardinal;
  51. begin
  52. (* DenyNone if sharing not specified. *)
  53. if (Mode and 112 = 0) or (Mode and 112 > 64) then
  54. Mode := Mode or 64;
  55. Rc:=Sys_DosOpenL(PChar (FileName), Handle, Action, 0, 0, 1, Mode, nil);
  56. If Rc=0 then
  57. FileOpen:=Handle
  58. else
  59. FileOpen:=feInvalidHandle; //FileOpen:=-RC;
  60. //should return feInvalidHandle(=-1) if fail, other negative returned value are no more errors
  61. end;
  62. function FileCreate (const FileName: string): THandle;
  63. begin
  64. FileCreate := FileCreate (FileName, doDenyRW, 777); (* Sharing to DenyAll *)
  65. end;
  66. function FileCreate (const FileName: string; Rights: integer): THandle;
  67. begin
  68. FileCreate := FileCreate (FileName, doDenyRW, Rights);
  69. (* Sharing to DenyAll *)
  70. end;
  71. function FileCreate (const FileName: string; ShareMode: integer;
  72. Rights: integer): THandle;
  73. var
  74. Handle: THandle;
  75. RC, Action: cardinal;
  76. begin
  77. ShareMode := ShareMode and 112;
  78. (* Sharing to DenyAll as default in case of values not allowed by OS/2. *)
  79. if (ShareMode = 0) or (ShareMode > 64) then
  80. ShareMode := doDenyRW;
  81. RC := Sys_DosOpenL (PChar (FileName), Handle, Action, 0, 0, $12,
  82. faCreate or ofReadWrite or ShareMode, nil);
  83. if RC = 0 then
  84. FileCreate := Handle
  85. else
  86. FileCreate := feInvalidHandle;
  87. End;
  88. function FileRead (Handle: THandle; Out Buffer; Count: longint): longint;
  89. Var
  90. T: cardinal;
  91. begin
  92. DosRead(Handle, Buffer, Count, T);
  93. FileRead := longint (T);
  94. end;
  95. function FileWrite (Handle: THandle; const Buffer; Count: longint): longint;
  96. Var
  97. T: cardinal;
  98. begin
  99. DosWrite (Handle, Buffer, Count, T);
  100. FileWrite := longint (T);
  101. end;
  102. function FileSeek (Handle: THandle; FOffset, Origin: longint): longint;
  103. var
  104. NPos: int64;
  105. begin
  106. if (Sys_DosSetFilePtrL (Handle, FOffset, Origin, NPos) = 0)
  107. and (NPos < high (longint)) then
  108. FileSeek:= longint (NPos)
  109. else
  110. FileSeek:=-1;
  111. end;
  112. function FileSeek (Handle: THandle; FOffset: Int64; Origin: Longint): Int64;
  113. var
  114. NPos: int64;
  115. begin
  116. if Sys_DosSetFilePtrL (Handle, FOffset, Origin, NPos) = 0 then
  117. FileSeek:= NPos
  118. else
  119. FileSeek:=-1;
  120. end;
  121. procedure FileClose (Handle: THandle);
  122. begin
  123. DosClose(Handle);
  124. end;
  125. function FileTruncate (Handle: THandle; Size: Int64): boolean;
  126. begin
  127. FileTruncate:=Sys_DosSetFileSizeL(Handle, Size)=0;
  128. FileSeek(Handle, 0, 2);
  129. end;
  130. function FileAge (const FileName: string): longint;
  131. var Handle: longint;
  132. begin
  133. Handle := FileOpen (FileName, 0);
  134. if Handle <> -1 then
  135. begin
  136. Result := FileGetDate (Handle);
  137. FileClose (Handle);
  138. end
  139. else
  140. Result := -1;
  141. end;
  142. function FileExists (const FileName: string): boolean;
  143. var
  144. L: longint;
  145. begin
  146. if FileName = '' then
  147. Result := false
  148. else
  149. begin
  150. L := FileGetAttr (FileName);
  151. Result := (L >= 0) and (L and (faDirectory or faVolumeID) = 0);
  152. (* Neither VolumeIDs nor directories are files. *)
  153. end;
  154. end;
  155. type TRec = record
  156. T, D: word;
  157. end;
  158. PSearchRec = ^TSearchRec;
  159. function FindFirst (const Path: string; Attr: longint; out Rslt: TSearchRec): longint;
  160. var SR: PSearchRec;
  161. FStat: PFileFindBuf3L;
  162. Count: cardinal;
  163. Err: cardinal;
  164. I: cardinal;
  165. begin
  166. New (FStat);
  167. Rslt.FindHandle := THandle ($FFFFFFFF);
  168. Count := 1;
  169. if FSApi64 then
  170. Err := DosFindFirst (PChar (Path), Rslt.FindHandle,
  171. Attr and FindResvdMask, FStat, SizeOf (FStat^), Count, ilStandardL)
  172. else
  173. Err := DosFindFirst (PChar (Path), Rslt.FindHandle,
  174. Attr and FindResvdMask, FStat, SizeOf (FStat^), Count, ilStandard);
  175. if (Err = 0) and (Count = 0) then
  176. Err := 18;
  177. FindFirst := -Err;
  178. if Err = 0 then
  179. begin
  180. Rslt.ExcludeAttr := 0;
  181. TRec (Rslt.Time).T := FStat^.TimeLastWrite;
  182. TRec (Rslt.Time).D := FStat^.DateLastWrite;
  183. if FSApi64 then
  184. begin
  185. Rslt.Size := FStat^.FileSize;
  186. Rslt.Name := FStat^.Name;
  187. Rslt.Attr := FStat^.AttrFile;
  188. end
  189. else
  190. begin
  191. Rslt.Size := PFileFindBuf3 (FStat)^.FileSize;
  192. Rslt.Name := PFileFindBuf3 (FStat)^.Name;
  193. Rslt.Attr := PFileFindBuf3 (FStat)^.AttrFile;
  194. end;
  195. end
  196. else
  197. FindClose(Rslt);
  198. Dispose (FStat);
  199. end;
  200. function FindNext (var Rslt: TSearchRec): longint;
  201. var
  202. SR: PSearchRec;
  203. FStat: PFileFindBuf3L;
  204. Count: cardinal;
  205. Err: cardinal;
  206. begin
  207. New (FStat);
  208. Count := 1;
  209. Err := DosFindNext (Rslt.FindHandle, FStat, SizeOf (FStat^), Count);
  210. if (Err = 0) and (Count = 0) then
  211. Err := 18;
  212. FindNext := -Err;
  213. if Err = 0 then
  214. begin
  215. Rslt.ExcludeAttr := 0;
  216. TRec (Rslt.Time).T := FStat^.TimeLastWrite;
  217. TRec (Rslt.Time).D := FStat^.DateLastWrite;
  218. if FSApi64 then
  219. begin
  220. Rslt.Size := FStat^.FileSize;
  221. Rslt.Name := FStat^.Name;
  222. Rslt.Attr := FStat^.AttrFile;
  223. end
  224. else
  225. begin
  226. Rslt.Size := PFileFindBuf3 (FStat)^.FileSize;
  227. Rslt.Name := PFileFindBuf3 (FStat)^.Name;
  228. Rslt.Attr := PFileFindBuf3 (FStat)^.AttrFile;
  229. end;
  230. end;
  231. Dispose (FStat);
  232. end;
  233. procedure FindClose (var F: TSearchrec);
  234. var
  235. SR: PSearchRec;
  236. begin
  237. DosFindClose (F.FindHandle);
  238. F.FindHandle := 0;
  239. end;
  240. function FileGetDate (Handle: THandle): longint;
  241. var
  242. FStat: TFileStatus3;
  243. Time: Longint;
  244. RC: cardinal;
  245. begin
  246. RC := DosQueryFileInfo(Handle, ilStandard, @FStat, SizeOf(FStat));
  247. if RC = 0 then
  248. begin
  249. Time := FStat.TimeLastWrite + longint (FStat.DateLastWrite) shl 16;
  250. if Time = 0 then
  251. Time := FStat.TimeCreation + longint (FStat.DateCreation) shl 16;
  252. end else
  253. Time:=0;
  254. FileGetDate:=Time;
  255. end;
  256. function FileSetDate (Handle: THandle; Age: longint): longint;
  257. var
  258. FStat: PFileStatus3;
  259. RC: cardinal;
  260. begin
  261. New (FStat);
  262. RC := DosQueryFileInfo (Handle, ilStandard, FStat, SizeOf (FStat^));
  263. if RC <> 0 then
  264. FileSetDate := -1
  265. else
  266. begin
  267. FStat^.DateLastAccess := Hi (Age);
  268. FStat^.DateLastWrite := Hi (Age);
  269. FStat^.TimeLastAccess := Lo (Age);
  270. FStat^.TimeLastWrite := Lo (Age);
  271. RC := DosSetFileInfo (Handle, ilStandard, FStat, SizeOf (FStat^));
  272. if RC <> 0 then
  273. FileSetDate := -1
  274. else
  275. FileSetDate := 0;
  276. end;
  277. Dispose (FStat);
  278. end;
  279. function FileGetAttr (const FileName: string): longint;
  280. var
  281. FS: PFileStatus3;
  282. begin
  283. New(FS);
  284. Result:=-DosQueryPathInfo(PChar (FileName), ilStandard, FS, SizeOf(FS^));
  285. If Result=0 Then Result:=FS^.attrFile;
  286. Dispose(FS);
  287. end;
  288. function FileSetAttr (const Filename: string; Attr: longint): longint;
  289. Var
  290. FS: PFileStatus3;
  291. Begin
  292. New(FS);
  293. FillChar(FS, SizeOf(FS^), 0);
  294. FS^.AttrFile:=Attr;
  295. Result:=-DosSetPathInfo(PChar (FileName), ilStandard, FS, SizeOf(FS^), 0);
  296. Dispose(FS);
  297. end;
  298. function DeleteFile (const FileName: string): boolean;
  299. Begin
  300. Result:=(DosDelete(PChar (FileName))=0);
  301. End;
  302. function RenameFile (const OldName, NewName: string): boolean;
  303. Begin
  304. Result:=(DosMove(PChar (OldName), PChar (NewName))=0);
  305. End;
  306. {****************************************************************************
  307. Disk Functions
  308. ****************************************************************************}
  309. function DiskFree (Drive: byte): int64;
  310. var FI: TFSinfo;
  311. RC: cardinal;
  312. begin
  313. {In OS/2, we use the filesystem information.}
  314. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  315. if RC = 0 then
  316. DiskFree := int64 (FI.Free_Clusters) *
  317. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  318. else
  319. DiskFree := -1;
  320. end;
  321. function DiskSize (Drive: byte): int64;
  322. var FI: TFSinfo;
  323. RC: cardinal;
  324. begin
  325. {In OS/2, we use the filesystem information.}
  326. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  327. if RC = 0 then
  328. DiskSize := int64 (FI.Total_Clusters) *
  329. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  330. else
  331. DiskSize := -1;
  332. end;
  333. function GetCurrentDir: string;
  334. begin
  335. GetDir (0, Result);
  336. end;
  337. function SetCurrentDir (const NewDir: string): boolean;
  338. var
  339. OrigInOutRes: word;
  340. begin
  341. OrigInOutRes := InOutRes;
  342. InOutRes := 0;
  343. {$I-}
  344. ChDir (NewDir);
  345. Result := InOutRes = 0;
  346. {$I+}
  347. InOutRes := OrigInOutRes;
  348. end;
  349. function CreateDir (const NewDir: string): boolean;
  350. var
  351. OrigInOutRes: word;
  352. begin
  353. OrigInOutRes := InOutRes;
  354. InOutRes := 0;
  355. {$I-}
  356. MkDir (NewDir);
  357. Result := InOutRes = 0;
  358. {$I+}
  359. InOutRes := OrigInOutRes;
  360. end;
  361. function RemoveDir (const Dir: string): boolean;
  362. var
  363. OrigInOutRes: word;
  364. begin
  365. OrigInOutRes := InOutRes;
  366. InOutRes := 0;
  367. {$I-}
  368. RmDir (Dir);
  369. Result := InOutRes = 0;
  370. {$I+}
  371. InOutRes := OrigInOutRes;
  372. end;
  373. function DirectoryExists (const Directory: string): boolean;
  374. var
  375. L: longint;
  376. begin
  377. if Directory = '' then
  378. Result := false
  379. else
  380. begin
  381. if ((Length (Directory) = 2) or
  382. (Length (Directory) = 3) and
  383. (Directory [3] in AllowDirectorySeparators)) and
  384. (Directory [2] in AllowDriveSeparators) and
  385. (UpCase (Directory [1]) in ['A'..'Z']) then
  386. (* Checking attributes for 'x:' is not possible but for 'x:.' it is. *)
  387. L := FileGetAttr (Directory + '.')
  388. else if (Directory [Length (Directory)] in AllowDirectorySeparators) and
  389. (Length (Directory) > 1) and
  390. (* Do not remove '\' in '\\' (invalid path, possibly broken UNC path). *)
  391. not (Directory [Length (Directory) - 1] in AllowDirectorySeparators) then
  392. L := FileGetAttr (Copy (Directory, 1, Length (Directory) - 1))
  393. else
  394. L := FileGetAttr (Directory);
  395. Result := (L > 0) and (L and faDirectory = faDirectory);
  396. end;
  397. end;
  398. {****************************************************************************
  399. Time Functions
  400. ****************************************************************************}
  401. procedure GetLocalTime (var SystemTime: TSystemTime);
  402. var
  403. DT: DosCalls.TDateTime;
  404. begin
  405. DosGetDateTime(DT);
  406. with SystemTime do
  407. begin
  408. Year:=DT.Year;
  409. Month:=DT.Month;
  410. Day:=DT.Day;
  411. Hour:=DT.Hour;
  412. Minute:=DT.Minute;
  413. Second:=DT.Second;
  414. MilliSecond:=DT.Sec100;
  415. end;
  416. end;
  417. {****************************************************************************
  418. Misc Functions
  419. ****************************************************************************}
  420. procedure sysbeep;
  421. begin
  422. // Maybe implement later on ?
  423. end;
  424. {****************************************************************************
  425. Locale Functions
  426. ****************************************************************************}
  427. procedure InitAnsi;
  428. var I: byte;
  429. Country: TCountryCode;
  430. begin
  431. for I := 0 to 255 do
  432. UpperCaseTable [I] := Chr (I);
  433. Move (UpperCaseTable, LowerCaseTable, SizeOf (UpperCaseTable));
  434. FillChar (Country, SizeOf (Country), 0);
  435. DosMapCase (SizeOf (UpperCaseTable), Country, @UpperCaseTable);
  436. for I := 0 to 255 do
  437. if UpperCaseTable [I] <> Chr (I) then
  438. LowerCaseTable [Ord (UpperCaseTable [I])] := Chr (I);
  439. end;
  440. procedure InitInternational;
  441. var Country: TCountryCode;
  442. CtryInfo: TCountryInfo;
  443. Size: cardinal;
  444. RC: cardinal;
  445. begin
  446. Size := 0;
  447. FillChar (Country, SizeOf (Country), 0);
  448. FillChar (CtryInfo, SizeOf (CtryInfo), 0);
  449. RC := DosQueryCtryInfo (SizeOf (CtryInfo), Country, CtryInfo, Size);
  450. if RC = 0 then
  451. begin
  452. DateSeparator := CtryInfo.DateSeparator;
  453. case CtryInfo.DateFormat of
  454. 1: begin
  455. ShortDateFormat := 'd/m/y';
  456. LongDateFormat := 'dd" "mmmm" "yyyy';
  457. end;
  458. 2: begin
  459. ShortDateFormat := 'y/m/d';
  460. LongDateFormat := 'yyyy" "mmmm" "dd';
  461. end;
  462. 3: begin
  463. ShortDateFormat := 'm/d/y';
  464. LongDateFormat := 'mmmm" "dd" "yyyy';
  465. end;
  466. end;
  467. TimeSeparator := CtryInfo.TimeSeparator;
  468. DecimalSeparator := CtryInfo.DecimalSeparator;
  469. ThousandSeparator := CtryInfo.ThousandSeparator;
  470. CurrencyFormat := CtryInfo.CurrencyFormat;
  471. CurrencyString := PChar (CtryInfo.CurrencyUnit);
  472. end;
  473. InitAnsi;
  474. InitInternationalGeneric;
  475. end;
  476. function SysErrorMessage(ErrorCode: Integer): String;
  477. begin
  478. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  479. end;
  480. {****************************************************************************
  481. OS Utils
  482. ****************************************************************************}
  483. function GetEnvPChar (EnvVar: shortstring): PChar;
  484. (* The assembler version is more than three times as fast as Pascal. *)
  485. var
  486. P: PChar;
  487. begin
  488. EnvVar := UpCase (EnvVar);
  489. {$ASMMODE INTEL}
  490. asm
  491. cld
  492. mov edi, Environment
  493. lea esi, EnvVar
  494. xor eax, eax
  495. lodsb
  496. @NewVar:
  497. cmp byte ptr [edi], 0
  498. jz @Stop
  499. push eax { eax contains length of searched variable name }
  500. push esi { esi points to the beginning of the variable name }
  501. mov ecx, -1 { our character ('=' - see below) _must_ be found }
  502. mov edx, edi { pointer to beginning of variable name saved in edx }
  503. mov al, '=' { searching until '=' (end of variable name) }
  504. repne
  505. scasb { scan until '=' not found }
  506. neg ecx { what was the name length? }
  507. dec ecx { corrected }
  508. dec ecx { exclude the '=' character }
  509. pop esi { restore pointer to beginning of variable name }
  510. pop eax { restore length of searched variable name }
  511. push eax { and save both of them again for later use }
  512. push esi
  513. cmp ecx, eax { compare length of searched variable name with name }
  514. jnz @NotEqual { ... of currently found variable, jump if different }
  515. xchg edx, edi { pointer to current variable name restored in edi }
  516. repe
  517. cmpsb { compare till the end of variable name }
  518. xchg edx, edi { pointer to beginning of variable contents in edi }
  519. jz @Equal { finish if they're equal }
  520. @NotEqual:
  521. xor eax, eax { look for 00h }
  522. mov ecx, -1 { it _must_ be found }
  523. repne
  524. scasb { scan until found }
  525. pop esi { restore pointer to beginning of variable name }
  526. pop eax { restore length of searched variable name }
  527. jmp @NewVar { ... or continue with new variable otherwise }
  528. @Stop:
  529. xor eax, eax
  530. mov P, eax { Not found - return nil }
  531. jmp @End
  532. @Equal:
  533. pop esi { restore the stack position }
  534. pop eax
  535. mov P, edi { place pointer to variable contents in P }
  536. @End:
  537. end ['eax','ecx','edx','esi','edi'];
  538. GetEnvPChar := P;
  539. end;
  540. {$ASMMODE ATT}
  541. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  542. begin
  543. GetEnvironmentVariable := StrPas (GetEnvPChar (EnvVar));
  544. end;
  545. Function GetEnvironmentVariableCount : Integer;
  546. begin
  547. (* Result:=FPCCountEnvVar(EnvP); - the amount is already known... *)
  548. GetEnvironmentVariableCount := EnvC;
  549. end;
  550. Function GetEnvironmentString(Index : Integer) : String;
  551. begin
  552. Result:=FPCGetEnvStrFromP (EnvP, Index);
  553. end;
  554. procedure Sleep (Milliseconds: cardinal);
  555. begin
  556. DosSleep (Milliseconds);
  557. end;
  558. function SysTimerTick: QWord;
  559. var
  560. L: cardinal;
  561. begin
  562. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  563. SysTimerTick := L;
  564. end;
  565. function ExecuteProcess (const Path: AnsiString; const ComLine: AnsiString;Flags:TExecuteFlags=[]):
  566. integer;
  567. var
  568. E: EOSError;
  569. CommandLine: ansistring;
  570. Args0, Args: DosCalls.PByteArray;
  571. ObjNameBuf: PChar;
  572. ArgSize: word;
  573. Res: TResultCodes;
  574. ObjName: shortstring;
  575. RC: cardinal;
  576. ExecAppType: cardinal;
  577. const
  578. MaxArgsSize = 3072; (* Amount of memory reserved for arguments in bytes. *)
  579. ObjBufSize = 512;
  580. function StartSession: cardinal;
  581. var
  582. HQ: THandle;
  583. SPID, STID, QName: shortstring;
  584. SID, PID: cardinal;
  585. SD: TStartData;
  586. RD: TRequestData;
  587. PCI: PChildInfo;
  588. CISize: cardinal;
  589. Prio: byte;
  590. begin
  591. Result := $FFFFFFFF;
  592. FillChar (SD, SizeOf (SD), 0);
  593. SD.Length := SizeOf (SD);
  594. SD.Related := ssf_Related_Child;
  595. if FileExists (Path) then
  596. (* Full path necessary for starting different executable files from current *)
  597. (* directory. *)
  598. CommandLine := ExpandFileName (Path)
  599. else
  600. CommandLine := Path;
  601. SD.PgmName := PChar (CommandLine);
  602. if ComLine <> '' then
  603. SD.PgmInputs := PChar (ComLine);
  604. if ExecInheritsHandles in Flags then
  605. SD.InheritOpt := ssf_InhertOpt_Parent;
  606. Str (GetProcessID, SPID);
  607. Str (ThreadID, STID);
  608. QName := '\QUEUES\FPC_ExecuteProcess_p' + SPID + 't' + STID + '.QUE'#0;
  609. SD.TermQ := @QName [1];
  610. SD.ObjectBuffer := ObjNameBuf;
  611. SD.ObjectBuffLen := ObjBufSize;
  612. RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
  613. if RC <> 0 then
  614. Move (QName [1], ObjNameBuf^, Length (QName))
  615. else
  616. begin
  617. RC := DosStartSession (SD, SID, PID);
  618. if (RC = 0) or (RC = 457) then
  619. begin
  620. RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
  621. if RC = 0 then
  622. begin
  623. Result := PCI^.Return;
  624. DosCloseQueue (HQ);
  625. DosFreeMem (PCI);
  626. FreeMem (ObjNameBuf, ObjBufSize);
  627. end
  628. else
  629. DosCloseQueue (HQ);
  630. end
  631. else
  632. DosCloseQueue (HQ);
  633. end;
  634. end;
  635. begin
  636. Result := integer ($FFFFFFFF);
  637. ObjName := '';
  638. GetMem (ObjNameBuf, ObjBufSize);
  639. FillChar (ObjNameBuf^, ObjBufSize, 0);
  640. if (DosQueryAppType (PChar (Path), ExecAppType) = 0) and
  641. (ApplicationType and 3 = ExecAppType and 3) then
  642. (* DosExecPgm should work... *)
  643. begin
  644. if ComLine = '' then
  645. begin
  646. Args0 := nil;
  647. Args := nil;
  648. end
  649. else
  650. begin
  651. GetMem (Args0, MaxArgsSize);
  652. Args := Args0;
  653. (* Work around a bug in OS/2 - argument to DosExecPgm *)
  654. (* should not cross 64K boundary. *)
  655. if ((PtrUInt (Args) + 1024) and $FFFF) < 1024 then
  656. Inc (pointer (Args), 1024);
  657. ArgSize := 0;
  658. Move (Path [1], Args^ [ArgSize], Length (Path));
  659. Inc (ArgSize, Length (Path));
  660. Args^ [ArgSize] := 0;
  661. Inc (ArgSize);
  662. {Now do the real arguments.}
  663. Move (ComLine [1], Args^ [ArgSize], Length (ComLine));
  664. Inc (ArgSize, Length (ComLine));
  665. Args^ [ArgSize] := 0;
  666. Inc (ArgSize);
  667. Args^ [ArgSize] := 0;
  668. end;
  669. Res.ExitCode := $FFFFFFFF;
  670. RC := DosExecPgm (ObjNameBuf, ObjBufSize, 0, Args, nil, Res, PChar (Path));
  671. if Args0 <> nil then
  672. FreeMem (Args0, MaxArgsSize);
  673. if RC = 0 then
  674. begin
  675. Result := Res.ExitCode;
  676. FreeMem (ObjNameBuf, ObjBufSize);
  677. end
  678. else
  679. begin
  680. if (RC = 190) or (RC = 191) then
  681. Result := StartSession;
  682. end;
  683. end
  684. else
  685. Result := StartSession;
  686. if RC <> 0 then
  687. begin
  688. ObjName := StrPas (ObjNameBuf);
  689. FreeMem (ObjNameBuf, ObjBufSize);
  690. if ComLine = '' then
  691. CommandLine := Path
  692. else
  693. CommandLine := Path + ' ' + ComLine;
  694. if ObjName = '' then
  695. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, RC])
  696. else
  697. E := EOSError.CreateFmt (SExecuteProcessFailed + ' (' + ObjName + ')', [CommandLine, RC]);
  698. E.ErrorCode := Result;
  699. raise E;
  700. end;
  701. end;
  702. function ExecuteProcess (const Path: AnsiString;
  703. const ComLine: array of AnsiString;Flags:TExecuteFlags=[]): integer;
  704. var
  705. CommandLine: AnsiString;
  706. I: integer;
  707. begin
  708. Commandline := '';
  709. for I := 0 to High (ComLine) do
  710. if Pos (' ', ComLine [I]) <> 0 then
  711. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  712. else
  713. CommandLine := CommandLine + ' ' + Comline [I];
  714. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  715. end;
  716. function GetTickCount: LongWord;
  717. var
  718. L: cardinal;
  719. begin
  720. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  721. GetTickCount := L;
  722. end;
  723. function GetTickCount64: QWord;
  724. var
  725. L: cardinal;
  726. begin
  727. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  728. GetTickCount64 := L;
  729. end;
  730. {****************************************************************************
  731. Initialization code
  732. ****************************************************************************}
  733. Initialization
  734. InitExceptions; { Initialize exceptions. OS independent }
  735. InitInternational; { Initialize internationalization settings }
  736. OnBeep:=@SysBeep;
  737. Finalization
  738. DoneExceptions;
  739. end.