sysutils.pp 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. SysUtils unit for win32
  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. windows;
  22. {$DEFINE HAS_SLEEP}
  23. {$DEFINE HAS_OSERROR}
  24. {$DEFINE HAS_OSCONFIG}
  25. {$DEFINE HAS_OSUSERDIR}
  26. {$DEFINE HAS_CREATEGUID}
  27. {$DEFINE HAS_LOCALTIMEZONEOFFSET}
  28. {$DEFINE HAS_GETTICKCOUNT}
  29. {$DEFINE HAS_GETTICKCOUNT64}
  30. {$DEFINE OS_FILESETDATEBYNAME}
  31. // this target has an fileflush implementation, don't include dummy
  32. {$DEFINE SYSUTILS_HAS_FILEFLUSH_IMPL}
  33. { used OS file system APIs use unicodestring }
  34. {$define SYSUTILS_HAS_UNICODESTR_FILEUTIL_IMPL}
  35. { OS has an ansistring/single byte environment variable API }
  36. {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
  37. { OS has a unicodestring/two byte environment variable API }
  38. {$define SYSUTILS_HAS_UNICODESTR_ENVVAR_IMPL}
  39. { Include platform independent interface part }
  40. {$i sysutilh.inc}
  41. type
  42. TSystemTime = Windows.TSystemTime;
  43. EWin32Error = class(Exception)
  44. public
  45. ErrorCode : DWORD;
  46. end;
  47. Var
  48. Win32Platform : Longint;
  49. Win32MajorVersion,
  50. Win32MinorVersion,
  51. Win32BuildNumber : dword;
  52. Win32CSDVersion : ShortString; // CSD record is 128 bytes only?
  53. const
  54. MaxEraCount = 7;
  55. var
  56. EraNames: array [1..MaxEraCount] of String;
  57. EraYearOffsets: array [1..MaxEraCount] of Integer;
  58. { Compatibility with Delphi }
  59. function Win32Check(res:boolean):boolean;inline;
  60. function WinCheck(res:boolean):boolean;
  61. function CheckWin32Version(Major,Minor : Integer ): Boolean;
  62. function CheckWin32Version(Major : Integer): Boolean;
  63. Procedure RaiseLastWin32Error;
  64. function GetFileVersion(const AFileName: string): Cardinal;
  65. function GetFileVersion(const AFileName: UnicodeString): Cardinal;
  66. procedure GetFormatSettings;
  67. procedure GetLocaleFormatSettings(LCID: Integer; var FormatSettings: TFormatSettings); platform;
  68. implementation
  69. uses
  70. sysconst,
  71. windirs;
  72. function WinCheck(res:boolean):boolean;
  73. begin
  74. if not res then
  75. RaiseLastOSError;
  76. result:=res;
  77. end;
  78. function Win32Check(res:boolean):boolean;inline;
  79. begin
  80. result:=WinCheck(res);
  81. end;
  82. procedure RaiseLastWin32Error;
  83. begin
  84. RaiseLastOSError;
  85. end;
  86. function CheckWin32Version(Major : Integer): Boolean;
  87. begin
  88. Result:=CheckWin32Version(Major,0)
  89. end;
  90. function CheckWin32Version(Major,Minor: Integer): Boolean;
  91. begin
  92. Result:=(Win32MajorVersion>dword(Major)) or
  93. ((Win32MajorVersion=dword(Major)) and (Win32MinorVersion>=dword(Minor)));
  94. end;
  95. function GetFileVersion(const AFileName:string):Cardinal;
  96. var
  97. { useful only as long as we don't need to touch different stack pages }
  98. buf : array[0..3071] of byte;
  99. bufp : pointer;
  100. fn : string;
  101. valsize,
  102. size : DWORD;
  103. h : DWORD;
  104. valrec : PVSFixedFileInfo;
  105. begin
  106. result:=$fffffff;
  107. fn:=AFileName;
  108. UniqueString(fn);
  109. size:=GetFileVersionInfoSizeA(pchar(fn),@h);
  110. if size>sizeof(buf) then
  111. begin
  112. getmem(bufp,size);
  113. try
  114. if GetFileVersionInfoA(pchar(fn),h,size,bufp) then
  115. if VerQueryValue(bufp,'\',valrec,valsize) then
  116. result:=valrec^.dwFileVersionMS;
  117. finally
  118. freemem(bufp);
  119. end;
  120. end
  121. else
  122. begin
  123. if GetFileVersionInfoA(pchar(fn),h,size,@buf) then
  124. if VerQueryValue(@buf,'\',valrec,valsize) then
  125. result:=valrec^.dwFileVersionMS;
  126. end;
  127. end;
  128. function GetFileVersion(const AFileName:UnicodeString):Cardinal;
  129. var
  130. { useful only as long as we don't need to touch different stack pages }
  131. buf : array[0..3071] of byte;
  132. bufp : pointer;
  133. fn : unicodestring;
  134. valsize,
  135. size : DWORD;
  136. h : DWORD;
  137. valrec : PVSFixedFileInfo;
  138. begin
  139. result:=$fffffff;
  140. fn:=AFileName;
  141. UniqueString(fn);
  142. size:=GetFileVersionInfoSizeW(pwidechar(fn),@h);
  143. if size>sizeof(buf) then
  144. begin
  145. getmem(bufp,size);
  146. try
  147. if GetFileVersionInfoW(pwidechar(fn),h,size,bufp) then
  148. if VerQueryValue(bufp,'\',valrec,valsize) then
  149. result:=valrec^.dwFileVersionMS;
  150. finally
  151. freemem(bufp);
  152. end;
  153. end
  154. else
  155. begin
  156. if GetFileVersionInfoW(pwidechar(fn),h,size,@buf) then
  157. if VerQueryValueW(@buf,'\',valrec,valsize) then
  158. result:=valrec^.dwFileVersionMS;
  159. end;
  160. end;
  161. {$define HASCREATEGUID}
  162. {$define HASEXPANDUNCFILENAME}
  163. {$DEFINE FPC_NOGENERICANSIROUTINES}
  164. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  165. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  166. function ConvertEraYearString(Count ,Year,Month,Day : integer) : string; forward;
  167. function ConvertEraString(Count ,Year,Month,Day : integer) : string; forward;
  168. { Include platform independent implementation part }
  169. {$i sysutils.inc}
  170. function GetTempFileName(Dir,Prefix: PChar; uUnique: DWORD; TempFileName: PChar):DWORD;
  171. begin
  172. Result:= Windows.GetTempFileNameA(Dir,Prefix,uUnique,TempFileName);
  173. end;
  174. { UUID generation. }
  175. function CoCreateGuid(out guid: TGUID): HResult; stdcall; external 'ole32.dll' name 'CoCreateGuid';
  176. function SysCreateGUID(out Guid: TGUID): Integer;
  177. begin
  178. Result := Integer(CoCreateGuid(Guid));
  179. end;
  180. function ExpandUNCFileName (const filename:rawbytestring) : rawbytestring;
  181. { returns empty string on errors }
  182. var
  183. u: unicodestring;
  184. begin
  185. { prevent data loss due to unsupported characters in ansi code page }
  186. u:=ExpandUNCFileName(unicodestring(filename));
  187. widestringmanager.Unicode2AnsiMoveProc(punicodechar(u),result,DefaultRTLFileSystemCodePage,length(u));
  188. end;
  189. function ExpandUNCFileName (const filename:unicodestring) : unicodestring;
  190. { returns empty string on errors }
  191. var
  192. s : unicodestring;
  193. size : dword;
  194. rc : dword;
  195. buf : pwidechar;
  196. begin
  197. s := ExpandFileName (filename);
  198. s := s + #0;
  199. size := max_path;
  200. getmem(buf,size);
  201. try
  202. rc := WNetGetUniversalNameW (pwidechar(s), UNIVERSAL_NAME_INFO_LEVEL, buf, @size);
  203. if rc=ERROR_MORE_DATA then
  204. begin
  205. buf:=reallocmem(buf,size);
  206. rc := WNetGetUniversalNameW (pwidechar(s), UNIVERSAL_NAME_INFO_LEVEL, buf, @size);
  207. end;
  208. if rc = NO_ERROR then
  209. Result := PRemoteNameInfoW(buf)^.lpUniversalName
  210. else if rc = ERROR_NOT_CONNECTED then
  211. Result := filename
  212. else
  213. Result := '';
  214. finally
  215. freemem(buf);
  216. end;
  217. end;
  218. {****************************************************************************
  219. File Functions
  220. ****************************************************************************}
  221. const
  222. AccessMode: array[0..2] of Cardinal = (
  223. GENERIC_READ,
  224. GENERIC_WRITE,
  225. GENERIC_READ or GENERIC_WRITE or FILE_WRITE_ATTRIBUTES);
  226. ShareModes: array[0..4] of Integer = (
  227. 0,
  228. 0,
  229. FILE_SHARE_READ,
  230. FILE_SHARE_WRITE,
  231. FILE_SHARE_READ or FILE_SHARE_WRITE);
  232. function FileFlush(Handle: THandle): Boolean;
  233. begin
  234. Result:= FlushFileBuffers(Handle);
  235. end;
  236. Function FileOpen (Const FileName : unicodestring; Mode : Integer) : THandle;
  237. begin
  238. result := CreateFileW(PWideChar(FileName), dword(AccessMode[Mode and 3]),
  239. dword(ShareModes[(Mode and $F0) shr 4]), nil, OPEN_EXISTING,
  240. FILE_ATTRIBUTE_NORMAL, 0);
  241. //if fail api return feInvalidHandle (INVALIDE_HANDLE=feInvalidHandle=-1)
  242. end;
  243. Function FileCreate (Const FileName : UnicodeString) : THandle;
  244. begin
  245. FileCreate:=FileCreate(FileName, fmShareExclusive, 0);
  246. end;
  247. Function FileCreate (Const FileName : UnicodeString; Rights:longint) : THandle;
  248. begin
  249. FileCreate:=FileCreate(FileName, fmShareExclusive, Rights);
  250. end;
  251. Function FileCreate (Const FileName : UnicodeString; ShareMode : Integer; Rights : Integer) : THandle;
  252. begin
  253. Result := CreateFileW(PwideChar(FileName), GENERIC_READ or GENERIC_WRITE,
  254. dword(ShareModes[(ShareMode and $F0) shr 4]), nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  255. end;
  256. Function FileRead (Handle : THandle; out Buffer; Count : longint) : Longint;
  257. Var
  258. res : dword;
  259. begin
  260. if ReadFile(Handle, Buffer, Count, res, nil) then
  261. FileRead:=Res
  262. else
  263. FileRead:=-1;
  264. end;
  265. Function FileWrite (Handle : THandle; const Buffer; Count : Longint) : Longint;
  266. Var
  267. Res : dword;
  268. begin
  269. if WriteFile(Handle, Buffer, Count, Res, nil) then
  270. FileWrite:=Res
  271. else
  272. FileWrite:=-1;
  273. end;
  274. Function FileSeek (Handle : THandle;FOffset,Origin : Longint) : Longint;
  275. begin
  276. Result := longint(SetFilePointer(Handle, FOffset, nil, Origin));
  277. end;
  278. Function FileSeek (Handle : THandle; FOffset: Int64; Origin: Longint) : Int64;
  279. var
  280. rslt: Int64Rec;
  281. begin
  282. rslt := Int64Rec(FOffset);
  283. rslt.lo := SetFilePointer(Handle, rslt.lo, @rslt.hi, Origin);
  284. if (rslt.lo = $FFFFFFFF) and (GetLastError <> 0) then
  285. rslt.hi := $FFFFFFFF;
  286. Result := Int64(rslt);
  287. end;
  288. Procedure FileClose (Handle : THandle);
  289. begin
  290. CloseHandle(Handle);
  291. end;
  292. Function FileTruncate (Handle : THandle;Size: Int64) : boolean;
  293. begin
  294. {
  295. Result:=longint(SetFilePointer(handle,Size,nil,FILE_BEGIN))<>-1;
  296. }
  297. if FileSeek (Handle, Size, FILE_BEGIN) = Size then
  298. Result:=SetEndOfFile(handle)
  299. else
  300. Result := false;
  301. end;
  302. Function DosToWinTime (DTime:longint;Var Wtime : TFileTime):longbool;
  303. var
  304. lft : TFileTime;
  305. begin
  306. DosToWinTime:=DosDateTimeToFileTime(longrec(dtime).hi,longrec(dtime).lo,@lft) and
  307. LocalFileTimeToFileTime(lft,Wtime);
  308. end;
  309. Function WinToDosTime (Var Wtime : TFileTime;var DTime:longint):longbool;
  310. var
  311. lft : TFileTime;
  312. begin
  313. WinToDosTime:=FileTimeToLocalFileTime(WTime,lft) and
  314. FileTimeToDosDateTime(lft,Longrec(Dtime).Hi,LongRec(DTIME).lo);
  315. end;
  316. Function FileAge (Const FileName : UnicodeString): Longint;
  317. var
  318. Handle: THandle;
  319. FindData: TWin32FindDataW;
  320. begin
  321. Handle := FindFirstFileW(Pwidechar(FileName), FindData);
  322. if Handle <> INVALID_HANDLE_VALUE then
  323. begin
  324. Windows.FindClose(Handle);
  325. if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
  326. If WinToDosTime(FindData.ftLastWriteTime,Result) then
  327. exit;
  328. end;
  329. Result := -1;
  330. end;
  331. function FileGetSymLinkTarget(const FileName: UnicodeString; out SymLinkRec: TUnicodeSymLinkRec): Boolean;
  332. { reparse point specific declarations from Windows headers }
  333. const
  334. IO_REPARSE_TAG_MOUNT_POINT = $A0000003;
  335. IO_REPARSE_TAG_SYMLINK = $A000000C;
  336. ERROR_REPARSE_TAG_INVALID = 4393;
  337. FSCTL_GET_REPARSE_POINT = $900A8;
  338. MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;
  339. SYMLINK_FLAG_RELATIVE = 1;
  340. FILE_FLAG_OPEN_REPARSE_POINT = $200000;
  341. FILE_READ_EA = $8;
  342. type
  343. TReparseDataBuffer = record
  344. ReparseTag: ULONG;
  345. ReparseDataLength: Word;
  346. Reserved: Word;
  347. SubstituteNameOffset: Word;
  348. SubstituteNameLength: Word;
  349. PrintNameOffset: Word;
  350. PrintNameLength: Word;
  351. case ULONG of
  352. IO_REPARSE_TAG_MOUNT_POINT: (
  353. PathBufferMount: array[0..4095] of WCHAR);
  354. IO_REPARSE_TAG_SYMLINK: (
  355. Flags: ULONG;
  356. PathBufferSym: array[0..4095] of WCHAR);
  357. end;
  358. const
  359. CShareAny = FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE;
  360. COpenReparse = FILE_FLAG_OPEN_REPARSE_POINT or FILE_FLAG_BACKUP_SEMANTICS;
  361. var
  362. HFile, Handle: THandle;
  363. PBuffer: ^TReparseDataBuffer;
  364. BytesReturned: DWORD;
  365. begin
  366. SymLinkRec := Default(TUnicodeSymLinkRec);
  367. HFile := CreateFileW(PUnicodeChar(FileName), FILE_READ_EA, CShareAny, Nil, OPEN_EXISTING, COpenReparse, 0);
  368. if HFile <> INVALID_HANDLE_VALUE then
  369. try
  370. GetMem(PBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  371. try
  372. if DeviceIoControl(HFile, FSCTL_GET_REPARSE_POINT, Nil, 0,
  373. PBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, @BytesReturned, Nil) then begin
  374. case PBuffer^.ReparseTag of
  375. IO_REPARSE_TAG_MOUNT_POINT: begin
  376. SymLinkRec.TargetName := WideCharLenToString(
  377. @PBuffer^.PathBufferMount[4 { skip start '\??\' } +
  378. PBuffer^.SubstituteNameOffset div SizeOf(WCHAR)],
  379. PBuffer^.SubstituteNameLength div SizeOf(WCHAR) - 4);
  380. end;
  381. IO_REPARSE_TAG_SYMLINK: begin
  382. SymLinkRec.TargetName := WideCharLenToString(
  383. @PBuffer^.PathBufferSym[PBuffer^.PrintNameOffset div SizeOf(WCHAR)],
  384. PBuffer^.PrintNameOffset div SizeOf(WCHAR));
  385. if (PBuffer^.Flags and SYMLINK_FLAG_RELATIVE) <> 0 then
  386. SymLinkRec.TargetName := ExpandFileName(ExtractFilePath(FileName) + SymLinkRec.TargetName);
  387. end;
  388. end;
  389. Handle := FindFirstFileExW(PUnicodeChar(FileName), FindExInfoBasic, @SymLinkRec.FindData,
  390. FindExSearchNameMatch, Nil, 0);
  391. if Handle <> INVALID_HANDLE_VALUE then begin
  392. Windows.FindClose(Handle);
  393. SymLinkRec.Attr := SymLinkRec.FindData.dwFileAttributes;
  394. SymLinkRec.Size := QWord(SymLinkRec.FindData.nFileSizeHigh) shl 32 + QWord(SymLinkRec.FindData.nFileSizeLow);
  395. end else
  396. SymLinkRec.TargetName := '';
  397. end else
  398. SetLastError(ERROR_REPARSE_TAG_INVALID);
  399. finally
  400. FreeMem(PBuffer);
  401. end;
  402. finally
  403. CloseHandle(HFile);
  404. end;
  405. Result := SymLinkRec.TargetName <> '';
  406. end;
  407. function FileOrDirExists(const FileOrDirName: UnicodeString; CheckDir: Boolean; FollowLink: Boolean): Boolean;
  408. const
  409. CDirAttributes: array[Boolean] of DWORD = (0, FILE_ATTRIBUTE_DIRECTORY);
  410. function FoundByEnum: Boolean;
  411. var
  412. FindData: TWin32FindDataW;
  413. Handle: THandle;
  414. begin
  415. { FindFirstFileEx is faster than FindFirstFile }
  416. Handle := FindFirstFileExW(PUnicodeChar(FileOrDirName), FindExInfoBasic, @FindData,
  417. FindExSearchNameMatch, Nil, 0);
  418. Result := Handle <> INVALID_HANDLE_VALUE;
  419. if Result then begin
  420. Windows.FindClose(Handle);
  421. Result := (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = CDirAttributes[CheckDir];
  422. end;
  423. end;
  424. function LinkFileExists: Boolean;
  425. var
  426. LinkTargetName: UnicodeString;
  427. begin
  428. Result := FileGetSymLinkTarget(FileOrDirName, LinkTargetName) and
  429. FileOrDirExists(LinkTargetName, CheckDir, False);
  430. end;
  431. const
  432. CNotExistsErrors = [
  433. ERROR_FILE_NOT_FOUND,
  434. ERROR_PATH_NOT_FOUND,
  435. ERROR_INVALID_NAME, // protects from names in the form of masks like '*'
  436. ERROR_INVALID_DRIVE,
  437. ERROR_NOT_READY,
  438. ERROR_INVALID_PARAMETER,
  439. ERROR_BAD_PATHNAME,
  440. ERROR_BAD_NETPATH,
  441. ERROR_BAD_NET_NAME
  442. ];
  443. var
  444. Attr : DWord;
  445. begin
  446. Attr := GetFileAttributesW(PUnicodeChar(FileOrDirName));
  447. if Attr = INVALID_FILE_ATTRIBUTES then
  448. Result := not (GetLastError in CNotExistsErrors) and FoundByEnum
  449. else begin
  450. Result := (Attr and FILE_ATTRIBUTE_DIRECTORY) = CDirAttributes[CheckDir];
  451. if Result and FollowLink and ((Attr and FILE_ATTRIBUTE_REPARSE_POINT) <> 0) then
  452. Result := LinkFileExists;
  453. end;
  454. end;
  455. Function FileExists (Const FileName : UnicodeString; FollowLink : Boolean) : Boolean;
  456. begin
  457. Result := FileOrDirExists(FileName, False, FollowLink);
  458. end;
  459. Function DirectoryExists (Const Directory : UnicodeString; FollowLink : Boolean) : Boolean;
  460. begin
  461. Result := FileOrDirExists(Directory, True, FollowLink);
  462. end;
  463. Function FindMatch(var f: TAbstractSearchRec; var Name: UnicodeString) : Longint;
  464. begin
  465. { Find file with correct attribute }
  466. While (F.FindData.dwFileAttributes and cardinal(F.ExcludeAttr))<>0 do
  467. begin
  468. if not FindNextFileW (F.FindHandle,F.FindData) then
  469. begin
  470. Result:=GetLastError;
  471. exit;
  472. end;
  473. end;
  474. { Convert some attributes back }
  475. WinToDosTime(F.FindData.ftLastWriteTime,F.Time);
  476. f.size:=F.FindData.NFileSizeLow+(qword(maxdword)+1)*F.FindData.NFileSizeHigh;
  477. f.attr:=F.FindData.dwFileAttributes;
  478. Name:=F.FindData.cFileName;
  479. Result:=0;
  480. end;
  481. Procedure InternalFindClose (var Handle: THandle; var FindData: TFindData);
  482. begin
  483. if Handle <> INVALID_HANDLE_VALUE then
  484. begin
  485. Windows.FindClose(Handle);
  486. Handle:=INVALID_HANDLE_VALUE;
  487. end;
  488. end;
  489. Function InternalFindFirst (Const Path : UnicodeString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name : UnicodeString) : Longint;
  490. begin
  491. Name:=Path;
  492. Rslt.Attr:=attr;
  493. Rslt.ExcludeAttr:=(not Attr) and ($1e);
  494. { $1e = faHidden or faSysFile or faVolumeID or faDirectory }
  495. { FindFirstFile is a Win32 Call }
  496. Rslt.FindHandle:=FindFirstFileW (PWideChar(Path),Rslt.FindData);
  497. If Rslt.FindHandle=Invalid_Handle_value then
  498. begin
  499. Result:=GetLastError;
  500. exit;
  501. end;
  502. { Find file with correct attribute }
  503. Result:=FindMatch(Rslt,Name);
  504. if (Result<>0) then
  505. InternalFindClose(Rslt.FindHandle,Rslt.FindData);
  506. end;
  507. Function InternalFindNext (Var Rslt : TAbstractSearchRec; var Name: UnicodeString) : Longint;
  508. begin
  509. if FindNextFileW(Rslt.FindHandle, Rslt.FindData) then
  510. Result := FindMatch(Rslt, Name)
  511. else
  512. Result := GetLastError;
  513. end;
  514. Function FileGetDate (Handle : THandle) : Longint;
  515. Var
  516. FT : TFileTime;
  517. begin
  518. If GetFileTime(Handle,nil,nil,@ft) and
  519. WinToDosTime(FT,Result) then
  520. exit;
  521. Result:=-1;
  522. end;
  523. Function FileSetDate (Handle : THandle;Age : Longint) : Longint;
  524. Var
  525. FT: TFileTime;
  526. begin
  527. Result := 0;
  528. if DosToWinTime(Age,FT) and
  529. SetFileTime(Handle, nil, nil, @FT) then
  530. Exit;
  531. Result := GetLastError;
  532. end;
  533. {$IFDEF OS_FILESETDATEBYNAME}
  534. Function FileSetDate (Const FileName : UnicodeString;Age : Longint) : Longint;
  535. Var
  536. fd : THandle;
  537. begin
  538. FD := CreateFileW (PWideChar (FileName), GENERIC_READ or GENERIC_WRITE,
  539. FILE_SHARE_WRITE, nil, OPEN_EXISTING,
  540. FILE_FLAG_BACKUP_SEMANTICS, 0);
  541. If (Fd<>feInvalidHandle) then
  542. try
  543. Result:=FileSetDate(fd,Age);
  544. finally
  545. FileClose(fd);
  546. end
  547. else
  548. Result:=GetLastOSError;
  549. end;
  550. {$ENDIF}
  551. Function FileGetAttr (Const FileName : UnicodeString) : Longint;
  552. begin
  553. Result:=Longint(GetFileAttributesW(PWideChar(FileName)));
  554. end;
  555. Function FileSetAttr (Const Filename : UnicodeString; Attr: longint) : Longint;
  556. begin
  557. if SetFileAttributesW(PWideChar(FileName), Attr) then
  558. Result:=0
  559. else
  560. Result := GetLastError;
  561. end;
  562. Function DeleteFile (Const FileName : UnicodeString) : Boolean;
  563. begin
  564. Result:=Windows.DeleteFileW(PWidechar(FileName));
  565. end;
  566. Function RenameFile (Const OldName, NewName : UnicodeString) : Boolean;
  567. begin
  568. Result := MoveFileW(PWideChar(OldName), PWideChar(NewName));
  569. end;
  570. {****************************************************************************
  571. Disk Functions
  572. ****************************************************************************}
  573. type
  574. TGetDiskFreeSpaceEx = function(drive:pchar;var availableforcaller,total,free):longbool;stdcall;
  575. var
  576. GetDiskFreeSpaceEx : TGetDiskFreeSpaceEx;
  577. function diskfree(drive : byte) : int64;
  578. var
  579. disk : array[1..4] of char;
  580. secs,bytes,
  581. free,total : dword;
  582. qwtotal,qwfree,qwcaller : int64;
  583. begin
  584. if drive=0 then
  585. begin
  586. disk[1]:='\';
  587. disk[2]:=#0;
  588. end
  589. else
  590. begin
  591. disk[1]:=chr(drive+64);
  592. disk[2]:=':';
  593. disk[3]:='\';
  594. disk[4]:=#0;
  595. end;
  596. if assigned(GetDiskFreeSpaceEx) then
  597. begin
  598. if GetDiskFreeSpaceEx(@disk[1],qwcaller,qwtotal,qwfree) then
  599. diskfree:=qwfree
  600. else
  601. diskfree:=-1;
  602. end
  603. else
  604. begin
  605. if GetDiskFreeSpace(@disk[1],secs,bytes,free,total) then
  606. diskfree:=int64(free)*secs*bytes
  607. else
  608. diskfree:=-1;
  609. end;
  610. end;
  611. function disksize(drive : byte) : int64;
  612. var
  613. disk : array[1..4] of char;
  614. secs,bytes,
  615. free,total : dword;
  616. qwtotal,qwfree,qwcaller : int64;
  617. begin
  618. if drive=0 then
  619. begin
  620. disk[1]:='\';
  621. disk[2]:=#0;
  622. end
  623. else
  624. begin
  625. disk[1]:=chr(drive+64);
  626. disk[2]:=':';
  627. disk[3]:='\';
  628. disk[4]:=#0;
  629. end;
  630. if assigned(GetDiskFreeSpaceEx) then
  631. begin
  632. if GetDiskFreeSpaceEx(@disk[1],qwcaller,qwtotal,qwfree) then
  633. disksize:=qwtotal
  634. else
  635. disksize:=-1;
  636. end
  637. else
  638. begin
  639. if GetDiskFreeSpace(@disk[1],secs,bytes,free,total) then
  640. disksize:=int64(total)*secs*bytes
  641. else
  642. disksize:=-1;
  643. end;
  644. end;
  645. {****************************************************************************
  646. Time Functions
  647. ****************************************************************************}
  648. Procedure GetLocalTime(var SystemTime: TSystemTime);
  649. begin
  650. windows.Getlocaltime(SystemTime);
  651. end;
  652. function GetLocalTimeOffset: Integer;
  653. var
  654. TZInfo: TTimeZoneInformation;
  655. begin
  656. case GetTimeZoneInformation(TZInfo) of
  657. TIME_ZONE_ID_UNKNOWN:
  658. Result := TZInfo.Bias;
  659. TIME_ZONE_ID_STANDARD:
  660. Result := TZInfo.Bias + TZInfo.StandardBias;
  661. TIME_ZONE_ID_DAYLIGHT:
  662. Result := TZInfo.Bias + TZInfo.DaylightBias;
  663. else
  664. Result := 0;
  665. end;
  666. end;
  667. function GetTickCount: LongWord;
  668. begin
  669. Result := Windows.GetTickCount;
  670. end;
  671. {$IFNDEF WINCE}
  672. type
  673. TGetTickCount64 = function : QWord; stdcall;
  674. var
  675. WinGetTickCount64: TGetTickCount64 = Nil;
  676. {$ENDIF}
  677. function GetTickCount64: QWord;
  678. {$IFNDEF WINCE}
  679. var
  680. lib: THandle;
  681. {$ENDIF}
  682. begin
  683. {$IFNDEF WINCE}
  684. { on Vista and newer there is a GetTickCount64 implementation }
  685. if Win32MajorVersion >= 6 then begin
  686. if not Assigned(WinGetTickCount64) then begin
  687. lib := LoadLibrary('kernel32.dll');
  688. WinGetTickCount64 := TGetTickCount64(
  689. GetProcAddress(lib, 'GetTickCount64'));
  690. end;
  691. Result := WinGetTickCount64();
  692. end else
  693. {$ENDIF}
  694. Result := Windows.GetTickCount;
  695. end;
  696. {****************************************************************************
  697. Misc Functions
  698. ****************************************************************************}
  699. procedure sysbeep;
  700. begin
  701. MessageBeep(0);
  702. end;
  703. {****************************************************************************
  704. Locale Functions
  705. ****************************************************************************}
  706. function GetLocaleStr(LID, LT: Longint; const Def: string): ShortString;
  707. var
  708. L: Integer;
  709. Buf: array[0..255] of Char;
  710. begin
  711. L := GetLocaleInfoA(LID, LT, Buf, SizeOf(Buf));
  712. if L > 0 then
  713. SetString(Result, @Buf[0], L - 1)
  714. else
  715. Result := Def;
  716. end;
  717. function GetLocaleChar(LID, LT: Longint; Def: Char): Char;
  718. var
  719. Buf: array[0..3] of Char; // sdate allows 4 chars.
  720. begin
  721. if GetLocaleInfoA(LID, LT, Buf, sizeof(buf)) > 0 then
  722. Result := Buf[0]
  723. else
  724. Result := Def;
  725. end;
  726. function ConvertEraString(Count ,Year,Month,Day : integer) : string;
  727. var
  728. ASystemTime: TSystemTime;
  729. wbuf: array[0..100] of WideChar;
  730. ALCID : LCID;
  731. begin
  732. Result := ''; if (Count<=0) then exit;
  733. DateTimeToSystemTime(EncodeDate(Year,Month,Day),ASystemTime);
  734. ALCID := GetThreadLocale;
  735. // ALCID := SysLocale.DefaultLCID;
  736. if GetDateFormatW(ALCID , DATE_USE_ALT_CALENDAR
  737. , @ASystemTime, PWChar('gg')
  738. , @wbuf, SizeOf(wbuf)) > 0 then
  739. begin
  740. if Count = 1 then
  741. wbuf[1] := #0;
  742. Result := string(WideString(wbuf));
  743. end;
  744. end;
  745. function ConvertEraYearString(Count ,Year,Month,Day : integer) : string;
  746. var
  747. ALCID : LCID;
  748. ASystemTime : TSystemTime;
  749. AFormatText : string;
  750. buf : array[0..100] of Char;
  751. begin
  752. Result := '';
  753. DateTimeToSystemTime(EncodeDate(Year,Month,Day),ASystemTime);
  754. if Count <= 2 then
  755. AFormatText := 'yy'
  756. else
  757. AFormatText := 'yyyy';
  758. ALCID := GetThreadLocale;
  759. // ALCID := SysLocale.DefaultLCID;
  760. if GetDateFormatA(ALCID, DATE_USE_ALT_CALENDAR
  761. , @ASystemTime, PChar(AFormatText)
  762. , @buf, SizeOf(buf)) > 0 then
  763. begin
  764. Result := buf;
  765. if (Count = 1) and (Result[1] = '0') then
  766. Result := Copy(Result, 2, Length(Result)-1);
  767. end;
  768. end;
  769. Function GetLocaleInt(LID,TP,Def: LongInt): LongInt;
  770. Var
  771. S: String;
  772. C: Integer;
  773. Begin
  774. S:=GetLocaleStr(LID,TP,'0');
  775. Val(S,Result,C);
  776. If C<>0 Then
  777. Result:=Def;
  778. End;
  779. function EnumEraNames(Names: PChar): WINBOOL; stdcall;
  780. var
  781. i : integer;
  782. begin
  783. Result := False;
  784. for i := Low(EraNames) to High(EraNames) do
  785. if (EraNames[i] = '') then
  786. begin
  787. EraNames[i] := Names;
  788. Result := True;
  789. break;
  790. end;
  791. end;
  792. function EnumEraYearOffsets(YearOffsets: PChar): WINBOOL; stdcall;
  793. var
  794. i : integer;
  795. begin
  796. Result := False;
  797. for i := Low(EraYearOffsets) to High(EraYearOffsets) do
  798. if (EraYearOffsets[i] = -1) then
  799. begin
  800. EraYearOffsets[i] := StrToIntDef(YearOffsets, 0);
  801. Result := True;
  802. break;
  803. end;
  804. end;
  805. procedure GetEraNamesAndYearOffsets;
  806. var
  807. ACALID : CALID;
  808. ALCID : LCID;
  809. buf : array[0..10] of char;
  810. i : integer;
  811. begin
  812. for i:= 1 to MaxEraCount do
  813. begin
  814. EraNames[i] := ''; EraYearOffsets[i] := -1;
  815. end;
  816. ALCID := GetThreadLocale;
  817. if GetLocaleInfoA(ALCID , LOCALE_IOPTIONALCALENDAR, buf, sizeof(buf)) <= 0 then exit;
  818. ACALID := StrToIntDef(buf,1);
  819. if ACALID in [3..5] then
  820. begin
  821. EnumCalendarInfoA(@EnumEraNames, ALCID, ACALID , CAL_SERASTRING);
  822. EnumCalendarInfoA(@EnumEraYearOffsets, ALCID, ACALID, CAL_IYEAROFFSETRANGE);
  823. end;
  824. (*
  825. 1 CAL_GREGORIAN Gregorian (localized)
  826. 2 CAL_GREGORIAN_US Gregorian (English strings always)
  827. 3 CAL_JAPAN Japanese Emperor Era
  828. 4 CAL_TAIWAN Taiwan Calendar
  829. 5 CAL_KOREA Korean Tangun Era
  830. 6 CAL_HIJRI Hijri (Arabic Lunar)
  831. 7 CAL_THAI Thai
  832. 8 CAL_HEBREW Hebrew (Lunar)
  833. 9 CAL_GREGORIAN_ME_FRENCH Gregorian Middle East French
  834. 10 CAL_GREGORIAN_ARABIC Gregorian Arabic
  835. 11 CAL_GREGORIAN_XLIT_ENGLISH Gregorian transliterated English
  836. 12 CAL_GREGORIAN_XLIT_FRENCH Gregorian transliterated French
  837. 23 CAL_UMALQURA Windows Vista or later: Um Al Qura (Arabic lunar) calendar
  838. *)
  839. end;
  840. procedure GetLocaleFormatSettings(LCID: Integer; var FormatSettings: TFormatSettings);
  841. var
  842. HF : Shortstring;
  843. LID : Windows.LCID;
  844. I,Day : longint;
  845. begin
  846. LID := LCID;
  847. with FormatSettings do
  848. begin
  849. { Date stuff }
  850. for I := 1 to 12 do
  851. begin
  852. ShortMonthNames[I]:=GetLocaleStr(LID,LOCALE_SABBREVMONTHNAME1+I-1,ShortMonthNames[i]);
  853. LongMonthNames[I]:=GetLocaleStr(LID,LOCALE_SMONTHNAME1+I-1,LongMonthNames[i]);
  854. end;
  855. for I := 1 to 7 do
  856. begin
  857. Day := (I + 5) mod 7;
  858. ShortDayNames[I]:=GetLocaleStr(LID,LOCALE_SABBREVDAYNAME1+Day,ShortDayNames[i]);
  859. LongDayNames[I]:=GetLocaleStr(LID,LOCALE_SDAYNAME1+Day,LongDayNames[i]);
  860. end;
  861. DateSeparator := GetLocaleChar(LID, LOCALE_SDATE, '/');
  862. ShortDateFormat := GetLocaleStr(LID, LOCALE_SSHORTDATE, 'm/d/yy');
  863. LongDateFormat := GetLocaleStr(LID, LOCALE_SLONGDATE, 'mmmm d, yyyy');
  864. { Time stuff }
  865. TimeSeparator := GetLocaleChar(LID, LOCALE_STIME, ':');
  866. TimeAMString := GetLocaleStr(LID, LOCALE_S1159, 'AM');
  867. TimePMString := GetLocaleStr(LID, LOCALE_S2359, 'PM');
  868. if StrToIntDef(GetLocaleStr(LID, LOCALE_ITLZERO, '0'), 0) = 0 then
  869. HF:='h'
  870. else
  871. HF:='hh';
  872. // No support for 12 hour stuff at the moment...
  873. ShortTimeFormat := HF+':nn';
  874. LongTimeFormat := HF + ':nn:ss';
  875. { Currency stuff }
  876. CurrencyString:=GetLocaleStr(LID, LOCALE_SCURRENCY, '');
  877. CurrencyFormat:=StrToIntDef(GetLocaleStr(LID, LOCALE_ICURRENCY, '0'), 0);
  878. NegCurrFormat:=StrToIntDef(GetLocaleStr(LID, LOCALE_INEGCURR, '0'), 0);
  879. { Number stuff }
  880. ThousandSeparator:=GetLocaleChar(LID, LOCALE_STHOUSAND, ',');
  881. DecimalSeparator:=GetLocaleChar(LID, LOCALE_SDECIMAL, '.');
  882. CurrencyDecimals:=StrToIntDef(GetLocaleStr(LID, LOCALE_ICURRDIGITS, '0'), 0);
  883. ListSeparator := GetLocaleChar(LID, LOCALE_SLIST, ',');
  884. end;
  885. end;
  886. procedure GetFormatSettings;
  887. begin
  888. GetlocaleFormatSettings(GetThreadLocale, DefaultFormatSettings);
  889. end;
  890. Procedure InitLeadBytes;
  891. var
  892. I,B,C,E: Byte;
  893. Info: TCPInfo;
  894. begin
  895. GetCPInfo(CP_ACP,Info);
  896. I:=0;
  897. With Info do
  898. begin
  899. B:=LeadByte[i];
  900. E:=LeadByte[i+1];
  901. while (I<MAX_LEADBYTES) and (B<>0) and (E<>0) do
  902. begin
  903. for C:=B to E do
  904. Include(LeadBytes,AnsiChar(C));
  905. Inc(I,2);
  906. if (I<MAX_LEADBYTES) then
  907. begin
  908. B:=LeadByte[i];
  909. E:=LeadByte[i+1];
  910. end;
  911. end;
  912. end;
  913. end;
  914. Procedure InitInternational;
  915. var
  916. { A call to GetSystemMetrics changes the value of the 8087 Control Word on
  917. Pentium4 with WinXP SP2 }
  918. old8087CW: word;
  919. DefaultCustomLocaleID : LCID; // typedef DWORD LCID;
  920. DefaultCustomLanguageID : Word; // typedef WORD LANGID;
  921. begin
  922. /// workaround for Windows 7 bug, see bug report #18574
  923. SetThreadLocale(GetUserDefaultLCID);
  924. InitInternationalGeneric;
  925. old8087CW:=Get8087CW;
  926. SysLocale.MBCS:=GetSystemMetrics(SM_DBCSENABLED)<>0;
  927. SysLocale.RightToLeft:=GetSystemMetrics(SM_MIDEASTENABLED)<>0;
  928. SysLocale.DefaultLCID := $0409;
  929. SysLocale.PriLangID := LANG_ENGLISH;
  930. SysLocale.SubLangID := SUBLANG_ENGLISH_US;
  931. // probably needs update with getthreadlocale. post 2.0.2
  932. DefaultCustomLocaleID := GetThreadLocale;
  933. if DefaultCustomLocaleID <> 0 then
  934. begin
  935. { Locale Identifiers
  936. +-------------+---------+-------------------------+
  937. | Reserved | Sort ID | Language ID |
  938. +-------------+---------+-------------------------+
  939. 31 20 19 16 15 0 bit }
  940. DefaultCustomLanguageID := DefaultCustomLocaleID and $FFFF; // 2^16
  941. if DefaultCustomLanguageID <> 0 then
  942. begin
  943. SysLocale.DefaultLCID := DefaultCustomLocaleID;
  944. { Language Identifiers
  945. +-------------------------+-------------------------+
  946. | SubLanguage ID | Primary Language ID |
  947. +-------------------------+-------------------------+
  948. 15 10 9 0 bit }
  949. SysLocale.PriLangID := DefaultCustomLanguageID and $3ff; // 2^10
  950. SysLocale.SubLangID := DefaultCustomLanguageID shr 10;
  951. end;
  952. end;
  953. Set8087CW(old8087CW);
  954. GetFormatSettings;
  955. if SysLocale.FarEast then GetEraNamesAndYearOffsets;
  956. end;
  957. {****************************************************************************
  958. Target Dependent
  959. ****************************************************************************}
  960. function SysErrorMessage(ErrorCode: Integer): String;
  961. const
  962. MaxMsgSize = Format_Message_Max_Width_Mask;
  963. var
  964. MsgBuffer: unicodestring;
  965. len: longint;
  966. begin
  967. SetLength(MsgBuffer, MaxMsgSize);
  968. len := FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
  969. nil,
  970. ErrorCode,
  971. MakeLangId(LANG_NEUTRAL, SUBLANG_DEFAULT),
  972. PUnicodeChar(MsgBuffer),
  973. MaxMsgSize,
  974. nil);
  975. // Remove trailing #13#10
  976. if (len > 1) and (MsgBuffer[len - 1] = #13) and (MsgBuffer[len] = #10) then
  977. Dec(len, 2);
  978. SetLength(MsgBuffer, len);
  979. Result := MsgBuffer;
  980. end;
  981. {****************************************************************************
  982. Initialization code
  983. ****************************************************************************}
  984. {$push}
  985. { GetEnvironmentStrings cannot be checked by CheckPointer function }
  986. {$checkpointer off}
  987. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  988. var
  989. oemenvvar, oemstr : RawByteString;
  990. i, hplen : longint;
  991. hp,p : pchar;
  992. begin
  993. oemenvvar:=uppercase(envvar);
  994. SetCodePage(oemenvvar,CP_OEMCP);
  995. Result:='';
  996. p:=GetEnvironmentStringsA;
  997. hp:=p;
  998. while hp^<>#0 do
  999. begin
  1000. oemstr:=hp;
  1001. { cache length, may change after uppercasing depending on code page }
  1002. hplen:=length(oemstr);
  1003. { all environment variables are encoded in the oem code page }
  1004. SetCodePage(oemstr,CP_OEMCP,false);
  1005. i:=pos('=',oemstr);
  1006. if uppercase(copy(oemstr,1,i-1))=oemenvvar then
  1007. begin
  1008. Result:=copy(oemstr,i+1,length(oemstr)-i);
  1009. break;
  1010. end;
  1011. { next string entry}
  1012. hp:=hp+hplen+1;
  1013. end;
  1014. FreeEnvironmentStringsA(p);
  1015. end;
  1016. Function GetEnvironmentVariable(Const EnvVar : UnicodeString) : UnicodeString;
  1017. var
  1018. s, upperenv : Unicodestring;
  1019. i : longint;
  1020. hp,p : pwidechar;
  1021. begin
  1022. Result:='';
  1023. p:=GetEnvironmentStringsW;
  1024. hp:=p;
  1025. upperenv:=uppercase(envvar);
  1026. while hp^<>#0 do
  1027. begin
  1028. s:=hp;
  1029. i:=pos('=',s);
  1030. if uppercase(copy(s,1,i-1))=upperenv then
  1031. begin
  1032. Result:=copy(s,i+1,length(s)-i);
  1033. break;
  1034. end;
  1035. { next string entry}
  1036. hp:=hp+strlen(hp)+1;
  1037. end;
  1038. FreeEnvironmentStringsW(p);
  1039. end;
  1040. Function GetEnvironmentVariableCount : Integer;
  1041. var
  1042. hp,p : pchar;
  1043. begin
  1044. Result:=0;
  1045. p:=GetEnvironmentStringsA;
  1046. hp:=p;
  1047. If (Hp<>Nil) then
  1048. while hp^<>#0 do
  1049. begin
  1050. Inc(Result);
  1051. hp:=hp+strlen(hp)+1;
  1052. end;
  1053. FreeEnvironmentStringsA(p);
  1054. end;
  1055. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  1056. var
  1057. hp,p : pchar;
  1058. {$ifdef FPC_RTL_UNICODE}
  1059. tmpstr : RawByteString;
  1060. {$endif}
  1061. begin
  1062. Result:='';
  1063. p:=GetEnvironmentStringsA;
  1064. hp:=p;
  1065. If (Hp<>Nil) then
  1066. begin
  1067. while (hp^<>#0) and (Index>1) do
  1068. begin
  1069. Dec(Index);
  1070. hp:=hp+strlen(hp)+1;
  1071. end;
  1072. If (hp^<>#0) then
  1073. begin
  1074. {$ifdef FPC_RTL_UNICODE}
  1075. tmpstr:=hp;
  1076. SetCodePage(tmpstr,CP_OEMCP,false);
  1077. Result:=tmpstr;
  1078. {$else}
  1079. Result:=hp;
  1080. SetCodePage(RawByteString(Result),CP_OEMCP,false);
  1081. {$endif}
  1082. end;
  1083. end;
  1084. FreeEnvironmentStringsA(p);
  1085. end;
  1086. {$pop}
  1087. function ExecuteProcess(Const Path: RawByteString; Const ComLine: RawByteString;Flags:TExecuteFlags=[]):integer;
  1088. begin
  1089. result:=ExecuteProcess(Unicodestring(Path),UnicodeString(ComLine),Flags);
  1090. end;
  1091. function ExecuteProcess(Const Path: UnicodeString; Const ComLine: UnicodeString;Flags:TExecuteFlags=[]):integer;
  1092. // win specific function
  1093. var
  1094. SI: TStartupInfoW;
  1095. PI: TProcessInformation;
  1096. Proc : THandle;
  1097. l : DWord;
  1098. CommandLine : unicodestring;
  1099. e : EOSError;
  1100. ExecInherits : longbool;
  1101. begin
  1102. FillChar(SI, SizeOf(SI), 0);
  1103. SI.cb:=SizeOf(SI);
  1104. SI.wShowWindow:=1;
  1105. { always surround the name of the application by quotes
  1106. so that long filenames will always be accepted. But don't
  1107. do it if there are already double quotes, since Win32 does not
  1108. like double quotes which are duplicated!
  1109. }
  1110. if pos('"',path)=0 then
  1111. CommandLine:='"'+path+'"'
  1112. else
  1113. CommandLine:=path;
  1114. if ComLine <> '' then
  1115. CommandLine:=Commandline+' '+ComLine+#0
  1116. else
  1117. CommandLine := CommandLine + #0;
  1118. ExecInherits:=ExecInheritsHandles in Flags;
  1119. if not CreateProcessW(nil, pwidechar(CommandLine),
  1120. Nil, Nil, ExecInherits,$20, Nil, Nil, SI, PI) then
  1121. begin
  1122. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
  1123. e.ErrorCode:=GetLastError;
  1124. raise e;
  1125. end;
  1126. Proc:=PI.hProcess;
  1127. if WaitForSingleObject(Proc, dword($ffffffff)) <> $ffffffff then
  1128. begin
  1129. GetExitCodeProcess(Proc,l);
  1130. CloseHandle(Proc);
  1131. CloseHandle(PI.hThread);
  1132. result:=l;
  1133. end
  1134. else
  1135. begin
  1136. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
  1137. e.ErrorCode:=GetLastError;
  1138. CloseHandle(Proc);
  1139. CloseHandle(PI.hThread);
  1140. raise e;
  1141. end;
  1142. end;
  1143. function ExecuteProcess(Const Path: RawByteString; Const ComLine: Array of RawByteString;Flags:TExecuteFlags=[]):integer;
  1144. var
  1145. CommandLine: UnicodeString;
  1146. I: integer;
  1147. begin
  1148. Commandline := '';
  1149. for I := 0 to High (ComLine) do
  1150. if Pos (' ', ComLine [I]) <> 0 then
  1151. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  1152. else
  1153. CommandLine := CommandLine + ' ' + Comline [I];
  1154. ExecuteProcess := ExecuteProcess (UnicodeString(Path), CommandLine,Flags);
  1155. end;
  1156. function ExecuteProcess(Const Path: UnicodeString; Const ComLine: Array of UnicodeString;Flags:TExecuteFlags=[]):integer;
  1157. var
  1158. CommandLine: UnicodeString;
  1159. I: integer;
  1160. begin
  1161. Commandline := '';
  1162. for I := 0 to High (ComLine) do
  1163. if Pos (' ', ComLine [I]) <> 0 then
  1164. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  1165. else
  1166. CommandLine := CommandLine + ' ' + Comline [I];
  1167. ExecuteProcess := ExecuteProcess (Path,CommandLine,Flags);
  1168. end;
  1169. Procedure Sleep(Milliseconds : Cardinal);
  1170. begin
  1171. Windows.Sleep(MilliSeconds)
  1172. end;
  1173. Function GetLastOSError : Integer;
  1174. begin
  1175. Result:=GetLastError;
  1176. end;
  1177. {****************************************************************************
  1178. Initialization code
  1179. ****************************************************************************}
  1180. var
  1181. kernel32dll : THandle;
  1182. Procedure LoadVersionInfo;
  1183. // and getfreespaceex
  1184. Var
  1185. versioninfo : TOSVERSIONINFO;
  1186. begin
  1187. GetDiskFreeSpaceEx:=nil;
  1188. versioninfo.dwOSVersionInfoSize:=sizeof(versioninfo);
  1189. GetVersionEx(versioninfo);
  1190. Win32Platform:=versionInfo.dwPlatformId;
  1191. Win32MajorVersion:=versionInfo.dwMajorVersion;
  1192. Win32MinorVersion:=versionInfo.dwMinorVersion;
  1193. Win32BuildNumber:=versionInfo.dwBuildNumber;
  1194. Move (versioninfo.szCSDVersion ,Win32CSDVersion[1],128);
  1195. win32CSDVersion[0]:=chr(strlen(pchar(@versioninfo.szCSDVersion)));
  1196. kernel32dll:=GetModuleHandle('kernel32');
  1197. if kernel32dll<>0 then
  1198. GetDiskFreeSpaceEx:=TGetDiskFreeSpaceEx(GetProcAddress(kernel32dll,'GetDiskFreeSpaceExA'));
  1199. end;
  1200. Function GetAppConfigDir(Global : Boolean) : String;
  1201. begin
  1202. If Global then
  1203. Result:=GetWindowsSpecialDir(CSIDL_COMMON_APPDATA)
  1204. else
  1205. Result:=GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA);
  1206. If (Result<>'') then
  1207. begin
  1208. if VendorName<>'' then
  1209. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  1210. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  1211. end
  1212. else
  1213. Result:=IncludeTrailingPathDelimiter(DGetAppConfigDir(Global));
  1214. end;
  1215. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  1216. begin
  1217. result:=DGetAppConfigFile(Global,SubDir);
  1218. end;
  1219. Function GetUserDir : String;
  1220. begin
  1221. Result:=GetWindowsSpecialDir(CSIDL_PROFILE);
  1222. end;
  1223. Procedure InitSysConfigDir;
  1224. begin
  1225. SetLength(SysConfigDir, MAX_PATH);
  1226. SetLength(SysConfigDir, GetWindowsDirectoryA(PChar(SysConfigDir), MAX_PATH));
  1227. end;
  1228. {****************************************************************************
  1229. Target Dependent WideString stuff
  1230. ****************************************************************************}
  1231. { This is the case of Win9x. Limited to current locale of course, but it's better
  1232. than not working at all. }
  1233. function DoCompareStringA(P1, P2: PWideChar; L1, L2: PtrUInt; Flags: DWORD): PtrInt;
  1234. var
  1235. a1, a2: AnsiString;
  1236. begin
  1237. if L1>0 then
  1238. widestringmanager.Wide2AnsiMoveProc(P1,a1,DefaultSystemCodePage,L1);
  1239. if L2>0 then
  1240. widestringmanager.Wide2AnsiMoveProc(P2,a2,DefaultSystemCodePage,L2);
  1241. SetLastError(0);
  1242. Result:=CompareStringA(LOCALE_USER_DEFAULT,Flags,pchar(a1),
  1243. length(a1),pchar(a2),length(a2))-2;
  1244. end;
  1245. function DoCompareStringW(P1, P2: PWideChar; L1, L2: PtrUInt; Flags: DWORD): PtrInt;
  1246. begin
  1247. SetLastError(0);
  1248. Result:=CompareStringW(LOCALE_USER_DEFAULT,Flags,P1,L1,P2,L2)-2;
  1249. if GetLastError=0 then
  1250. Exit;
  1251. if GetLastError=ERROR_CALL_NOT_IMPLEMENTED then // Win9x case
  1252. Result:=DoCompareStringA(P1, P2, L1, L2, Flags);
  1253. if GetLastError<>0 then
  1254. RaiseLastOSError;
  1255. end;
  1256. const
  1257. WinAPICompareFlags : array [TCompareOption] of LongWord
  1258. = ({LINGUISTIC_IGNORECASE, LINGUISTIC_IGNOREDIACRITIC, }NORM_IGNORECASE{,
  1259. NORM_IGNOREKANATYPE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS, NORM_IGNOREWIDTH,
  1260. NORM_LINGUISTIC_CASING, SORT_DIGITSASNUMBERS, SORT_STRINGSORT});
  1261. function Win32CompareWideString(const s1, s2 : WideString; Options : TCompareOptions) : PtrInt;
  1262. Var
  1263. O : LongWord;
  1264. CO : TCompareOption;
  1265. begin
  1266. O:=0;
  1267. for CO in TCompareOption do
  1268. if CO in Options then
  1269. O:=O or WinAPICompareFlags[CO];
  1270. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), O);
  1271. end;
  1272. function Win32CompareTextWideString(const s1, s2 : WideString) : PtrInt;
  1273. begin
  1274. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), NORM_IGNORECASE);
  1275. end;
  1276. function Win32AnsiUpperCase(const s: string): string;
  1277. begin
  1278. if length(s)>0 then
  1279. begin
  1280. result:=s;
  1281. UniqueString(result);
  1282. CharUpperBuffA(pchar(result),length(result));
  1283. end
  1284. else
  1285. result:='';
  1286. end;
  1287. function Win32AnsiLowerCase(const s: string): string;
  1288. begin
  1289. if length(s)>0 then
  1290. begin
  1291. result:=s;
  1292. UniqueString(result);
  1293. CharLowerBuffA(pchar(result),length(result));
  1294. end
  1295. else
  1296. result:='';
  1297. end;
  1298. function Win32AnsiCompareStr(const S1, S2: string): PtrInt;
  1299. begin
  1300. result:=CompareStringA(LOCALE_USER_DEFAULT,0,pchar(s1),length(s1),
  1301. pchar(s2),length(s2))-2;
  1302. end;
  1303. function Win32AnsiCompareText(const S1, S2: string): PtrInt;
  1304. begin
  1305. result:=CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE,pchar(s1),length(s1),
  1306. pchar(s2),length(s2))-2;
  1307. end;
  1308. function Win32AnsiStrComp(S1, S2: PChar): PtrInt;
  1309. begin
  1310. result:=CompareStringA(LOCALE_USER_DEFAULT,0,s1,-1,s2,-1)-2;
  1311. end;
  1312. function Win32AnsiStrIComp(S1, S2: PChar): PtrInt;
  1313. begin
  1314. result:=CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE,s1,-1,s2,-1)-2;
  1315. end;
  1316. function Win32AnsiStrLComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  1317. begin
  1318. result:=CompareStringA(LOCALE_USER_DEFAULT,0,s1,maxlen,s2,maxlen)-2;
  1319. end;
  1320. function Win32AnsiStrLIComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  1321. begin
  1322. result:=CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE,s1,maxlen,s2,maxlen)-2;
  1323. end;
  1324. function Win32AnsiStrLower(Str: PChar): PChar;
  1325. begin
  1326. CharLowerA(str);
  1327. result:=str;
  1328. end;
  1329. function Win32AnsiStrUpper(Str: PChar): PChar;
  1330. begin
  1331. CharUpperA(str);
  1332. result:=str;
  1333. end;
  1334. function Win32CompareUnicodeString(const s1, s2 : UnicodeString; Options : TCompareOptions) : PtrInt;
  1335. Var
  1336. O : LongWord;
  1337. CO : TCompareOption;
  1338. begin
  1339. O:=0;
  1340. for CO in TCompareOption do
  1341. if CO in Options then
  1342. O:=O or WinAPICompareFlags[CO];
  1343. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), O);
  1344. end;
  1345. function Win32CompareTextUnicodeString(const s1, s2 : UnicodeString) : PtrInt;
  1346. begin
  1347. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), NORM_IGNORECASE);
  1348. end;
  1349. { there is a similiar procedure in the system unit which inits the fields which
  1350. are relevant already for the system unit }
  1351. procedure InitWin32Widestrings;
  1352. begin
  1353. { return value: number of code points in the string. Whenever an invalid
  1354. code point is encountered, all characters part of this invalid code point
  1355. are considered to form one "character" and the next character is
  1356. considered to be the start of a new (possibly also invalid) code point }
  1357. //!!! CharLengthPCharProc : function(const Str: PChar): PtrInt;
  1358. { return value:
  1359. -1 if incomplete or invalid code point
  1360. 0 if NULL character,
  1361. > 0 if that's the length in bytes of the code point }
  1362. //!!!! CodePointLengthProc : function(const Str: PChar; MaxLookAead: PtrInt): Ptrint;
  1363. widestringmanager.CompareWideStringProc:=@Win32CompareWideString;
  1364. widestringmanager.UpperAnsiStringProc:=@Win32AnsiUpperCase;
  1365. widestringmanager.LowerAnsiStringProc:=@Win32AnsiLowerCase;
  1366. widestringmanager.CompareStrAnsiStringProc:=@Win32AnsiCompareStr;
  1367. widestringmanager.CompareTextAnsiStringProc:=@Win32AnsiCompareText;
  1368. widestringmanager.StrCompAnsiStringProc:=@Win32AnsiStrComp;
  1369. widestringmanager.StrICompAnsiStringProc:=@Win32AnsiStrIComp;
  1370. widestringmanager.StrLCompAnsiStringProc:=@Win32AnsiStrLComp;
  1371. widestringmanager.StrLICompAnsiStringProc:=@Win32AnsiStrLIComp;
  1372. widestringmanager.StrLowerAnsiStringProc:=@Win32AnsiStrLower;
  1373. widestringmanager.StrUpperAnsiStringProc:=@Win32AnsiStrUpper;
  1374. widestringmanager.CompareUnicodeStringProc:=@Win32CompareUnicodeString;
  1375. end;
  1376. { Platform-specific exception support }
  1377. function WinExceptionObject(code: Longint; const rec: TExceptionRecord): Exception;
  1378. var
  1379. entry: PExceptMapEntry;
  1380. begin
  1381. entry := FindExceptMapEntry(code);
  1382. if assigned(entry) then
  1383. result:=entry^.cls.CreateRes(entry^.msg)
  1384. else
  1385. result:=EExternalException.CreateResFmt(@SExternalException,[rec.ExceptionCode]);
  1386. if result is EExternal then
  1387. EExternal(result).FExceptionRecord:=rec;
  1388. end;
  1389. function WinExceptionClass(code: longint): ExceptClass;
  1390. var
  1391. entry: PExceptMapEntry;
  1392. begin
  1393. entry := FindExceptMapEntry(code);
  1394. if assigned(entry) then
  1395. result:=entry^.cls
  1396. else
  1397. result:=EExternalException;
  1398. end;
  1399. Initialization
  1400. InitWin32Widestrings;
  1401. InitExceptions; { Initialize exceptions. OS independent }
  1402. {$ifdef mswindows} { Keeps exe size down for systems that do not use SEH }
  1403. ExceptObjProc:=@WinExceptionObject;
  1404. ExceptClsProc:=@WinExceptionClass;
  1405. {$endif mswindows}
  1406. InitLeadBytes;
  1407. InitInternational; { Initialize internationalization settings }
  1408. LoadVersionInfo;
  1409. InitSysConfigDir;
  1410. OnBeep:=@SysBeep;
  1411. Finalization
  1412. DoneExceptions;
  1413. end.