sysutils.pp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2010 by Sven Barth
  4. member of the Free Pascal development team
  5. Sysutils unit for NativeNT
  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. {$modeswitch typehelpers}
  19. {$modeswitch advancedrecords}
  20. uses
  21. ndk;
  22. {$DEFINE HAS_SLEEP}
  23. {$DEFINE HAS_CREATEGUID}
  24. type
  25. TNativeNTFindData = record
  26. SearchSpec: UnicodeString;
  27. NamePos: LongInt;
  28. Handle: THandle;
  29. IsDirObj: Boolean;
  30. SearchAttr: LongInt;
  31. Context: ULONG;
  32. LastRes: NTSTATUS;
  33. end;
  34. { used OS file system APIs use ansistring }
  35. {$define SYSUTILS_HAS_UNICODESTR_FILEUTIL_IMPL}
  36. { OS has an ansistring/single byte environment variable API (actually it's
  37. unicodestring, but that's not yet implemented) }
  38. {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
  39. { Include platform independent interface part }
  40. {$i sysutilh.inc}
  41. implementation
  42. uses
  43. sysconst, ndkutils;
  44. {$DEFINE FPC_NOGENERICANSIROUTINES}
  45. { Include platform independent implementation part }
  46. {$i sysutils.inc}
  47. {****************************************************************************
  48. File Functions
  49. ****************************************************************************}
  50. function FileOpen(const FileName : UnicodeString; Mode : Integer) : THandle;
  51. const
  52. AccessMode: array[0..2] of ACCESS_MASK = (
  53. GENERIC_READ,
  54. GENERIC_WRITE,
  55. GENERIC_READ or GENERIC_WRITE);
  56. ShareMode: array[0..4] of ULONG = (
  57. 0,
  58. 0,
  59. FILE_SHARE_READ,
  60. FILE_SHARE_WRITE,
  61. FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE);
  62. var
  63. ntstr: UNICODE_STRING;
  64. objattr: OBJECT_ATTRIBUTES;
  65. iostatus: IO_STATUS_BLOCK;
  66. begin
  67. UnicodeStrToNtStr(FileName, ntstr);
  68. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  69. NtCreateFile(@Result, AccessMode[Mode and 3] or NT_SYNCHRONIZE, @objattr,
  70. @iostatus, Nil, FILE_ATTRIBUTE_NORMAL, ShareMode[(Mode and $F0) shr 4],
  71. FILE_OPEN, FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, Nil, 0);
  72. FreeNtStr(ntstr);
  73. end;
  74. function FileCreate(const FileName : UnicodeString) : THandle;
  75. begin
  76. FileCreate := FileCreate(FileName, fmShareDenyNone, 0);
  77. end;
  78. function FileCreate(const FileName : UnicodeString; Rights: longint) : THandle;
  79. begin
  80. FileCreate := FileCreate(FileName, fmShareDenyNone, Rights);
  81. end;
  82. function FileCreate(const FileName : UnicodeString; ShareMode : longint; Rights: longint) : THandle;
  83. const
  84. ShareModeFlags: array[0..4] of ULONG = (
  85. 0,
  86. 0,
  87. FILE_SHARE_READ,
  88. FILE_SHARE_WRITE,
  89. FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE);
  90. var
  91. ntstr: UNICODE_STRING;
  92. objattr: OBJECT_ATTRIBUTES;
  93. iostatus: IO_STATUS_BLOCK;
  94. res: NTSTATUS;
  95. begin
  96. UnicodeStrToNtStr(FileName, ntstr);
  97. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  98. NtCreateFile(@Result, GENERIC_READ or GENERIC_WRITE or NT_SYNCHRONIZE,
  99. @objattr, @iostatus, Nil, FILE_ATTRIBUTE_NORMAL,
  100. ShareModeFlags[(ShareMode and $F0) shr 4], FILE_OVERWRITE_IF,
  101. FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, Nil, 0);
  102. FreeNtStr(ntstr);
  103. end;
  104. function FileRead(Handle : THandle; out Buffer; Count : longint) : Longint;
  105. var
  106. iostatus: IO_STATUS_BLOCK;
  107. res: NTSTATUS;
  108. begin
  109. res := NtReadFile(Handle, 0, Nil, Nil, @iostatus, @Buffer, Count, Nil, Nil);
  110. if res = STATUS_PENDING then begin
  111. res := NtWaitForSingleObject(Handle, False, Nil);
  112. if NT_SUCCESS(res) then
  113. res := iostatus.union1.Status;
  114. end;
  115. if NT_SUCCESS(res) then
  116. Result := LongInt(iostatus.Information)
  117. else
  118. Result := -1;
  119. end;
  120. function FileWrite(Handle : THandle; const Buffer; Count : Longint) : Longint;
  121. var
  122. iostatus: IO_STATUS_BLOCK;
  123. res: NTSTATUS;
  124. begin
  125. res := NtWriteFile(Handle, 0, Nil, Nil, @iostatus, @Buffer, Count, Nil,
  126. Nil);
  127. if res = STATUS_PENDING then begin
  128. res := NtWaitForSingleObject(Handle, False, Nil);
  129. if NT_SUCCESS(res) then
  130. res := iostatus.union1.Status;
  131. end;
  132. if NT_SUCCESS(res) then
  133. Result := LongInt(iostatus.Information)
  134. else
  135. Result := -1;
  136. end;
  137. function FileSeek(Handle : THandle;FOffset,Origin : Longint) : Longint;
  138. begin
  139. Result := longint(FileSeek(Handle, Int64(FOffset), Origin));
  140. end;
  141. function FileSeek(Handle : THandle; FOffset: Int64; Origin: Longint) : Int64;
  142. const
  143. ErrorCode = $FFFFFFFFFFFFFFFF;
  144. var
  145. position: FILE_POSITION_INFORMATION;
  146. standard: FILE_STANDARD_INFORMATION;
  147. iostatus: IO_STATUS_BLOCK;
  148. res: NTSTATUS;
  149. begin
  150. { determine the new position }
  151. case Origin of
  152. fsFromBeginning:
  153. position.CurrentByteOffset.QuadPart := FOffset;
  154. fsFromCurrent: begin
  155. res := NtQueryInformationFile(Handle, @iostatus, @position,
  156. SizeOf(FILE_POSITION_INFORMATION), FilePositionInformation);
  157. if res < 0 then begin
  158. Result := ErrorCode;
  159. Exit;
  160. end;
  161. position.CurrentByteOffset.QuadPart :=
  162. position.CurrentByteOffset.QuadPart + FOffset;
  163. end;
  164. fsFromEnd: begin
  165. res := NtQueryInformationFile(Handle, @iostatus, @standard,
  166. SizeOf(FILE_STANDARD_INFORMATION), FileStandardInformation);
  167. if res < 0 then begin
  168. Result := ErrorCode;
  169. Exit;
  170. end;
  171. position.CurrentByteOffset.QuadPart := standard.EndOfFile.QuadPart +
  172. FOffset;
  173. end;
  174. else begin
  175. Result := ErrorCode;
  176. Exit;
  177. end;
  178. end;
  179. { set the new position }
  180. res := NtSetInformationFile(Handle, @iostatus, @position,
  181. SizeOf(FILE_POSITION_INFORMATION), FilePositionInformation);
  182. if res < 0 then
  183. Result := ErrorCode
  184. else
  185. Result := position.CurrentByteOffset.QuadPart;
  186. end;
  187. procedure FileClose(Handle : THandle);
  188. begin
  189. NtClose(Handle);
  190. end;
  191. function FileTruncate(Handle : THandle;Size: Int64) : boolean;
  192. var
  193. endoffileinfo: FILE_END_OF_FILE_INFORMATION;
  194. allocinfo: FILE_ALLOCATION_INFORMATION;
  195. iostatus: IO_STATUS_BLOCK;
  196. res: NTSTATUS;
  197. begin
  198. // based on ReactOS' SetEndOfFile
  199. endoffileinfo.EndOfFile.QuadPart := Size;
  200. res := NtSetInformationFile(Handle, @iostatus, @endoffileinfo,
  201. SizeOf(FILE_END_OF_FILE_INFORMATION), FileEndOfFileInformation);
  202. if NT_SUCCESS(res) then begin
  203. allocinfo.AllocationSize.QuadPart := Size;
  204. res := NtSetInformationFile(handle, @iostatus, @allocinfo,
  205. SizeOf(FILE_ALLOCATION_INFORMATION), FileAllocationInformation);
  206. Result := NT_SUCCESS(res);
  207. end else
  208. Result := False;
  209. end;
  210. function NTToDosTime(const NtTime: LARGE_INTEGER): LongInt;
  211. var
  212. userdata: PKUSER_SHARED_DATA;
  213. local, bias: LARGE_INTEGER;
  214. fields: TIME_FIELDS;
  215. zs: LongInt;
  216. begin
  217. userdata := SharedUserData;
  218. repeat
  219. bias.u.HighPart := userdata^.TimeZoneBias.High1Time;
  220. bias.u.LowPart := userdata^.TimeZoneBias.LowPart;
  221. until bias.u.HighPart = userdata^.TimeZoneBias.High2Time;
  222. local.QuadPart := NtTime.QuadPart - bias.QuadPart;
  223. RtlTimeToTimeFields(@local, @fields);
  224. { from objpas\datutil.inc\DateTimeToDosDateTime }
  225. Result := - 1980;
  226. Result := Result + fields.Year and 127;
  227. Result := Result shl 4;
  228. Result := Result + fields.Month;
  229. Result := Result shl 5;
  230. Result := Result + fields.Day;
  231. Result := Result shl 16;
  232. zs := fields.Hour;
  233. zs := zs shl 6;
  234. zs := zs + fields.Minute;
  235. zs := zs shl 5;
  236. zs := zs + fields.Second div 2;
  237. Result := Result + (zs and $ffff);
  238. end;
  239. function DosToNtTime(aDTime: LongInt; var aNtTime: LARGE_INTEGER): Boolean;
  240. var
  241. fields: TIME_FIELDS;
  242. local, bias: LARGE_INTEGER;
  243. userdata: PKUSER_SHARED_DATA;
  244. begin
  245. { from objpas\datutil.inc\DosDateTimeToDateTime }
  246. fields.Second := (aDTime and 31) * 2;
  247. aDTime := aDTime shr 5;
  248. fields.Minute := aDTime and 63;
  249. aDTime := aDTime shr 6;
  250. fields.Hour := aDTime and 31;
  251. aDTime := aDTime shr 5;
  252. fields.Day := aDTime and 31;
  253. aDTime := aDTime shr 5;
  254. fields.Month := aDTime and 15;
  255. aDTime := aDTime shr 4;
  256. fields.Year := aDTime + 1980;
  257. Result := RtlTimeFieldsToTime(@fields, @local);
  258. if not Result then
  259. Exit;
  260. userdata := SharedUserData;
  261. repeat
  262. bias.u.HighPart := userdata^.TimeZoneBias.High1Time;
  263. bias.u.LowPart := userdata^.TimeZoneBias.LowPart;
  264. until bias.u.HighPart = userdata^.TimeZoneBias.High2Time;
  265. aNtTime.QuadPart := local.QuadPart + bias.QuadPart;
  266. end;
  267. function FileAge(const FileName: UnicodeString): Longint;
  268. begin
  269. { TODO }
  270. Result := -1;
  271. end;
  272. function FileExists(const FileName: UnicodeString; FollowLink : Boolean): Boolean;
  273. var
  274. ntstr: UNICODE_STRING;
  275. objattr: OBJECT_ATTRIBUTES;
  276. res: NTSTATUS;
  277. iostatus: IO_STATUS_BLOCK;
  278. h: THandle;
  279. begin
  280. UnicodeStrToNtStr(FileName, ntstr);
  281. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  282. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  283. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  284. FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  285. Result := NT_SUCCESS(res);
  286. if Result then
  287. NtClose(h);
  288. FreeNtStr(ntstr);
  289. end;
  290. function DirectoryExists(const Directory : UnicodeString; FollowLink : Boolean) : Boolean;
  291. var
  292. ntstr: UNICODE_STRING;
  293. objattr: OBJECT_ATTRIBUTES;
  294. res: NTSTATUS;
  295. iostatus: IO_STATUS_BLOCK;
  296. h: THandle;
  297. begin
  298. UnicodeStrToNtStr(Directory, ntstr);
  299. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  300. { first test wether this is a object directory }
  301. res := NtOpenDirectoryObject(@h, DIRECTORY_QUERY, @objattr);
  302. if NT_SUCCESS(res) then
  303. Result := True
  304. else begin
  305. if res = STATUS_OBJECT_TYPE_MISMATCH then begin
  306. { this is a file object! }
  307. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  308. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  309. FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  310. Result := NT_SUCCESS(res);
  311. end else
  312. Result := False;
  313. end;
  314. if Result then
  315. NtClose(h);
  316. FreeNtStr(ntstr);
  317. end;
  318. { copied from rtl/unix/sysutils.pp and adapted to UTF-16 }
  319. Function FNMatch(const Pattern,Name:UnicodeString):Boolean;
  320. Var
  321. LenPat,LenName : longint;
  322. function NameUtf16CodePointLen(index: longint): longint;
  323. begin
  324. { see https://en.wikipedia.org/wiki/UTF-16#Description for details }
  325. Result:=1;
  326. { valid surrogate pair? }
  327. if (Name[index]>=#$D800) and
  328. (Name[index]<=#$DBFF) then
  329. begin
  330. if (index+1<=LenName) and
  331. (Name[index+1]>=#$DC00) and
  332. (Name[index+1]<=#$DFFF) then
  333. inc(Result)
  334. else
  335. exit;
  336. end;
  337. { combining diacritics?
  338. 1) U+0300 - U+036F
  339. 2) U+1DC0 - U+1DFF
  340. 3) U+20D0 - U+20FF
  341. 4) U+FE20 - U+FE2F
  342. }
  343. while (index+Result+1<=LenName) and
  344. ((word(ord(Name[index+Result+1])-$0300) <= word($036F-$0300)) or
  345. (word(ord(Name[index+Result+1])-$1DC0) <= word($1DFF-$1DC0)) or
  346. (word(ord(Name[index+Result+1])-$20D0) <= word($20FF-$20D0)) or
  347. (word(ord(Name[index+Result+1])-$FE20) <= word($FE2F-$FE20))) do
  348. begin
  349. inc(Result)
  350. end;
  351. end;
  352. procedure GoToLastByteOfUtf16CodePoint(var j: longint);
  353. begin
  354. { Take one less, because we have to stop at the last word of the sequence.
  355. }
  356. inc(j,NameUtf16CodePointLen(j)-1);
  357. end;
  358. { input:
  359. i: current position in pattern (start of utf-16 code point)
  360. j: current position in name (start of utf-16 code point)
  361. update_i_j: should i and j be changed by the routine or not
  362. output:
  363. i: if update_i_j, then position of last matching part of code point in
  364. pattern, or first non-matching code point in pattern. Otherwise the
  365. same value as on input.
  366. j: if update_i_j, then position of last matching part of code point in
  367. name, or first non-matching code point in name. Otherwise the
  368. same value as on input.
  369. result: true if match, false if no match
  370. }
  371. function CompareUtf16CodePoint(var i,j: longint; update_i_j: boolean): Boolean;
  372. var
  373. words,
  374. new_i,
  375. new_j: longint;
  376. begin
  377. words:=NameUtf16CodePointLen(j);
  378. new_i:=i;
  379. new_j:=j;
  380. { ensure that a part of an UTF-8 codepoint isn't interpreted
  381. as '*' or '?' }
  382. repeat
  383. dec(words);
  384. Result:=
  385. (new_j<=LenName) and
  386. (new_i<=LenPat) and
  387. (Pattern[new_i]=Name[new_j]);
  388. inc(new_i);
  389. inc(new_j);
  390. until not(Result) or
  391. (words=0);
  392. if update_i_j then
  393. begin
  394. i:=new_i;
  395. j:=new_j;
  396. end;
  397. end;
  398. Function DoFNMatch(i,j:longint):Boolean;
  399. Var
  400. Found : boolean;
  401. Begin
  402. Found:=true;
  403. While Found and (i<=LenPat) Do
  404. Begin
  405. Case Pattern[i] of
  406. '?' :
  407. begin
  408. Found:=(j<=LenName);
  409. GoToLastByteOfUtf16CodePoint(j);
  410. end;
  411. '*' : Begin
  412. {find the next character in pattern, different of ? and *}
  413. while Found do
  414. begin
  415. inc(i);
  416. if i>LenPat then
  417. Break;
  418. case Pattern[i] of
  419. '*' : ;
  420. '?' : begin
  421. if j>LenName then
  422. begin
  423. DoFNMatch:=false;
  424. Exit;
  425. end;
  426. GoToLastByteOfUtf16CodePoint(j);
  427. inc(j);
  428. end;
  429. else
  430. Found:=false;
  431. end;
  432. end;
  433. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  434. { Now, find in name the character which i points to, if the * or
  435. ? wasn't the last character in the pattern, else, use up all
  436. the chars in name }
  437. Found:=false;
  438. if (i<=LenPat) then
  439. begin
  440. repeat
  441. {find a letter (not only first !) which maches pattern[i]}
  442. while (j<=LenName) and
  443. ((name[j]<>pattern[i]) or
  444. not CompareUtf16CodePoint(i,j,false)) do
  445. begin
  446. GoToLastByteOfUtf16CodePoint(j);
  447. inc(j);
  448. end;
  449. if (j<LenName) then
  450. begin
  451. { while positions i/j have already been checked, we have to
  452. ensure that we don't split a code point }
  453. if DoFnMatch(i,j) then
  454. begin
  455. i:=LenPat;
  456. j:=LenName;{we can stop}
  457. Found:=true;
  458. Break;
  459. end
  460. { We didn't find one, need to look further }
  461. else
  462. begin
  463. GoToLastByteOfUtf16CodePoint(j);
  464. inc(j);
  465. end;
  466. end
  467. else if j=LenName then
  468. begin
  469. Found:=true;
  470. Break;
  471. end;
  472. { This 'until' condition must be j>LenName, not j>=LenName.
  473. That's because when we 'need to look further' and
  474. j = LenName then loop must not terminate. }
  475. until (j>LenName);
  476. end
  477. else
  478. begin
  479. j:=LenName;{we can stop}
  480. Found:=true;
  481. end;
  482. end;
  483. #$D800..#$DBFF:
  484. begin
  485. { ensure that a part of an UTF-16 codepoint isn't matched with
  486. '*' or '?' }
  487. Found:=CompareUtf16CodePoint(i,j,true);
  488. { at this point, either Found is false (and we'll stop), or
  489. both pattern[i] and name[j] are the end of the current code
  490. point and equal }
  491. end
  492. else {not a wildcard character in pattern}
  493. Found:=(j<=LenName) and (pattern[i]=name[j]);
  494. end;
  495. inc(i);
  496. inc(j);
  497. end;
  498. DoFnMatch:=Found and (j>LenName);
  499. end;
  500. Begin {start FNMatch}
  501. LenPat:=Length(Pattern);
  502. LenName:=Length(Name);
  503. FNMatch:=DoFNMatch(1,1);
  504. End;
  505. function FindGetFileInfo(const s: UnicodeString; var f: TAbstractSearchRec; var Name: UnicodeString): Boolean;
  506. var
  507. ntstr: UNICODE_STRING;
  508. objattr: OBJECT_ATTRIBUTES;
  509. res: NTSTATUS;
  510. h: THandle;
  511. iostatus: IO_STATUS_BLOCK;
  512. attr: LongInt;
  513. filename: UnicodeString;
  514. isfileobj: Boolean;
  515. objinfo: OBJECT_BASIC_INFORMATION;
  516. fileinfo: FILE_BASIC_INFORMATION;
  517. time: LongInt;
  518. begin
  519. UnicodeStrToNtStr(s, ntstr);
  520. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  521. filename := ExtractFileName(s);
  522. { TODO : handle symlinks }
  523. { If Assigned(F.FindHandle) and ((((PUnixFindData(f.FindHandle)^.searchattr)) and faSymlink) > 0) then
  524. FindGetFileInfo:=(fplstat(pointer(s),st)=0)
  525. else
  526. FindGetFileInfo:=(fpstat(pointer(s),st)=0);}
  527. attr := 0;
  528. Result := False;
  529. if (faDirectory and f.FindData.SearchAttr <> 0) and
  530. ((filename = '.') or (filename = '..')) then begin
  531. attr := faDirectory;
  532. res := STATUS_SUCCESS;
  533. end else
  534. res := STATUS_INVALID_PARAMETER;
  535. isfileobj := False;
  536. if not NT_SUCCESS(res) then begin
  537. { first check whether it's a directory }
  538. res := NtOpenDirectoryObject(@h, DIRECTORY_QUERY, @objattr);
  539. if not NT_SUCCESS(res) then
  540. if res = STATUS_OBJECT_TYPE_MISMATCH then begin
  541. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  542. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  543. FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  544. isfileobj := NT_SUCCESS(res);
  545. end;
  546. if NT_SUCCESS(res) then
  547. attr := faDirectory;
  548. end;
  549. if not NT_SUCCESS(res) then begin
  550. { first try whether we have a file object }
  551. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  552. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  553. FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  554. isfileobj := NT_SUCCESS(res);
  555. if res = STATUS_OBJECT_TYPE_MISMATCH then begin
  556. { is this an object? }
  557. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  558. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  559. FILE_SYNCHRONOUS_IO_NONALERT);
  560. if (res = STATUS_OBJECT_TYPE_MISMATCH)
  561. and (f.FindData.SearchAttr and faSysFile <> 0) then begin
  562. { this is some other system file like an event or port, so we can only
  563. provide it's name }
  564. res := STATUS_SUCCESS;
  565. attr := faSysFile;
  566. end;
  567. end;
  568. end;
  569. FreeNtStr(ntstr);
  570. if not NT_SUCCESS(res) then
  571. Exit;
  572. time := 0;
  573. if isfileobj then begin
  574. res := NtQueryInformationFile(h, @iostatus, @fileinfo, SizeOf(fileinfo),
  575. FileBasicInformation);
  576. if NT_SUCCESS(res) then begin
  577. time := NtToDosTime(fileinfo.LastWriteTime);
  578. { copy file attributes? }
  579. end;
  580. end else begin
  581. res := NtQueryObject(h, ObjectBasicInformation, @objinfo, SizeOf(objinfo),
  582. Nil);
  583. if NT_SUCCESS(res) then begin
  584. time := NtToDosTime(objinfo.CreateTime);
  585. { what about attributes? }
  586. end;
  587. end;
  588. if (attr and not f.FindData.SearchAttr) = 0 then begin
  589. Name := filename;
  590. f.Attr := attr;
  591. f.Size := 0;
  592. {$ifndef FPUNONE}
  593. if time = 0 then
  594. { for now we use "Now" as a fall back; ideally this should be the system
  595. start time }
  596. f.Time := DateTimeToFileDate(Now)
  597. else
  598. f.Time := time;
  599. {$endif}
  600. Result := True;
  601. end else
  602. Result := False;
  603. NtClose(h);
  604. end;
  605. Procedure InternalFindClose (var Handle: THandle; var FindData: TFindData);
  606. begin
  607. if FindData.Handle <> 0 then
  608. begin
  609. NtClose(FindData.Handle);
  610. FindData.Handle:=0;
  611. end;
  612. end;
  613. Function InternalFindNext (Var Rslt : TAbstractSearchRec; var Name: UnicodeString) : Longint;
  614. {
  615. re-opens dir if not already in array and calls FindGetFileInfo
  616. }
  617. Var
  618. DirName : UnicodeString;
  619. FName,
  620. SName : UnicodeString;
  621. Found,
  622. Finished : boolean;
  623. ntstr: UNICODE_STRING;
  624. objattr: OBJECT_ATTRIBUTES;
  625. buf: array of WideChar;
  626. len: LongWord;
  627. res: NTSTATUS;
  628. i: LongInt;
  629. dirinfo: POBJECT_DIRECTORY_INFORMATION;
  630. filedirinfo: PFILE_DIRECTORY_INFORMATION;
  631. pc: PChar;
  632. filename: UnicodeString;
  633. iostatus: IO_STATUS_BLOCK;
  634. begin
  635. { TODO : relative directories }
  636. Result := -1;
  637. { SearchSpec='' means that there were no wild cards, so only one file to
  638. find.
  639. }
  640. if Rslt.FindData.SearchSpec = '' then
  641. Exit;
  642. { relative directories not supported for now }
  643. if Rslt.FindData.NamePos = 0 then
  644. Exit;
  645. if Rslt.FindData.Handle = 0 then begin
  646. if Rslt.FindData.NamePos > 1 then
  647. filename := Copy(Rslt.FindData.SearchSpec, 1, Rslt.FindData.NamePos - 1)
  648. else
  649. if Rslt.FindData.NamePos = 1 then
  650. filename := Copy(Rslt.FindData.SearchSpec, 1, 1)
  651. else
  652. filename := Rslt.FindData.SearchSpec;
  653. UnicodeStrToNtStr(filename, ntstr);
  654. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  655. res := NtOpenDirectoryObject(@Rslt.FindData.Handle,
  656. DIRECTORY_QUERY or DIRECTORY_TRAVERSE, @objattr);
  657. if not NT_SUCCESS(res) then begin
  658. if res = STATUS_OBJECT_TYPE_MISMATCH then
  659. res := NtOpenFile(@Rslt.FindData.Handle,
  660. FILE_LIST_DIRECTORY or NT_SYNCHRONIZE, @objattr,
  661. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  662. FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  663. end else
  664. Rslt.FindData.IsDirObj := True;
  665. FreeNTStr(ntstr);
  666. if not NT_SUCCESS(res) then
  667. Exit;
  668. end;
  669. { if (NTFindData^.SearchType = 0) and
  670. (NTFindData^.Dirptr = Nil) then
  671. begin
  672. If NTFindData^.NamePos = 0 Then
  673. DirName:='./'
  674. Else
  675. DirName:=Copy(NTFindData^.SearchSpec,1,NTFindData^.NamePos);
  676. NTFindData^.DirPtr := fpopendir(Pchar(pointer(DirName)));
  677. end;}
  678. SName := Copy(Rslt.FindData.SearchSpec, Rslt.FindData.NamePos + 1,
  679. Length(Rslt.FindData.SearchSpec));
  680. Found := False;
  681. Finished := not NT_SUCCESS(Rslt.FindData.LastRes)
  682. or (Rslt.FindData.LastRes = STATUS_NO_MORE_ENTRIES);
  683. SetLength(buf, 200);
  684. dirinfo := @buf[0];
  685. filedirinfo := @buf[0];
  686. while not Finished do begin
  687. if Rslt.FindData.IsDirObj then
  688. res := NtQueryDirectoryObject(Rslt.FindData.Handle, @buf[0],
  689. Length(buf) * SizeOf(buf[0]), True, False,
  690. @Rslt.FindData.Context, @len)
  691. else
  692. res := NtQueryDirectoryFile(Rslt.FindData.Handle, 0, Nil, Nil, @iostatus,
  693. @buf[0], Length(buf) * SizeOf(buf[0]), FileDirectoryInformation,
  694. True, Nil, False);
  695. if Rslt.FindData.IsDirObj then begin
  696. Finished := (res = STATUS_NO_MORE_ENTRIES)
  697. or (res = STATUS_NO_MORE_FILES)
  698. or not NT_SUCCESS(res);
  699. Rslt.FindData.LastRes := res;
  700. if dirinfo^.Name.Length > 0 then begin
  701. SetLength(FName, dirinfo^.Name.Length div 2);
  702. move(dirinfo^.Name.Buffer[0],FName[1],dirinfo^.Name.Length);
  703. {$ifdef debug_findnext}
  704. Write(FName, ' (');
  705. for i := 0 to dirinfo^.TypeName.Length div 2 - 1 do
  706. if dirinfo^.TypeName.Buffer[i] < #256 then
  707. Write(AnsiChar(Byte(dirinfo^.TypeName.Buffer[i])))
  708. else
  709. Write('?');
  710. Writeln(')');
  711. {$endif debug_findnext}
  712. end else
  713. FName := '';
  714. end else begin
  715. SetLength(FName, filedirinfo^.FileNameLength div 2);
  716. move(filedirinfo^.FileName[0],FName[1],filedirinfo^.FileNameLength);
  717. end;
  718. if FName = '' then
  719. Finished := True
  720. else begin
  721. if FNMatch(SName, FName) then begin
  722. Found := FindGetFileInfo(Copy(Rslt.FindData.SearchSpec, 1,
  723. Rslt.FindData.NamePos) + FName, Rslt, Name);
  724. if Found then begin
  725. Result := 0;
  726. Exit;
  727. end;
  728. end;
  729. end;
  730. end;
  731. end;
  732. Function InternalFindFirst (Const Path : UnicodeString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name : UnicodeString) : Longint;
  733. {
  734. opens dir and calls FindNext if needed.
  735. }
  736. Begin
  737. Result := -1;
  738. if Path = '' then
  739. Exit;
  740. Rslt.FindData.SearchAttr := Attr;
  741. {Wildcards?}
  742. if (Pos('?', Path) = 0) and (Pos('*', Path) = 0) then begin
  743. if FindGetFileInfo(Path, Rslt, Name) then
  744. Result := 0;
  745. end else begin
  746. {Create Info}
  747. Rslt.FindData.SearchSpec := Path;
  748. Rslt.FindData.NamePos := Length(Rslt.FindData.SearchSpec);
  749. while (Rslt.FindData.NamePos > 0)
  750. and (Rslt.FindData.SearchSpec[Rslt.FindData.NamePos] <> DirectorySeparator)
  751. do
  752. Dec(Rslt.FindData.NamePos);
  753. Result := InternalFindNext(Rslt,Name);
  754. end;
  755. if Result <> 0 then
  756. InternalFindClose(Rslt.FindHandle,Rslt.FindData);
  757. end;
  758. function FileGetDate(Handle: THandle): Longint;
  759. var
  760. res: NTSTATUS;
  761. basic: FILE_BASIC_INFORMATION;
  762. iostatus: IO_STATUS_BLOCK;
  763. begin
  764. res := NtQueryInformationFile(Handle, @iostatus, @basic,
  765. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  766. if NT_SUCCESS(res) then
  767. Result := NtToDosTime(basic.LastWriteTime)
  768. else
  769. Result := -1;
  770. end;
  771. function FileSetDate(Handle: THandle;Age: Longint): Longint;
  772. var
  773. res: NTSTATUS;
  774. basic: FILE_BASIC_INFORMATION;
  775. iostatus: IO_STATUS_BLOCK;
  776. begin
  777. res := NtQueryInformationFile(Handle, @iostatus, @basic,
  778. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  779. if NT_SUCCESS(res) then begin
  780. if not DosToNtTime(Age, basic.LastWriteTime) then begin
  781. Result := -1;
  782. Exit;
  783. end;
  784. res := NtSetInformationFile(Handle, @iostatus, @basic,
  785. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  786. if NT_SUCCESS(res) then
  787. Result := 0
  788. else
  789. Result := res;
  790. end else
  791. Result := res;
  792. end;
  793. function FileGetAttr(const FileName: UnicodeString): Longint;
  794. var
  795. objattr: OBJECT_ATTRIBUTES;
  796. info: FILE_NETWORK_OPEN_INFORMATION;
  797. res: NTSTATUS;
  798. ntstr: UNICODE_STRING;
  799. begin
  800. UnicodeStrToNtStr(FileName, ntstr);
  801. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  802. res := NtQueryFullAttributesFile(@objattr, @info);
  803. if NT_SUCCESS(res) then
  804. Result := info.FileAttributes
  805. else
  806. Result := 0;
  807. FreeNtStr(ntstr);
  808. end;
  809. function FileSetAttr(const Filename: UnicodeString; Attr: LongInt): Longint;
  810. var
  811. h: THandle;
  812. objattr: OBJECT_ATTRIBUTES;
  813. ntstr: UNICODE_STRING;
  814. basic: FILE_BASIC_INFORMATION;
  815. res: NTSTATUS;
  816. iostatus: IO_STATUS_BLOCK;
  817. begin
  818. UnicodeStrToNtStr(Filename, ntstr);
  819. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  820. res := NtOpenFile(@h,
  821. NT_SYNCHRONIZE or FILE_READ_ATTRIBUTES or FILE_WRITE_ATTRIBUTES,
  822. @objattr, @iostatus,
  823. FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
  824. FILE_SYNCHRONOUS_IO_NONALERT);
  825. FreeNtStr(ntstr);
  826. if NT_SUCCESS(res) then begin
  827. res := NtQueryInformationFile(h, @iostatus, @basic,
  828. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  829. if NT_SUCCESS(res) then begin
  830. basic.FileAttributes := Attr;
  831. Result := NtSetInformationFile(h, @iostatus, @basic,
  832. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  833. end;
  834. NtClose(h);
  835. end else
  836. Result := res;
  837. end;
  838. function DeleteFile(const FileName: UnicodeString): Boolean;
  839. var
  840. h: THandle;
  841. objattr: OBJECT_ATTRIBUTES;
  842. ntstr: UNICODE_STRING;
  843. dispinfo: FILE_DISPOSITION_INFORMATION;
  844. res: NTSTATUS;
  845. iostatus: IO_STATUS_BLOCK;
  846. begin
  847. UnicodeStrToNtStr(Filename, ntstr);
  848. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  849. res := NtOpenFile(@h, NT_DELETE, @objattr, @iostatus,
  850. FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
  851. FILE_NON_DIRECTORY_FILE);
  852. FreeNtStr(ntstr);
  853. if NT_SUCCESS(res) then begin
  854. dispinfo.DeleteFile := True;
  855. res := NtSetInformationFile(h, @iostatus, @dispinfo,
  856. SizeOf(FILE_DISPOSITION_INFORMATION), FileDispositionInformation);
  857. Result := NT_SUCCESS(res);
  858. NtClose(h);
  859. end else
  860. Result := False;
  861. end;
  862. function RenameFile(const OldName, NewName: UnicodeString): Boolean;
  863. var
  864. h: THandle;
  865. objattr: OBJECT_ATTRIBUTES;
  866. iostatus: IO_STATUS_BLOCK;
  867. dest, src: UNICODE_STRING;
  868. renameinfo: PFILE_RENAME_INFORMATION;
  869. res: LongInt;
  870. begin
  871. { check whether the destination exists first }
  872. UnicodeStrToNtStr(NewName, dest);
  873. InitializeObjectAttributes(objattr, @dest, 0, 0, Nil);
  874. res := NtCreateFile(@h, 0, @objattr, @iostatus, Nil, 0,
  875. FILE_SHARE_READ or FILE_SHARE_WRITE, FILE_OPEN,
  876. FILE_NON_DIRECTORY_FILE, Nil, 0);
  877. if NT_SUCCESS(res) then begin
  878. { destination already exists => error }
  879. NtClose(h);
  880. Result := False;
  881. end else begin
  882. UnicodeStrToNtStr(OldName, src);
  883. InitializeObjectAttributes(objattr, @src, 0, 0, Nil);
  884. res := NtCreateFile(@h,
  885. GENERIC_ALL or NT_SYNCHRONIZE or FILE_READ_ATTRIBUTES,
  886. @objattr, @iostatus, Nil, 0, FILE_SHARE_READ or FILE_SHARE_WRITE,
  887. FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT or FILE_OPEN_REMOTE_INSTANCE
  888. or FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, Nil,
  889. 0);
  890. if NT_SUCCESS(res) then begin
  891. renameinfo := GetMem(SizeOf(FILE_RENAME_INFORMATION) + dest.Length);
  892. with renameinfo^ do begin
  893. ReplaceIfExists := False;
  894. RootDirectory := 0;
  895. FileNameLength := dest.Length;
  896. Move(dest.Buffer^, renameinfo^.FileName, dest.Length);
  897. end;
  898. res := NtSetInformationFile(h, @iostatus, renameinfo,
  899. SizeOf(FILE_RENAME_INFORMATION) + dest.Length,
  900. FileRenameInformation);
  901. if not NT_SUCCESS(res) then begin
  902. { this could happen if src and destination reside on different drives,
  903. so we need to copy the file manually }
  904. {$message warning 'RenameFile: Implement file copy!'}
  905. Result := False;
  906. end else
  907. Result := True;
  908. NtClose(h);
  909. end else
  910. Result := False;
  911. FreeNtStr(src);
  912. end;
  913. FreeNtStr(dest);
  914. end;
  915. {****************************************************************************
  916. Disk Functions
  917. ****************************************************************************}
  918. function diskfree(drive: byte): int64;
  919. begin
  920. { here the mount manager needs to be queried }
  921. Result := -1;
  922. end;
  923. function disksize(drive: byte): int64;
  924. begin
  925. { here the mount manager needs to be queried }
  926. Result := -1;
  927. end;
  928. {****************************************************************************
  929. Time Functions
  930. ****************************************************************************}
  931. procedure GetLocalTime(var SystemTime: TSystemTime);
  932. var
  933. bias, syst: LARGE_INTEGER;
  934. fields: TIME_FIELDS;
  935. userdata: PKUSER_SHARED_DATA;
  936. begin
  937. // get UTC time
  938. userdata := SharedUserData;
  939. repeat
  940. syst.u.HighPart := userdata^.SystemTime.High1Time;
  941. syst.u.LowPart := userdata^.SystemTime.LowPart;
  942. until syst.u.HighPart = userdata^.SystemTime.High2Time;
  943. // adjust to local time
  944. repeat
  945. bias.u.HighPart := userdata^.TimeZoneBias.High1Time;
  946. bias.u.LowPart := userdata^.TimeZoneBias.LowPart;
  947. until bias.u.HighPart = userdata^.TimeZoneBias.High2Time;
  948. syst.QuadPart := syst.QuadPart - bias.QuadPart;
  949. RtlTimeToTimeFields(@syst, @fields);
  950. SystemTime.Year := fields.Year;
  951. SystemTime.Month := fields.Month;
  952. SystemTime.Day := fields.Day;
  953. SystemTime.Hour := fields.Hour;
  954. SystemTime.Minute := fields.Minute;
  955. SystemTime.Second := fields.Second;
  956. SystemTime.Millisecond := fields.MilliSeconds;
  957. end;
  958. {****************************************************************************
  959. Misc Functions
  960. ****************************************************************************}
  961. procedure sysbeep;
  962. begin
  963. { empty }
  964. end;
  965. procedure InitInternational;
  966. begin
  967. InitInternationalGeneric;
  968. end;
  969. {****************************************************************************
  970. Target Dependent
  971. ****************************************************************************}
  972. function SysErrorMessage(ErrorCode: Integer): String;
  973. begin
  974. Result := 'NT error code: 0x' + IntToHex(ErrorCode, 8);
  975. end;
  976. {****************************************************************************
  977. Initialization code
  978. ****************************************************************************}
  979. function wstrlen(p: PWideChar): SizeInt; external name 'FPC_PWIDECHAR_LENGTH';
  980. function GetEnvironmentVariable(const EnvVar: String): String;
  981. var
  982. s, upperenvvar : UTF8String;
  983. i : longint;
  984. hp: pwidechar;
  985. len: sizeint;
  986. begin
  987. { TODO : test once I know how to execute processes }
  988. Result:='';
  989. hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
  990. { first convert to UTF-8, then uppercase in order to avoid potential data
  991. loss }
  992. upperenvvar:=EnvVar;
  993. upperenvvar:=UpperCase(upperenvvar);
  994. while hp^<>#0 do
  995. begin
  996. len:=UnicodeToUTF8(Nil, hp, 0);
  997. SetLength(s,len);
  998. UnicodeToUTF8(PChar(s), hp, len);
  999. i:=pos('=',s);
  1000. if uppercase(copy(s,1,i-1))=upperenvvar then
  1001. begin
  1002. { copy() returns a rawbytestring -> will keep UTF-8 encoding }
  1003. Result:=copy(s,i+1,length(s)-i);
  1004. break;
  1005. end;
  1006. { next string entry}
  1007. hp:=hp+wstrlen(hp)+1;
  1008. end;
  1009. end;
  1010. function GetEnvironmentVariableCount: Integer;
  1011. var
  1012. hp : pwidechar;
  1013. begin
  1014. Result:=0;
  1015. hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
  1016. If (Hp<>Nil) then
  1017. while hp^<>#0 do
  1018. begin
  1019. Inc(Result);
  1020. hp:=hp+wstrlen(hp)+1;
  1021. end;
  1022. end;
  1023. function GetEnvironmentString(Index: Integer): {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  1024. var
  1025. hp : pwidechar;
  1026. len: sizeint;
  1027. begin
  1028. Result:='';
  1029. hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
  1030. If (Hp<>Nil) then
  1031. begin
  1032. while (hp^<>#0) and (Index>1) do
  1033. begin
  1034. Dec(Index);
  1035. hp:=hp+wstrlen(hp)+1;
  1036. end;
  1037. If (hp^<>#0) then
  1038. begin
  1039. {$ifdef FPC_RTL_UNICODE}
  1040. Result:=hp;
  1041. {$else}
  1042. len:=UnicodeToUTF8(Nil, hp, 0);
  1043. SetLength(Result, len);
  1044. UnicodeToUTF8(PChar(Result), hp, len);
  1045. SetCodePage(RawByteString(Result),CP_UTF8,false);
  1046. {$endif}
  1047. end;
  1048. end;
  1049. end;
  1050. function ExecuteProcess(const Path: RawByteString; const ComLine: RawByteString;
  1051. Flags: TExecuteFlags = []): Integer;
  1052. begin
  1053. { TODO : implement }
  1054. Result := 0;
  1055. end;
  1056. function ExecuteProcess(const Path: RawByteString;
  1057. const ComLine: Array of RawByteString; Flags:TExecuteFlags = []): Integer;
  1058. var
  1059. CommandLine: RawByteString;
  1060. I: integer;
  1061. begin
  1062. Commandline := '';
  1063. for I := 0 to High (ComLine) do
  1064. if Pos (' ', ComLine [I]) <> 0 then
  1065. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  1066. else
  1067. CommandLine := CommandLine + ' ' + Comline [I];
  1068. ExecuteProcess := ExecuteProcess (Path, CommandLine,Flags);
  1069. end;
  1070. function ExecuteProcess(const Path: UnicodeString; const ComLine: UnicodeString;
  1071. Flags: TExecuteFlags = []): Integer;
  1072. begin
  1073. { TODO : implement }
  1074. Result := 0;
  1075. end;
  1076. function ExecuteProcess(const Path: UnicodeString;
  1077. const ComLine: Array of UnicodeString; Flags:TExecuteFlags = []): Integer;
  1078. var
  1079. CommandLine: UnicodeString;
  1080. I: integer;
  1081. begin
  1082. Commandline := '';
  1083. for I := 0 to High (ComLine) do
  1084. if Pos (' ', ComLine [I]) <> 0 then
  1085. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  1086. else
  1087. CommandLine := CommandLine + ' ' + Comline [I];
  1088. ExecuteProcess := ExecuteProcess (Path, CommandLine,Flags);
  1089. end;
  1090. procedure Sleep(Milliseconds: Cardinal);
  1091. const
  1092. DelayFactor = 10000;
  1093. var
  1094. interval: LARGE_INTEGER;
  1095. begin
  1096. interval.QuadPart := - Milliseconds * DelayFactor;
  1097. NtDelayExecution(False, @interval);
  1098. end;
  1099. {****************************************************************************
  1100. Initialization code
  1101. ****************************************************************************}
  1102. initialization
  1103. InitExceptions; { Initialize exceptions. OS independent }
  1104. InitInternational; { Initialize internationalization settings }
  1105. OnBeep := @SysBeep;
  1106. finalization
  1107. DoneExceptions;
  1108. end.