sysutils.pp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  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): Int64;
  268. begin
  269. { TODO }
  270. Result := -1;
  271. end;
  272. function FileGetSymLinkTarget(const FileName: UnicodeString; out SymLinkRec: TUnicodeSymLinkRec): Boolean;
  273. begin
  274. Result := False;
  275. end;
  276. function FileExists(const FileName: UnicodeString; FollowLink : Boolean): Boolean;
  277. var
  278. ntstr: UNICODE_STRING;
  279. objattr: OBJECT_ATTRIBUTES;
  280. res: NTSTATUS;
  281. iostatus: IO_STATUS_BLOCK;
  282. h: THandle;
  283. begin
  284. UnicodeStrToNtStr(FileName, ntstr);
  285. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  286. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  287. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  288. FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  289. Result := NT_SUCCESS(res);
  290. if Result then
  291. NtClose(h);
  292. FreeNtStr(ntstr);
  293. end;
  294. function DirectoryExists(const Directory : UnicodeString; FollowLink : Boolean) : Boolean;
  295. var
  296. ntstr: UNICODE_STRING;
  297. objattr: OBJECT_ATTRIBUTES;
  298. res: NTSTATUS;
  299. iostatus: IO_STATUS_BLOCK;
  300. h: THandle;
  301. begin
  302. UnicodeStrToNtStr(Directory, ntstr);
  303. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  304. { first test wether this is a object directory }
  305. res := NtOpenDirectoryObject(@h, DIRECTORY_QUERY, @objattr);
  306. if NT_SUCCESS(res) then
  307. Result := True
  308. else begin
  309. if res = STATUS_OBJECT_TYPE_MISMATCH then begin
  310. { this is a file object! }
  311. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  312. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  313. FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  314. Result := NT_SUCCESS(res);
  315. end else
  316. Result := False;
  317. end;
  318. if Result then
  319. NtClose(h);
  320. FreeNtStr(ntstr);
  321. end;
  322. { copied from rtl/unix/sysutils.pp and adapted to UTF-16 }
  323. Function FNMatch(const Pattern,Name:UnicodeString):Boolean;
  324. Var
  325. LenPat,LenName : longint;
  326. function NameUtf16CodePointLen(index: longint): longint;
  327. begin
  328. { see https://en.wikipedia.org/wiki/UTF-16#Description for details }
  329. Result:=1;
  330. { valid surrogate pair? }
  331. if (Name[index]>=#$D800) and
  332. (Name[index]<=#$DBFF) then
  333. begin
  334. if (index+1<=LenName) and
  335. (Name[index+1]>=#$DC00) and
  336. (Name[index+1]<=#$DFFF) then
  337. inc(Result)
  338. else
  339. exit;
  340. end;
  341. { combining diacritics?
  342. 1) U+0300 - U+036F
  343. 2) U+1DC0 - U+1DFF
  344. 3) U+20D0 - U+20FF
  345. 4) U+FE20 - U+FE2F
  346. }
  347. while (index+Result+1<=LenName) and
  348. ((word(ord(Name[index+Result+1])-$0300) <= word($036F-$0300)) or
  349. (word(ord(Name[index+Result+1])-$1DC0) <= word($1DFF-$1DC0)) or
  350. (word(ord(Name[index+Result+1])-$20D0) <= word($20FF-$20D0)) or
  351. (word(ord(Name[index+Result+1])-$FE20) <= word($FE2F-$FE20))) do
  352. begin
  353. inc(Result)
  354. end;
  355. end;
  356. procedure GoToLastByteOfUtf16CodePoint(var j: longint);
  357. begin
  358. { Take one less, because we have to stop at the last word of the sequence.
  359. }
  360. inc(j,NameUtf16CodePointLen(j)-1);
  361. end;
  362. { input:
  363. i: current position in pattern (start of utf-16 code point)
  364. j: current position in name (start of utf-16 code point)
  365. update_i_j: should i and j be changed by the routine or not
  366. output:
  367. i: if update_i_j, then position of last matching part of code point in
  368. pattern, or first non-matching code point in pattern. Otherwise the
  369. same value as on input.
  370. j: if update_i_j, then position of last matching part of code point in
  371. name, or first non-matching code point in name. Otherwise the
  372. same value as on input.
  373. result: true if match, false if no match
  374. }
  375. function CompareUtf16CodePoint(var i,j: longint; update_i_j: boolean): Boolean;
  376. var
  377. words,
  378. new_i,
  379. new_j: longint;
  380. begin
  381. words:=NameUtf16CodePointLen(j);
  382. new_i:=i;
  383. new_j:=j;
  384. { ensure that a part of an UTF-8 codepoint isn't interpreted
  385. as '*' or '?' }
  386. repeat
  387. dec(words);
  388. Result:=
  389. (new_j<=LenName) and
  390. (new_i<=LenPat) and
  391. (Pattern[new_i]=Name[new_j]);
  392. inc(new_i);
  393. inc(new_j);
  394. until not(Result) or
  395. (words=0);
  396. if update_i_j then
  397. begin
  398. i:=new_i;
  399. j:=new_j;
  400. end;
  401. end;
  402. Function DoFNMatch(i,j:longint):Boolean;
  403. Var
  404. Found : boolean;
  405. Begin
  406. Found:=true;
  407. While Found and (i<=LenPat) Do
  408. Begin
  409. Case Pattern[i] of
  410. '?' :
  411. begin
  412. Found:=(j<=LenName);
  413. GoToLastByteOfUtf16CodePoint(j);
  414. end;
  415. '*' : Begin
  416. {find the next character in pattern, different of ? and *}
  417. while Found do
  418. begin
  419. inc(i);
  420. if i>LenPat then
  421. Break;
  422. case Pattern[i] of
  423. '*' : ;
  424. '?' : begin
  425. if j>LenName then
  426. begin
  427. DoFNMatch:=false;
  428. Exit;
  429. end;
  430. GoToLastByteOfUtf16CodePoint(j);
  431. inc(j);
  432. end;
  433. else
  434. Found:=false;
  435. end;
  436. end;
  437. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  438. { Now, find in name the character which i points to, if the * or
  439. ? wasn't the last character in the pattern, else, use up all
  440. the chars in name }
  441. Found:=false;
  442. if (i<=LenPat) then
  443. begin
  444. repeat
  445. {find a letter (not only first !) which maches pattern[i]}
  446. while (j<=LenName) and
  447. ((name[j]<>pattern[i]) or
  448. not CompareUtf16CodePoint(i,j,false)) do
  449. begin
  450. GoToLastByteOfUtf16CodePoint(j);
  451. inc(j);
  452. end;
  453. if (j<LenName) then
  454. begin
  455. { while positions i/j have already been checked, we have to
  456. ensure that we don't split a code point }
  457. if DoFnMatch(i,j) then
  458. begin
  459. i:=LenPat;
  460. j:=LenName;{we can stop}
  461. Found:=true;
  462. Break;
  463. end
  464. { We didn't find one, need to look further }
  465. else
  466. begin
  467. GoToLastByteOfUtf16CodePoint(j);
  468. inc(j);
  469. end;
  470. end
  471. else if j=LenName then
  472. begin
  473. Found:=true;
  474. Break;
  475. end;
  476. { This 'until' condition must be j>LenName, not j>=LenName.
  477. That's because when we 'need to look further' and
  478. j = LenName then loop must not terminate. }
  479. until (j>LenName);
  480. end
  481. else
  482. begin
  483. j:=LenName;{we can stop}
  484. Found:=true;
  485. end;
  486. end;
  487. #$D800..#$DBFF:
  488. begin
  489. { ensure that a part of an UTF-16 codepoint isn't matched with
  490. '*' or '?' }
  491. Found:=CompareUtf16CodePoint(i,j,true);
  492. { at this point, either Found is false (and we'll stop), or
  493. both pattern[i] and name[j] are the end of the current code
  494. point and equal }
  495. end
  496. else {not a wildcard character in pattern}
  497. Found:=(j<=LenName) and (pattern[i]=name[j]);
  498. end;
  499. inc(i);
  500. inc(j);
  501. end;
  502. DoFnMatch:=Found and (j>LenName);
  503. end;
  504. Begin {start FNMatch}
  505. LenPat:=Length(Pattern);
  506. LenName:=Length(Name);
  507. FNMatch:=DoFNMatch(1,1);
  508. End;
  509. function FindGetFileInfo(const s: UnicodeString; var f: TAbstractSearchRec; var Name: UnicodeString): Boolean;
  510. var
  511. ntstr: UNICODE_STRING;
  512. objattr: OBJECT_ATTRIBUTES;
  513. res: NTSTATUS;
  514. h: THandle;
  515. iostatus: IO_STATUS_BLOCK;
  516. attr: LongInt;
  517. filename: UnicodeString;
  518. isfileobj: Boolean;
  519. objinfo: OBJECT_BASIC_INFORMATION;
  520. fileinfo: FILE_BASIC_INFORMATION;
  521. time: LongInt;
  522. begin
  523. UnicodeStrToNtStr(s, ntstr);
  524. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  525. filename := ExtractFileName(s);
  526. { TODO : handle symlinks }
  527. { If Assigned(F.FindHandle) and ((((PUnixFindData(f.FindHandle)^.searchattr)) and faSymlink) > 0) then
  528. FindGetFileInfo:=(fplstat(pointer(s),st)=0)
  529. else
  530. FindGetFileInfo:=(fpstat(pointer(s),st)=0);}
  531. attr := 0;
  532. Result := False;
  533. if (faDirectory and f.FindData.SearchAttr <> 0) and
  534. ((filename = '.') or (filename = '..')) then begin
  535. attr := faDirectory;
  536. res := STATUS_SUCCESS;
  537. end else
  538. res := STATUS_INVALID_PARAMETER;
  539. isfileobj := False;
  540. if not NT_SUCCESS(res) then begin
  541. { first check whether it's a directory }
  542. res := NtOpenDirectoryObject(@h, DIRECTORY_QUERY, @objattr);
  543. if not NT_SUCCESS(res) then
  544. if res = STATUS_OBJECT_TYPE_MISMATCH then begin
  545. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  546. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  547. FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  548. isfileobj := NT_SUCCESS(res);
  549. end;
  550. if NT_SUCCESS(res) then
  551. attr := faDirectory;
  552. end;
  553. if not NT_SUCCESS(res) then begin
  554. { first try whether we have a file object }
  555. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  556. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  557. FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  558. isfileobj := NT_SUCCESS(res);
  559. if res = STATUS_OBJECT_TYPE_MISMATCH then begin
  560. { is this an object? }
  561. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  562. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  563. FILE_SYNCHRONOUS_IO_NONALERT);
  564. if (res = STATUS_OBJECT_TYPE_MISMATCH)
  565. and (f.FindData.SearchAttr and faSysFile <> 0) then begin
  566. { this is some other system file like an event or port, so we can only
  567. provide it's name }
  568. res := STATUS_SUCCESS;
  569. attr := faSysFile;
  570. end;
  571. end;
  572. end;
  573. FreeNtStr(ntstr);
  574. if not NT_SUCCESS(res) then
  575. Exit;
  576. time := 0;
  577. if isfileobj then begin
  578. res := NtQueryInformationFile(h, @iostatus, @fileinfo, SizeOf(fileinfo),
  579. FileBasicInformation);
  580. if NT_SUCCESS(res) then begin
  581. time := NtToDosTime(fileinfo.LastWriteTime);
  582. { copy file attributes? }
  583. end;
  584. end else begin
  585. res := NtQueryObject(h, ObjectBasicInformation, @objinfo, SizeOf(objinfo),
  586. Nil);
  587. if NT_SUCCESS(res) then begin
  588. time := NtToDosTime(objinfo.CreateTime);
  589. { what about attributes? }
  590. end;
  591. end;
  592. if (attr and not f.FindData.SearchAttr) = 0 then begin
  593. Name := filename;
  594. f.Attr := attr;
  595. f.Size := 0;
  596. {$ifndef FPUNONE}
  597. if time = 0 then
  598. { for now we use "Now" as a fall back; ideally this should be the system
  599. start time }
  600. f.Time := DateTimeToFileDate(Now)
  601. else
  602. f.Time := time;
  603. {$endif}
  604. Result := True;
  605. end else
  606. Result := False;
  607. NtClose(h);
  608. end;
  609. Procedure InternalFindClose (var Handle: THandle; var FindData: TFindData);
  610. begin
  611. if FindData.Handle <> 0 then
  612. begin
  613. NtClose(FindData.Handle);
  614. FindData.Handle:=0;
  615. end;
  616. end;
  617. Function InternalFindNext (Var Rslt : TAbstractSearchRec; var Name: UnicodeString) : Longint;
  618. {
  619. re-opens dir if not already in array and calls FindGetFileInfo
  620. }
  621. Var
  622. DirName : UnicodeString;
  623. FName,
  624. SName : UnicodeString;
  625. Found,
  626. Finished : boolean;
  627. ntstr: UNICODE_STRING;
  628. objattr: OBJECT_ATTRIBUTES;
  629. buf: array of WideChar;
  630. len: LongWord;
  631. res: NTSTATUS;
  632. i: LongInt;
  633. dirinfo: POBJECT_DIRECTORY_INFORMATION;
  634. filedirinfo: PFILE_DIRECTORY_INFORMATION;
  635. pc: PChar;
  636. filename: UnicodeString;
  637. iostatus: IO_STATUS_BLOCK;
  638. begin
  639. { TODO : relative directories }
  640. Result := -1;
  641. { SearchSpec='' means that there were no wild cards, so only one file to
  642. find.
  643. }
  644. if Rslt.FindData.SearchSpec = '' then
  645. Exit;
  646. { relative directories not supported for now }
  647. if Rslt.FindData.NamePos = 0 then
  648. Exit;
  649. if Rslt.FindData.Handle = 0 then begin
  650. if Rslt.FindData.NamePos > 1 then
  651. filename := Copy(Rslt.FindData.SearchSpec, 1, Rslt.FindData.NamePos - 1)
  652. else
  653. if Rslt.FindData.NamePos = 1 then
  654. filename := Copy(Rslt.FindData.SearchSpec, 1, 1)
  655. else
  656. filename := Rslt.FindData.SearchSpec;
  657. UnicodeStrToNtStr(filename, ntstr);
  658. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  659. res := NtOpenDirectoryObject(@Rslt.FindData.Handle,
  660. DIRECTORY_QUERY or DIRECTORY_TRAVERSE, @objattr);
  661. if not NT_SUCCESS(res) then begin
  662. if res = STATUS_OBJECT_TYPE_MISMATCH then
  663. res := NtOpenFile(@Rslt.FindData.Handle,
  664. FILE_LIST_DIRECTORY or NT_SYNCHRONIZE, @objattr,
  665. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  666. FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  667. end else
  668. Rslt.FindData.IsDirObj := True;
  669. FreeNTStr(ntstr);
  670. if not NT_SUCCESS(res) then
  671. Exit;
  672. end;
  673. { if (NTFindData^.SearchType = 0) and
  674. (NTFindData^.Dirptr = Nil) then
  675. begin
  676. If NTFindData^.NamePos = 0 Then
  677. DirName:='./'
  678. Else
  679. DirName:=Copy(NTFindData^.SearchSpec,1,NTFindData^.NamePos);
  680. NTFindData^.DirPtr := fpopendir(Pchar(pointer(DirName)));
  681. end;}
  682. SName := Copy(Rslt.FindData.SearchSpec, Rslt.FindData.NamePos + 1,
  683. Length(Rslt.FindData.SearchSpec));
  684. Found := False;
  685. Finished := not NT_SUCCESS(Rslt.FindData.LastRes)
  686. or (Rslt.FindData.LastRes = STATUS_NO_MORE_ENTRIES);
  687. SetLength(buf, 200);
  688. dirinfo := @buf[0];
  689. filedirinfo := @buf[0];
  690. while not Finished do begin
  691. if Rslt.FindData.IsDirObj then
  692. res := NtQueryDirectoryObject(Rslt.FindData.Handle, @buf[0],
  693. Length(buf) * SizeOf(buf[0]), True, False,
  694. @Rslt.FindData.Context, @len)
  695. else
  696. res := NtQueryDirectoryFile(Rslt.FindData.Handle, 0, Nil, Nil, @iostatus,
  697. @buf[0], Length(buf) * SizeOf(buf[0]), FileDirectoryInformation,
  698. True, Nil, False);
  699. if Rslt.FindData.IsDirObj then begin
  700. Finished := (res = STATUS_NO_MORE_ENTRIES)
  701. or (res = STATUS_NO_MORE_FILES)
  702. or not NT_SUCCESS(res);
  703. Rslt.FindData.LastRes := res;
  704. if dirinfo^.Name.Length > 0 then begin
  705. SetLength(FName, dirinfo^.Name.Length div 2);
  706. move(dirinfo^.Name.Buffer[0],FName[1],dirinfo^.Name.Length);
  707. {$ifdef debug_findnext}
  708. Write(FName, ' (');
  709. for i := 0 to dirinfo^.TypeName.Length div 2 - 1 do
  710. if dirinfo^.TypeName.Buffer[i] < #256 then
  711. Write(AnsiChar(Byte(dirinfo^.TypeName.Buffer[i])))
  712. else
  713. Write('?');
  714. Writeln(')');
  715. {$endif debug_findnext}
  716. end else
  717. FName := '';
  718. end else begin
  719. SetLength(FName, filedirinfo^.FileNameLength div 2);
  720. move(filedirinfo^.FileName[0],FName[1],filedirinfo^.FileNameLength);
  721. end;
  722. if FName = '' then
  723. Finished := True
  724. else begin
  725. if FNMatch(SName, FName) then begin
  726. Found := FindGetFileInfo(Copy(Rslt.FindData.SearchSpec, 1,
  727. Rslt.FindData.NamePos) + FName, Rslt, Name);
  728. if Found then begin
  729. Result := 0;
  730. Exit;
  731. end;
  732. end;
  733. end;
  734. end;
  735. end;
  736. Function InternalFindFirst (Const Path : UnicodeString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name : UnicodeString) : Longint;
  737. {
  738. opens dir and calls FindNext if needed.
  739. }
  740. Begin
  741. Result := -1;
  742. if Path = '' then
  743. Exit;
  744. Rslt.FindData.SearchAttr := Attr;
  745. {Wildcards?}
  746. if (Pos('?', Path) = 0) and (Pos('*', Path) = 0) then begin
  747. if FindGetFileInfo(Path, Rslt, Name) then
  748. Result := 0;
  749. end else begin
  750. {Create Info}
  751. Rslt.FindData.SearchSpec := Path;
  752. Rslt.FindData.NamePos := Length(Rslt.FindData.SearchSpec);
  753. while (Rslt.FindData.NamePos > 0)
  754. and (Rslt.FindData.SearchSpec[Rslt.FindData.NamePos] <> DirectorySeparator)
  755. do
  756. Dec(Rslt.FindData.NamePos);
  757. Result := InternalFindNext(Rslt,Name);
  758. end;
  759. if Result <> 0 then
  760. InternalFindClose(Rslt.FindHandle,Rslt.FindData);
  761. end;
  762. function FileGetDate(Handle: THandle): Longint;
  763. var
  764. res: NTSTATUS;
  765. basic: FILE_BASIC_INFORMATION;
  766. iostatus: IO_STATUS_BLOCK;
  767. begin
  768. res := NtQueryInformationFile(Handle, @iostatus, @basic,
  769. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  770. if NT_SUCCESS(res) then
  771. Result := NtToDosTime(basic.LastWriteTime)
  772. else
  773. Result := -1;
  774. end;
  775. function FileSetDate(Handle: THandle;Age: Int64): Longint;
  776. var
  777. res: NTSTATUS;
  778. basic: FILE_BASIC_INFORMATION;
  779. iostatus: IO_STATUS_BLOCK;
  780. begin
  781. res := NtQueryInformationFile(Handle, @iostatus, @basic,
  782. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  783. if NT_SUCCESS(res) then begin
  784. if not DosToNtTime(Age, basic.LastWriteTime) then begin
  785. Result := -1;
  786. Exit;
  787. end;
  788. res := NtSetInformationFile(Handle, @iostatus, @basic,
  789. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  790. if NT_SUCCESS(res) then
  791. Result := 0
  792. else
  793. Result := res;
  794. end else
  795. Result := res;
  796. end;
  797. function FileGetAttr(const FileName: UnicodeString): Longint;
  798. var
  799. objattr: OBJECT_ATTRIBUTES;
  800. info: FILE_NETWORK_OPEN_INFORMATION;
  801. res: NTSTATUS;
  802. ntstr: UNICODE_STRING;
  803. begin
  804. UnicodeStrToNtStr(FileName, ntstr);
  805. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  806. res := NtQueryFullAttributesFile(@objattr, @info);
  807. if NT_SUCCESS(res) then
  808. Result := info.FileAttributes
  809. else
  810. Result := 0;
  811. FreeNtStr(ntstr);
  812. end;
  813. function FileSetAttr(const Filename: UnicodeString; Attr: LongInt): Longint;
  814. var
  815. h: THandle;
  816. objattr: OBJECT_ATTRIBUTES;
  817. ntstr: UNICODE_STRING;
  818. basic: FILE_BASIC_INFORMATION;
  819. res: NTSTATUS;
  820. iostatus: IO_STATUS_BLOCK;
  821. begin
  822. UnicodeStrToNtStr(Filename, ntstr);
  823. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  824. res := NtOpenFile(@h,
  825. NT_SYNCHRONIZE or FILE_READ_ATTRIBUTES or FILE_WRITE_ATTRIBUTES,
  826. @objattr, @iostatus,
  827. FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
  828. FILE_SYNCHRONOUS_IO_NONALERT);
  829. FreeNtStr(ntstr);
  830. if NT_SUCCESS(res) then begin
  831. res := NtQueryInformationFile(h, @iostatus, @basic,
  832. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  833. if NT_SUCCESS(res) then begin
  834. basic.FileAttributes := Attr;
  835. Result := NtSetInformationFile(h, @iostatus, @basic,
  836. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  837. end;
  838. NtClose(h);
  839. end else
  840. Result := res;
  841. end;
  842. function DeleteFile(const FileName: UnicodeString): Boolean;
  843. var
  844. h: THandle;
  845. objattr: OBJECT_ATTRIBUTES;
  846. ntstr: UNICODE_STRING;
  847. dispinfo: FILE_DISPOSITION_INFORMATION;
  848. res: NTSTATUS;
  849. iostatus: IO_STATUS_BLOCK;
  850. begin
  851. UnicodeStrToNtStr(Filename, ntstr);
  852. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  853. res := NtOpenFile(@h, NT_DELETE, @objattr, @iostatus,
  854. FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
  855. FILE_NON_DIRECTORY_FILE);
  856. FreeNtStr(ntstr);
  857. if NT_SUCCESS(res) then begin
  858. dispinfo.DeleteFile := True;
  859. res := NtSetInformationFile(h, @iostatus, @dispinfo,
  860. SizeOf(FILE_DISPOSITION_INFORMATION), FileDispositionInformation);
  861. Result := NT_SUCCESS(res);
  862. NtClose(h);
  863. end else
  864. Result := False;
  865. end;
  866. function RenameFile(const OldName, NewName: UnicodeString): Boolean;
  867. var
  868. h: THandle;
  869. objattr: OBJECT_ATTRIBUTES;
  870. iostatus: IO_STATUS_BLOCK;
  871. dest, src: UNICODE_STRING;
  872. renameinfo: PFILE_RENAME_INFORMATION;
  873. res: LongInt;
  874. begin
  875. { check whether the destination exists first }
  876. UnicodeStrToNtStr(NewName, dest);
  877. InitializeObjectAttributes(objattr, @dest, 0, 0, Nil);
  878. res := NtCreateFile(@h, 0, @objattr, @iostatus, Nil, 0,
  879. FILE_SHARE_READ or FILE_SHARE_WRITE, FILE_OPEN,
  880. FILE_NON_DIRECTORY_FILE, Nil, 0);
  881. if NT_SUCCESS(res) then begin
  882. { destination already exists => error }
  883. NtClose(h);
  884. Result := False;
  885. end else begin
  886. UnicodeStrToNtStr(OldName, src);
  887. InitializeObjectAttributes(objattr, @src, 0, 0, Nil);
  888. res := NtCreateFile(@h,
  889. GENERIC_ALL or NT_SYNCHRONIZE or FILE_READ_ATTRIBUTES,
  890. @objattr, @iostatus, Nil, 0, FILE_SHARE_READ or FILE_SHARE_WRITE,
  891. FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT or FILE_OPEN_REMOTE_INSTANCE
  892. or FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, Nil,
  893. 0);
  894. if NT_SUCCESS(res) then begin
  895. renameinfo := GetMem(SizeOf(FILE_RENAME_INFORMATION) + dest.Length);
  896. with renameinfo^ do begin
  897. ReplaceIfExists := False;
  898. RootDirectory := 0;
  899. FileNameLength := dest.Length;
  900. Move(dest.Buffer^, renameinfo^.FileName, dest.Length);
  901. end;
  902. res := NtSetInformationFile(h, @iostatus, renameinfo,
  903. SizeOf(FILE_RENAME_INFORMATION) + dest.Length,
  904. FileRenameInformation);
  905. if not NT_SUCCESS(res) then begin
  906. { this could happen if src and destination reside on different drives,
  907. so we need to copy the file manually }
  908. {$message warning 'RenameFile: Implement file copy!'}
  909. Result := False;
  910. end else
  911. Result := True;
  912. NtClose(h);
  913. end else
  914. Result := False;
  915. FreeNtStr(src);
  916. end;
  917. FreeNtStr(dest);
  918. end;
  919. {****************************************************************************
  920. Disk Functions
  921. ****************************************************************************}
  922. function diskfree(drive: byte): int64;
  923. begin
  924. { here the mount manager needs to be queried }
  925. Result := -1;
  926. end;
  927. function disksize(drive: byte): int64;
  928. begin
  929. { here the mount manager needs to be queried }
  930. Result := -1;
  931. end;
  932. {****************************************************************************
  933. Time Functions
  934. ****************************************************************************}
  935. procedure GetLocalTime(var SystemTime: TSystemTime);
  936. var
  937. bias, syst: LARGE_INTEGER;
  938. fields: TIME_FIELDS;
  939. userdata: PKUSER_SHARED_DATA;
  940. begin
  941. // get UTC time
  942. userdata := SharedUserData;
  943. repeat
  944. syst.u.HighPart := userdata^.SystemTime.High1Time;
  945. syst.u.LowPart := userdata^.SystemTime.LowPart;
  946. until syst.u.HighPart = userdata^.SystemTime.High2Time;
  947. // adjust to local time
  948. repeat
  949. bias.u.HighPart := userdata^.TimeZoneBias.High1Time;
  950. bias.u.LowPart := userdata^.TimeZoneBias.LowPart;
  951. until bias.u.HighPart = userdata^.TimeZoneBias.High2Time;
  952. syst.QuadPart := syst.QuadPart - bias.QuadPart;
  953. RtlTimeToTimeFields(@syst, @fields);
  954. SystemTime.Year := fields.Year;
  955. SystemTime.Month := fields.Month;
  956. SystemTime.Day := fields.Day;
  957. SystemTime.Hour := fields.Hour;
  958. SystemTime.Minute := fields.Minute;
  959. SystemTime.Second := fields.Second;
  960. SystemTime.Millisecond := fields.MilliSeconds;
  961. end;
  962. {****************************************************************************
  963. Misc Functions
  964. ****************************************************************************}
  965. procedure sysbeep;
  966. begin
  967. { empty }
  968. end;
  969. procedure InitInternational;
  970. begin
  971. InitInternationalGeneric;
  972. end;
  973. {****************************************************************************
  974. Target Dependent
  975. ****************************************************************************}
  976. function SysErrorMessage(ErrorCode: Integer): String;
  977. begin
  978. Result := 'NT error code: 0x' + IntToHex(ErrorCode, 8);
  979. end;
  980. {****************************************************************************
  981. Initialization code
  982. ****************************************************************************}
  983. function wstrlen(p: PWideChar): SizeInt; external name 'FPC_PWIDECHAR_LENGTH';
  984. function GetEnvironmentVariable(const EnvVar: String): String;
  985. var
  986. s, upperenvvar : UTF8String;
  987. i : longint;
  988. hp: pwidechar;
  989. len: sizeint;
  990. begin
  991. { TODO : test once I know how to execute processes }
  992. Result:='';
  993. hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
  994. { first convert to UTF-8, then uppercase in order to avoid potential data
  995. loss }
  996. upperenvvar:=EnvVar;
  997. upperenvvar:=UpperCase(upperenvvar);
  998. while hp^<>#0 do
  999. begin
  1000. len:=UnicodeToUTF8(Nil, hp, 0);
  1001. SetLength(s,len);
  1002. UnicodeToUTF8(PChar(s), hp, len);
  1003. i:=pos('=',s);
  1004. if uppercase(copy(s,1,i-1))=upperenvvar then
  1005. begin
  1006. { copy() returns a rawbytestring -> will keep UTF-8 encoding }
  1007. Result:=copy(s,i+1,length(s)-i);
  1008. break;
  1009. end;
  1010. { next string entry}
  1011. hp:=hp+wstrlen(hp)+1;
  1012. end;
  1013. end;
  1014. function GetEnvironmentVariableCount: Integer;
  1015. var
  1016. hp : pwidechar;
  1017. begin
  1018. Result:=0;
  1019. hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
  1020. If (Hp<>Nil) then
  1021. while hp^<>#0 do
  1022. begin
  1023. Inc(Result);
  1024. hp:=hp+wstrlen(hp)+1;
  1025. end;
  1026. end;
  1027. function GetEnvironmentString(Index: Integer): {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  1028. var
  1029. hp : pwidechar;
  1030. len: sizeint;
  1031. begin
  1032. Result:='';
  1033. hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
  1034. If (Hp<>Nil) then
  1035. begin
  1036. while (hp^<>#0) and (Index>1) do
  1037. begin
  1038. Dec(Index);
  1039. hp:=hp+wstrlen(hp)+1;
  1040. end;
  1041. If (hp^<>#0) then
  1042. begin
  1043. {$ifdef FPC_RTL_UNICODE}
  1044. Result:=hp;
  1045. {$else}
  1046. len:=UnicodeToUTF8(Nil, hp, 0);
  1047. SetLength(Result, len);
  1048. UnicodeToUTF8(PChar(Result), hp, len);
  1049. SetCodePage(RawByteString(Result),CP_UTF8,false);
  1050. {$endif}
  1051. end;
  1052. end;
  1053. end;
  1054. function ExecuteProcess(const Path: RawByteString; const ComLine: RawByteString;
  1055. Flags: TExecuteFlags = []): Integer;
  1056. begin
  1057. { TODO : implement }
  1058. Result := 0;
  1059. end;
  1060. function ExecuteProcess(const Path: RawByteString;
  1061. const ComLine: Array of RawByteString; Flags:TExecuteFlags = []): Integer;
  1062. var
  1063. CommandLine: RawByteString;
  1064. I: integer;
  1065. begin
  1066. Commandline := '';
  1067. for I := 0 to High (ComLine) do
  1068. if Pos (' ', ComLine [I]) <> 0 then
  1069. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  1070. else
  1071. CommandLine := CommandLine + ' ' + Comline [I];
  1072. ExecuteProcess := ExecuteProcess (Path, CommandLine,Flags);
  1073. end;
  1074. function ExecuteProcess(const Path: UnicodeString; const ComLine: UnicodeString;
  1075. Flags: TExecuteFlags = []): Integer;
  1076. begin
  1077. { TODO : implement }
  1078. Result := 0;
  1079. end;
  1080. function ExecuteProcess(const Path: UnicodeString;
  1081. const ComLine: Array of UnicodeString; Flags:TExecuteFlags = []): Integer;
  1082. var
  1083. CommandLine: UnicodeString;
  1084. I: integer;
  1085. begin
  1086. Commandline := '';
  1087. for I := 0 to High (ComLine) do
  1088. if Pos (' ', ComLine [I]) <> 0 then
  1089. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  1090. else
  1091. CommandLine := CommandLine + ' ' + Comline [I];
  1092. ExecuteProcess := ExecuteProcess (Path, CommandLine,Flags);
  1093. end;
  1094. procedure Sleep(Milliseconds: Cardinal);
  1095. const
  1096. DelayFactor = 10000;
  1097. var
  1098. interval: LARGE_INTEGER;
  1099. begin
  1100. interval.QuadPart := - Milliseconds * DelayFactor;
  1101. NtDelayExecution(False, @interval);
  1102. end;
  1103. {****************************************************************************
  1104. Initialization code
  1105. ****************************************************************************}
  1106. initialization
  1107. InitExceptions; { Initialize exceptions. OS independent }
  1108. InitInternational; { Initialize internationalization settings }
  1109. OnBeep := @SysBeep;
  1110. finalization
  1111. FreeTerminateProcs;
  1112. DoneExceptions;
  1113. end.