sysutils.pp 37 KB

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