sysutils.pp 22 KB

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