sysutils.pp 22 KB

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