sysutils.pp 37 KB

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