sysutils.pp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499
  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. if Handle<=4 then
  291. exit;
  292. CloseHandle(Handle);
  293. end;
  294. Function FileTruncate (Handle : THandle;Size: Int64) : boolean;
  295. begin
  296. {
  297. Result:=longint(SetFilePointer(handle,Size,nil,FILE_BEGIN))<>-1;
  298. }
  299. if FileSeek (Handle, Size, FILE_BEGIN) = Size then
  300. Result:=SetEndOfFile(handle)
  301. else
  302. Result := false;
  303. end;
  304. Function DosToWinTime (DTime:longint;Var Wtime : TFileTime):longbool;
  305. var
  306. lft : TFileTime;
  307. begin
  308. DosToWinTime:=DosDateTimeToFileTime(longrec(dtime).hi,longrec(dtime).lo,@lft) and
  309. LocalFileTimeToFileTime(lft,Wtime);
  310. end;
  311. Function WinToDosTime (Var Wtime : TFileTime;var DTime:longint):longbool;
  312. var
  313. lft : TFileTime;
  314. begin
  315. WinToDosTime:=FileTimeToLocalFileTime(WTime,lft) and
  316. FileTimeToDosDateTime(lft,Longrec(Dtime).Hi,LongRec(DTIME).lo);
  317. end;
  318. Function FileAge (Const FileName : UnicodeString): Longint;
  319. var
  320. Handle: THandle;
  321. FindData: TWin32FindDataW;
  322. begin
  323. Handle := FindFirstFileW(Pwidechar(FileName), FindData);
  324. if Handle <> INVALID_HANDLE_VALUE then
  325. begin
  326. Windows.FindClose(Handle);
  327. if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
  328. If WinToDosTime(FindData.ftLastWriteTime,Result) then
  329. exit;
  330. end;
  331. Result := -1;
  332. end;
  333. Function FileExists (Const FileName : UnicodeString) : Boolean;
  334. var
  335. Attr:Dword;
  336. begin
  337. Attr:=GetFileAttributesW(PWideChar(FileName));
  338. if Attr <> $ffffffff then
  339. Result:= (Attr and FILE_ATTRIBUTE_DIRECTORY) = 0
  340. else
  341. Result:=False;
  342. end;
  343. Function DirectoryExists (Const Directory : UnicodeString) : Boolean;
  344. var
  345. Attr:Dword;
  346. begin
  347. Attr:=GetFileAttributesW(PWideChar(Directory));
  348. if Attr <> $ffffffff then
  349. Result:= (Attr and FILE_ATTRIBUTE_DIRECTORY) > 0
  350. else
  351. Result:=False;
  352. end;
  353. Function FindMatch(var f: TAbstractSearchRec; var Name: UnicodeString) : Longint;
  354. begin
  355. { Find file with correct attribute }
  356. While (F.FindData.dwFileAttributes and cardinal(F.ExcludeAttr))<>0 do
  357. begin
  358. if not FindNextFileW (F.FindHandle,F.FindData) then
  359. begin
  360. Result:=GetLastError;
  361. exit;
  362. end;
  363. end;
  364. { Convert some attributes back }
  365. WinToDosTime(F.FindData.ftLastWriteTime,F.Time);
  366. f.size:=F.FindData.NFileSizeLow+(qword(maxdword)+1)*F.FindData.NFileSizeHigh;
  367. f.attr:=F.FindData.dwFileAttributes;
  368. Name:=F.FindData.cFileName;
  369. Result:=0;
  370. end;
  371. Procedure InternalFindClose (var Handle: THandle; var FindData: TFindData);
  372. begin
  373. if Handle <> INVALID_HANDLE_VALUE then
  374. begin
  375. Windows.FindClose(Handle);
  376. Handle:=INVALID_HANDLE_VALUE;
  377. end;
  378. end;
  379. Function InternalFindFirst (Const Path : UnicodeString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name : UnicodeString) : Longint;
  380. begin
  381. Name:=Path;
  382. Rslt.Attr:=attr;
  383. Rslt.ExcludeAttr:=(not Attr) and ($1e);
  384. { $1e = faHidden or faSysFile or faVolumeID or faDirectory }
  385. { FindFirstFile is a Win32 Call }
  386. Rslt.FindHandle:=FindFirstFileW (PWideChar(Path),Rslt.FindData);
  387. If Rslt.FindHandle=Invalid_Handle_value then
  388. begin
  389. Result:=GetLastError;
  390. exit;
  391. end;
  392. { Find file with correct attribute }
  393. Result:=FindMatch(Rslt,Name);
  394. if (Result<>0) then
  395. InternalFindClose(Rslt.FindHandle,Rslt.FindData);
  396. end;
  397. Function InternalFindNext (Var Rslt : TAbstractSearchRec; var Name: UnicodeString) : Longint;
  398. begin
  399. if FindNextFileW(Rslt.FindHandle, Rslt.FindData) then
  400. Result := FindMatch(Rslt, Name)
  401. else
  402. Result := GetLastError;
  403. end;
  404. Function FileGetDate (Handle : THandle) : Longint;
  405. Var
  406. FT : TFileTime;
  407. begin
  408. If GetFileTime(Handle,nil,nil,@ft) and
  409. WinToDosTime(FT,Result) then
  410. exit;
  411. Result:=-1;
  412. end;
  413. Function FileSetDate (Handle : THandle;Age : Longint) : Longint;
  414. Var
  415. FT: TFileTime;
  416. begin
  417. Result := 0;
  418. if DosToWinTime(Age,FT) and
  419. SetFileTime(Handle, nil, nil, @FT) then
  420. Exit;
  421. Result := GetLastError;
  422. end;
  423. {$IFDEF OS_FILESETDATEBYNAME}
  424. Function FileSetDate (Const FileName : UnicodeString;Age : Longint) : Longint;
  425. Var
  426. fd : THandle;
  427. begin
  428. FD := CreateFileW (PWideChar (FileName), GENERIC_READ or GENERIC_WRITE,
  429. FILE_SHARE_WRITE, nil, OPEN_EXISTING,
  430. FILE_FLAG_BACKUP_SEMANTICS, 0);
  431. If (Fd<>feInvalidHandle) then
  432. try
  433. Result:=FileSetDate(fd,Age);
  434. finally
  435. FileClose(fd);
  436. end
  437. else
  438. Result:=GetLastOSError;
  439. end;
  440. {$ENDIF}
  441. Function FileGetAttr (Const FileName : UnicodeString) : Longint;
  442. begin
  443. Result:=Longint(GetFileAttributesW(PWideChar(FileName)));
  444. end;
  445. Function FileSetAttr (Const Filename : UnicodeString; Attr: longint) : Longint;
  446. begin
  447. if SetFileAttributesW(PWideChar(FileName), Attr) then
  448. Result:=0
  449. else
  450. Result := GetLastError;
  451. end;
  452. Function DeleteFile (Const FileName : UnicodeString) : Boolean;
  453. begin
  454. Result:=Windows.DeleteFileW(PWidechar(FileName));
  455. end;
  456. Function RenameFile (Const OldName, NewName : UnicodeString) : Boolean;
  457. begin
  458. Result := MoveFileW(PWideChar(OldName), PWideChar(NewName));
  459. end;
  460. {****************************************************************************
  461. Disk Functions
  462. ****************************************************************************}
  463. type
  464. TGetDiskFreeSpaceEx = function(drive:pchar;var availableforcaller,total,free):longbool;stdcall;
  465. var
  466. GetDiskFreeSpaceEx : TGetDiskFreeSpaceEx;
  467. function diskfree(drive : byte) : int64;
  468. var
  469. disk : array[1..4] of char;
  470. secs,bytes,
  471. free,total : dword;
  472. qwtotal,qwfree,qwcaller : int64;
  473. begin
  474. if drive=0 then
  475. begin
  476. disk[1]:='\';
  477. disk[2]:=#0;
  478. end
  479. else
  480. begin
  481. disk[1]:=chr(drive+64);
  482. disk[2]:=':';
  483. disk[3]:='\';
  484. disk[4]:=#0;
  485. end;
  486. if assigned(GetDiskFreeSpaceEx) then
  487. begin
  488. if GetDiskFreeSpaceEx(@disk[1],qwcaller,qwtotal,qwfree) then
  489. diskfree:=qwfree
  490. else
  491. diskfree:=-1;
  492. end
  493. else
  494. begin
  495. if GetDiskFreeSpace(@disk[1],secs,bytes,free,total) then
  496. diskfree:=int64(free)*secs*bytes
  497. else
  498. diskfree:=-1;
  499. end;
  500. end;
  501. function disksize(drive : byte) : int64;
  502. var
  503. disk : array[1..4] of char;
  504. secs,bytes,
  505. free,total : dword;
  506. qwtotal,qwfree,qwcaller : int64;
  507. begin
  508. if drive=0 then
  509. begin
  510. disk[1]:='\';
  511. disk[2]:=#0;
  512. end
  513. else
  514. begin
  515. disk[1]:=chr(drive+64);
  516. disk[2]:=':';
  517. disk[3]:='\';
  518. disk[4]:=#0;
  519. end;
  520. if assigned(GetDiskFreeSpaceEx) then
  521. begin
  522. if GetDiskFreeSpaceEx(@disk[1],qwcaller,qwtotal,qwfree) then
  523. disksize:=qwtotal
  524. else
  525. disksize:=-1;
  526. end
  527. else
  528. begin
  529. if GetDiskFreeSpace(@disk[1],secs,bytes,free,total) then
  530. disksize:=int64(total)*secs*bytes
  531. else
  532. disksize:=-1;
  533. end;
  534. end;
  535. {****************************************************************************
  536. Time Functions
  537. ****************************************************************************}
  538. Procedure GetLocalTime(var SystemTime: TSystemTime);
  539. begin
  540. windows.Getlocaltime(SystemTime);
  541. end;
  542. function GetLocalTimeOffset: Integer;
  543. var
  544. TZInfo: TTimeZoneInformation;
  545. begin
  546. case GetTimeZoneInformation(TZInfo) of
  547. TIME_ZONE_ID_UNKNOWN:
  548. Result := TZInfo.Bias;
  549. TIME_ZONE_ID_STANDARD:
  550. Result := TZInfo.Bias + TZInfo.StandardBias;
  551. TIME_ZONE_ID_DAYLIGHT:
  552. Result := TZInfo.Bias + TZInfo.DaylightBias;
  553. else
  554. Result := 0;
  555. end;
  556. end;
  557. function GetTickCount: LongWord;
  558. begin
  559. Result := Windows.GetTickCount;
  560. end;
  561. {$IFNDEF WINCE}
  562. type
  563. TGetTickCount64 = function : QWord; stdcall;
  564. var
  565. WinGetTickCount64: TGetTickCount64 = Nil;
  566. {$ENDIF}
  567. function GetTickCount64: QWord;
  568. {$IFNDEF WINCE}
  569. var
  570. lib: THandle;
  571. {$ENDIF}
  572. begin
  573. {$IFNDEF WINCE}
  574. { on Vista and newer there is a GetTickCount64 implementation }
  575. if Win32MajorVersion >= 6 then begin
  576. if not Assigned(WinGetTickCount64) then begin
  577. lib := LoadLibrary('kernel32.dll');
  578. WinGetTickCount64 := TGetTickCount64(
  579. GetProcAddress(lib, 'GetTickCount64'));
  580. end;
  581. Result := WinGetTickCount64();
  582. end else
  583. {$ENDIF}
  584. Result := Windows.GetTickCount;
  585. end;
  586. {****************************************************************************
  587. Misc Functions
  588. ****************************************************************************}
  589. procedure sysbeep;
  590. begin
  591. MessageBeep(0);
  592. end;
  593. {****************************************************************************
  594. Locale Functions
  595. ****************************************************************************}
  596. function GetLocaleStr(LID, LT: Longint; const Def: string): ShortString;
  597. var
  598. L: Integer;
  599. Buf: array[0..255] of Char;
  600. begin
  601. L := GetLocaleInfoA(LID, LT, Buf, SizeOf(Buf));
  602. if L > 0 then
  603. SetString(Result, @Buf[0], L - 1)
  604. else
  605. Result := Def;
  606. end;
  607. function GetLocaleChar(LID, LT: Longint; Def: Char): Char;
  608. var
  609. Buf: array[0..3] of Char; // sdate allows 4 chars.
  610. begin
  611. if GetLocaleInfoA(LID, LT, Buf, sizeof(buf)) > 0 then
  612. Result := Buf[0]
  613. else
  614. Result := Def;
  615. end;
  616. function ConvertEraString(Count ,Year,Month,Day : integer) : string;
  617. var
  618. ASystemTime: TSystemTime;
  619. buf: array[0..100] of char;
  620. ALCID : LCID;
  621. PriLangID : Word;
  622. SubLangID : Word;
  623. begin
  624. Result := ''; if (Count<=0) then exit;
  625. DateTimeToSystemTime(EncodeDate(Year,Month,Day),ASystemTime);
  626. ALCID := GetThreadLocale;
  627. // ALCID := SysLocale.DefaultLCID;
  628. if GetDateFormatA(ALCID , DATE_USE_ALT_CALENDAR
  629. , @ASystemTime, PChar('gg')
  630. , @buf, SizeOf(buf)) > 0 then
  631. begin
  632. Result := buf;
  633. if Count = 1 then
  634. begin
  635. PriLangID := ALCID and $3FF;
  636. SubLangID := (ALCID and $FFFF) shr 10;
  637. case PriLangID of
  638. LANG_JAPANESE:
  639. begin
  640. Result := Copy(WideString(Result),1,1);
  641. end;
  642. LANG_CHINESE:
  643. if (SubLangID = SUBLANG_CHINESE_TRADITIONAL) then
  644. begin
  645. Result := Copy(WideString(Result),1,1);
  646. end;
  647. end;
  648. end;
  649. end;
  650. // if Result = '' then Result := StringOfChar('G',Count);
  651. end;
  652. function ConvertEraYearString(Count ,Year,Month,Day : integer) : string;
  653. var
  654. ALCID : LCID;
  655. ASystemTime : TSystemTime;
  656. AFormatText : string;
  657. buf : array[0..100] of Char;
  658. begin
  659. Result := '';
  660. DateTimeToSystemTime(EncodeDate(Year,Month,Day),ASystemTime);
  661. if Count <= 2 then
  662. AFormatText := 'yy'
  663. else
  664. AFormatText := 'yyyy';
  665. ALCID := GetThreadLocale;
  666. // ALCID := SysLocale.DefaultLCID;
  667. if GetDateFormatA(ALCID, DATE_USE_ALT_CALENDAR
  668. , @ASystemTime, PChar(AFormatText)
  669. , @buf, SizeOf(buf)) > 0 then
  670. begin
  671. Result := buf;
  672. if (Count = 1) and (Result[1] = '0') then
  673. Result := Copy(Result, 2, Length(Result)-1);
  674. end;
  675. end;
  676. Function GetLocaleInt(LID,TP,Def: LongInt): LongInt;
  677. Var
  678. S: String;
  679. C: Integer;
  680. Begin
  681. S:=GetLocaleStr(LID,TP,'0');
  682. Val(S,Result,C);
  683. If C<>0 Then
  684. Result:=Def;
  685. End;
  686. function EnumEraNames(Names: PChar): WINBOOL; stdcall;
  687. var
  688. i : integer;
  689. begin
  690. Result := False;
  691. for i := Low(EraNames) to High(EraNames) do
  692. if (EraNames[i] = '') then
  693. begin
  694. EraNames[i] := Names;
  695. Result := True;
  696. break;
  697. end;
  698. end;
  699. function EnumEraYearOffsets(YearOffsets: PChar): WINBOOL; stdcall;
  700. var
  701. i : integer;
  702. begin
  703. Result := False;
  704. for i := Low(EraYearOffsets) to High(EraYearOffsets) do
  705. if (EraYearOffsets[i] = -1) then
  706. begin
  707. EraYearOffsets[i] := StrToIntDef(YearOffsets, 0);
  708. Result := True;
  709. break;
  710. end;
  711. end;
  712. procedure GetEraNamesAndYearOffsets;
  713. var
  714. ACALID : CALID;
  715. ALCID : LCID;
  716. buf : array[0..10] of char;
  717. i : integer;
  718. begin
  719. for i:= 1 to MaxEraCount do
  720. begin
  721. EraNames[i] := ''; EraYearOffsets[i] := -1;
  722. end;
  723. ALCID := GetThreadLocale;
  724. if GetLocaleInfoA(ALCID , LOCALE_IOPTIONALCALENDAR, buf, sizeof(buf)) <= 0 then exit;
  725. ACALID := StrToIntDef(buf,1);
  726. if ACALID in [3..5] then
  727. begin
  728. EnumCalendarInfoA(@EnumEraNames, ALCID, ACALID , CAL_SERASTRING);
  729. EnumCalendarInfoA(@EnumEraYearOffsets, ALCID, ACALID, CAL_IYEAROFFSETRANGE);
  730. end;
  731. (*
  732. 1 CAL_GREGORIAN Gregorian (localized)
  733. 2 CAL_GREGORIAN_US Gregorian (English strings always)
  734. 3 CAL_JAPAN Japanese Emperor Era
  735. 4 CAL_TAIWAN Taiwan Calendar
  736. 5 CAL_KOREA Korean Tangun Era
  737. 6 CAL_HIJRI Hijri (Arabic Lunar)
  738. 7 CAL_THAI Thai
  739. 8 CAL_HEBREW Hebrew (Lunar)
  740. 9 CAL_GREGORIAN_ME_FRENCH Gregorian Middle East French
  741. 10 CAL_GREGORIAN_ARABIC Gregorian Arabic
  742. 11 CAL_GREGORIAN_XLIT_ENGLISH Gregorian transliterated English
  743. 12 CAL_GREGORIAN_XLIT_FRENCH Gregorian transliterated French
  744. 23 CAL_UMALQURA Windows Vista or later: Um Al Qura (Arabic lunar) calendar
  745. *)
  746. end;
  747. procedure GetLocaleFormatSettings(LCID: Integer; var FormatSettings: TFormatSettings);
  748. var
  749. HF : Shortstring;
  750. LID : Windows.LCID;
  751. I,Day : longint;
  752. begin
  753. LID := LCID;
  754. with FormatSettings do
  755. begin
  756. { Date stuff }
  757. for I := 1 to 12 do
  758. begin
  759. ShortMonthNames[I]:=GetLocaleStr(LID,LOCALE_SABBREVMONTHNAME1+I-1,ShortMonthNames[i]);
  760. LongMonthNames[I]:=GetLocaleStr(LID,LOCALE_SMONTHNAME1+I-1,LongMonthNames[i]);
  761. end;
  762. for I := 1 to 7 do
  763. begin
  764. Day := (I + 5) mod 7;
  765. ShortDayNames[I]:=GetLocaleStr(LID,LOCALE_SABBREVDAYNAME1+Day,ShortDayNames[i]);
  766. LongDayNames[I]:=GetLocaleStr(LID,LOCALE_SDAYNAME1+Day,LongDayNames[i]);
  767. end;
  768. DateSeparator := GetLocaleChar(LID, LOCALE_SDATE, '/');
  769. ShortDateFormat := GetLocaleStr(LID, LOCALE_SSHORTDATE, 'm/d/yy');
  770. LongDateFormat := GetLocaleStr(LID, LOCALE_SLONGDATE, 'mmmm d, yyyy');
  771. { Time stuff }
  772. TimeSeparator := GetLocaleChar(LID, LOCALE_STIME, ':');
  773. TimeAMString := GetLocaleStr(LID, LOCALE_S1159, 'AM');
  774. TimePMString := GetLocaleStr(LID, LOCALE_S2359, 'PM');
  775. if StrToIntDef(GetLocaleStr(LID, LOCALE_ITLZERO, '0'), 0) = 0 then
  776. HF:='h'
  777. else
  778. HF:='hh';
  779. // No support for 12 hour stuff at the moment...
  780. ShortTimeFormat := HF+':nn';
  781. LongTimeFormat := HF + ':nn:ss';
  782. { Currency stuff }
  783. CurrencyString:=GetLocaleStr(LID, LOCALE_SCURRENCY, '');
  784. CurrencyFormat:=StrToIntDef(GetLocaleStr(LID, LOCALE_ICURRENCY, '0'), 0);
  785. NegCurrFormat:=StrToIntDef(GetLocaleStr(LID, LOCALE_INEGCURR, '0'), 0);
  786. { Number stuff }
  787. ThousandSeparator:=GetLocaleChar(LID, LOCALE_STHOUSAND, ',');
  788. DecimalSeparator:=GetLocaleChar(LID, LOCALE_SDECIMAL, '.');
  789. CurrencyDecimals:=StrToIntDef(GetLocaleStr(LID, LOCALE_ICURRDIGITS, '0'), 0);
  790. ListSeparator := GetLocaleChar(LID, LOCALE_SLIST, ',');
  791. end;
  792. end;
  793. procedure GetFormatSettings;
  794. begin
  795. GetlocaleFormatSettings(GetThreadLocale, DefaultFormatSettings);
  796. end;
  797. Procedure InitInternational;
  798. var
  799. { A call to GetSystemMetrics changes the value of the 8087 Control Word on
  800. Pentium4 with WinXP SP2 }
  801. old8087CW: word;
  802. DefaultCustomLocaleID : LCID; // typedef DWORD LCID;
  803. DefaultCustomLanguageID : Word; // typedef WORD LANGID;
  804. begin
  805. /// workaround for Windows 7 bug, see bug report #18574
  806. SetThreadLocale(GetUserDefaultLCID);
  807. InitInternationalGeneric;
  808. old8087CW:=Get8087CW;
  809. SysLocale.MBCS:=GetSystemMetrics(SM_DBCSENABLED)<>0;
  810. SysLocale.RightToLeft:=GetSystemMetrics(SM_MIDEASTENABLED)<>0;
  811. SysLocale.DefaultLCID := $0409;
  812. SysLocale.PriLangID := LANG_ENGLISH;
  813. SysLocale.SubLangID := SUBLANG_ENGLISH_US;
  814. // probably needs update with getthreadlocale. post 2.0.2
  815. DefaultCustomLocaleID := GetThreadLocale;
  816. if DefaultCustomLocaleID <> 0 then
  817. begin
  818. { Locale Identifiers
  819. +-------------+---------+-------------------------+
  820. | Reserved | Sort ID | Language ID |
  821. +-------------+---------+-------------------------+
  822. 31 20 19 16 15 0 bit }
  823. DefaultCustomLanguageID := DefaultCustomLocaleID and $FFFF; // 2^16
  824. if DefaultCustomLanguageID <> 0 then
  825. begin
  826. SysLocale.DefaultLCID := DefaultCustomLocaleID;
  827. { Language Identifiers
  828. +-------------------------+-------------------------+
  829. | SubLanguage ID | Primary Language ID |
  830. +-------------------------+-------------------------+
  831. 15 10 9 0 bit }
  832. SysLocale.PriLangID := DefaultCustomLanguageID and $3ff; // 2^10
  833. SysLocale.SubLangID := DefaultCustomLanguageID shr 10;
  834. end;
  835. end;
  836. Set8087CW(old8087CW);
  837. GetFormatSettings;
  838. if SysLocale.FarEast then GetEraNamesAndYearOffsets;
  839. end;
  840. {****************************************************************************
  841. Target Dependent
  842. ****************************************************************************}
  843. function SysErrorMessage(ErrorCode: Integer): String;
  844. const
  845. MaxMsgSize = Format_Message_Max_Width_Mask;
  846. var
  847. MsgBuffer: unicodestring;
  848. len: longint;
  849. begin
  850. SetLength(MsgBuffer, MaxMsgSize);
  851. len := FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
  852. nil,
  853. ErrorCode,
  854. MakeLangId(LANG_NEUTRAL, SUBLANG_DEFAULT),
  855. PUnicodeChar(MsgBuffer),
  856. MaxMsgSize,
  857. nil);
  858. // Remove trailing #13#10
  859. if (len > 1) and (MsgBuffer[len - 1] = #13) and (MsgBuffer[len] = #10) then
  860. Dec(len, 2);
  861. SetLength(MsgBuffer, len);
  862. Result := MsgBuffer;
  863. end;
  864. {****************************************************************************
  865. Initialization code
  866. ****************************************************************************}
  867. {$push}
  868. { GetEnvironmentStrings cannot be checked by CheckPointer function }
  869. {$checkpointer off}
  870. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  871. var
  872. oemenvvar, oemstr : RawByteString;
  873. i, hplen : longint;
  874. hp,p : pchar;
  875. begin
  876. oemenvvar:=uppercase(envvar);
  877. SetCodePage(oemenvvar,CP_OEMCP);
  878. Result:='';
  879. p:=GetEnvironmentStringsA;
  880. hp:=p;
  881. while hp^<>#0 do
  882. begin
  883. oemstr:=hp;
  884. { cache length, may change after uppercasing depending on code page }
  885. hplen:=length(oemstr);
  886. { all environment variables are encoded in the oem code page }
  887. SetCodePage(oemstr,CP_OEMCP,false);
  888. i:=pos('=',oemstr);
  889. if uppercase(copy(oemstr,1,i-1))=oemenvvar then
  890. begin
  891. Result:=copy(oemstr,i+1,length(oemstr)-i);
  892. break;
  893. end;
  894. { next string entry}
  895. hp:=hp+hplen+1;
  896. end;
  897. FreeEnvironmentStringsA(p);
  898. end;
  899. Function GetEnvironmentVariable(Const EnvVar : UnicodeString) : UnicodeString;
  900. var
  901. s, upperenv : Unicodestring;
  902. i : longint;
  903. hp,p : pwidechar;
  904. begin
  905. Result:='';
  906. p:=GetEnvironmentStringsW;
  907. hp:=p;
  908. upperenv:=uppercase(envvar);
  909. while hp^<>#0 do
  910. begin
  911. s:=hp;
  912. i:=pos('=',s);
  913. if uppercase(copy(s,1,i-1))=upperenv then
  914. begin
  915. Result:=copy(s,i+1,length(s)-i);
  916. break;
  917. end;
  918. { next string entry}
  919. hp:=hp+strlen(hp)+1;
  920. end;
  921. FreeEnvironmentStringsW(p);
  922. end;
  923. Function GetEnvironmentVariableCount : Integer;
  924. var
  925. hp,p : pchar;
  926. begin
  927. Result:=0;
  928. p:=GetEnvironmentStringsA;
  929. hp:=p;
  930. If (Hp<>Nil) then
  931. while hp^<>#0 do
  932. begin
  933. Inc(Result);
  934. hp:=hp+strlen(hp)+1;
  935. end;
  936. FreeEnvironmentStringsA(p);
  937. end;
  938. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  939. var
  940. hp,p : pchar;
  941. {$ifdef FPC_RTL_UNICODE}
  942. tmpstr : RawByteString;
  943. {$endif}
  944. begin
  945. Result:='';
  946. p:=GetEnvironmentStringsA;
  947. hp:=p;
  948. If (Hp<>Nil) then
  949. begin
  950. while (hp^<>#0) and (Index>1) do
  951. begin
  952. Dec(Index);
  953. hp:=hp+strlen(hp)+1;
  954. end;
  955. If (hp^<>#0) then
  956. begin
  957. {$ifdef FPC_RTL_UNICODE}
  958. tmpstr:=hp;
  959. SetCodePage(tmpstr,CP_OEMCP,false);
  960. Result:=tmpstr;
  961. {$else}
  962. Result:=hp;
  963. SetCodePage(RawByteString(Result),CP_OEMCP,false);
  964. {$endif}
  965. end;
  966. end;
  967. FreeEnvironmentStringsA(p);
  968. end;
  969. {$pop}
  970. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
  971. // win specific function
  972. var
  973. SI: TStartupInfo;
  974. PI: TProcessInformation;
  975. Proc : THandle;
  976. l : DWord;
  977. CommandLine : ansistring;
  978. e : EOSError;
  979. ExecInherits : longbool;
  980. begin
  981. FillChar(SI, SizeOf(SI), 0);
  982. SI.cb:=SizeOf(SI);
  983. SI.wShowWindow:=1;
  984. { always surround the name of the application by quotes
  985. so that long filenames will always be accepted. But don't
  986. do it if there are already double quotes, since Win32 does not
  987. like double quotes which are duplicated!
  988. }
  989. if pos('"',path)=0 then
  990. CommandLine:='"'+path+'"'
  991. else
  992. CommandLine:=path;
  993. if ComLine <> '' then
  994. CommandLine:=Commandline+' '+ComLine+#0
  995. else
  996. CommandLine := CommandLine + #0;
  997. ExecInherits:=ExecInheritsHandles in Flags;
  998. if not CreateProcessA(nil, pchar(CommandLine),
  999. Nil, Nil, ExecInherits,$20, Nil, Nil, SI, PI) then
  1000. begin
  1001. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
  1002. e.ErrorCode:=GetLastError;
  1003. raise e;
  1004. end;
  1005. Proc:=PI.hProcess;
  1006. if WaitForSingleObject(Proc, dword($ffffffff)) <> $ffffffff then
  1007. begin
  1008. GetExitCodeProcess(Proc,l);
  1009. CloseHandle(Proc);
  1010. CloseHandle(PI.hThread);
  1011. result:=l;
  1012. end
  1013. else
  1014. begin
  1015. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
  1016. e.ErrorCode:=GetLastError;
  1017. CloseHandle(Proc);
  1018. CloseHandle(PI.hThread);
  1019. raise e;
  1020. end;
  1021. end;
  1022. function ExecuteProcess(Const Path: AnsiString; Const ComLine: Array of AnsiString;Flags:TExecuteFlags=[]):integer;
  1023. var
  1024. CommandLine: AnsiString;
  1025. I: integer;
  1026. begin
  1027. Commandline := '';
  1028. for I := 0 to High (ComLine) do
  1029. if Pos (' ', ComLine [I]) <> 0 then
  1030. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  1031. else
  1032. CommandLine := CommandLine + ' ' + Comline [I];
  1033. ExecuteProcess := ExecuteProcess (Path, CommandLine,Flags);
  1034. end;
  1035. Procedure Sleep(Milliseconds : Cardinal);
  1036. begin
  1037. Windows.Sleep(MilliSeconds)
  1038. end;
  1039. Function GetLastOSError : Integer;
  1040. begin
  1041. Result:=GetLastError;
  1042. end;
  1043. {****************************************************************************
  1044. Initialization code
  1045. ****************************************************************************}
  1046. var
  1047. kernel32dll : THandle;
  1048. Procedure LoadVersionInfo;
  1049. // and getfreespaceex
  1050. Var
  1051. versioninfo : TOSVERSIONINFO;
  1052. begin
  1053. GetDiskFreeSpaceEx:=nil;
  1054. versioninfo.dwOSVersionInfoSize:=sizeof(versioninfo);
  1055. GetVersionEx(versioninfo);
  1056. Win32Platform:=versionInfo.dwPlatformId;
  1057. Win32MajorVersion:=versionInfo.dwMajorVersion;
  1058. Win32MinorVersion:=versionInfo.dwMinorVersion;
  1059. Win32BuildNumber:=versionInfo.dwBuildNumber;
  1060. Move (versioninfo.szCSDVersion ,Win32CSDVersion[1],128);
  1061. win32CSDVersion[0]:=chr(strlen(pchar(@versioninfo.szCSDVersion)));
  1062. kernel32dll:=GetModuleHandle('kernel32');
  1063. if kernel32dll<>0 then
  1064. GetDiskFreeSpaceEx:=TGetDiskFreeSpaceEx(GetProcAddress(kernel32dll,'GetDiskFreeSpaceExA'));
  1065. end;
  1066. Function GetAppConfigDir(Global : Boolean) : String;
  1067. begin
  1068. If Global then
  1069. Result:=GetWindowsSpecialDir(CSIDL_COMMON_APPDATA)
  1070. else
  1071. Result:=GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA);
  1072. If (Result<>'') then
  1073. begin
  1074. if VendorName<>'' then
  1075. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  1076. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  1077. end
  1078. else
  1079. Result:=IncludeTrailingPathDelimiter(DGetAppConfigDir(Global));
  1080. end;
  1081. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  1082. begin
  1083. result:=DGetAppConfigFile(Global,SubDir);
  1084. end;
  1085. Function GetUserDir : String;
  1086. begin
  1087. Result:=GetWindowsSpecialDir(CSIDL_PROFILE);
  1088. end;
  1089. Procedure InitSysConfigDir;
  1090. begin
  1091. SetLength(SysConfigDir, MAX_PATH);
  1092. SetLength(SysConfigDir, GetWindowsDirectoryA(PChar(SysConfigDir), MAX_PATH));
  1093. end;
  1094. {****************************************************************************
  1095. Target Dependent WideString stuff
  1096. ****************************************************************************}
  1097. { This is the case of Win9x. Limited to current locale of course, but it's better
  1098. than not working at all. }
  1099. function DoCompareStringA(P1, P2: PWideChar; L1, L2: PtrUInt; Flags: DWORD): PtrInt;
  1100. var
  1101. a1, a2: AnsiString;
  1102. begin
  1103. if L1>0 then
  1104. widestringmanager.Wide2AnsiMoveProc(P1,a1,DefaultSystemCodePage,L1);
  1105. if L2>0 then
  1106. widestringmanager.Wide2AnsiMoveProc(P2,a2,DefaultSystemCodePage,L2);
  1107. SetLastError(0);
  1108. Result:=CompareStringA(LOCALE_USER_DEFAULT,Flags,pchar(a1),
  1109. length(a1),pchar(a2),length(a2))-2;
  1110. end;
  1111. function DoCompareStringW(P1, P2: PWideChar; L1, L2: PtrUInt; Flags: DWORD): PtrInt;
  1112. begin
  1113. SetLastError(0);
  1114. Result:=CompareStringW(LOCALE_USER_DEFAULT,Flags,P1,L1,P2,L2)-2;
  1115. if GetLastError=0 then
  1116. Exit;
  1117. if GetLastError=ERROR_CALL_NOT_IMPLEMENTED then // Win9x case
  1118. Result:=DoCompareStringA(P1, P2, L1, L2, Flags);
  1119. if GetLastError<>0 then
  1120. RaiseLastOSError;
  1121. end;
  1122. const
  1123. WinAPICompareFlags : array [TCompareOption] of LongWord
  1124. = (LINGUISTIC_IGNORECASE, LINGUISTIC_IGNOREDIACRITIC, NORM_IGNORECASE,
  1125. NORM_IGNOREKANATYPE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS, NORM_IGNOREWIDTH,
  1126. NORM_LINGUISTIC_CASING, SORT_DIGITSASNUMBERS, SORT_STRINGSORT);
  1127. function Win32CompareWideString(const s1, s2 : WideString; Options : TCompareOptions) : PtrInt;
  1128. Var
  1129. O : LongWord;
  1130. CO : TCompareOption;
  1131. begin
  1132. O:=0;
  1133. for CO in TCompareOption do
  1134. if CO in Options then
  1135. O:=O or WinAPICompareFlags[CO];
  1136. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), O);
  1137. end;
  1138. function Win32CompareTextWideString(const s1, s2 : WideString) : PtrInt;
  1139. begin
  1140. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), NORM_IGNORECASE);
  1141. end;
  1142. function Win32AnsiUpperCase(const s: string): string;
  1143. begin
  1144. if length(s)>0 then
  1145. begin
  1146. result:=s;
  1147. UniqueString(result);
  1148. CharUpperBuffA(pchar(result),length(result));
  1149. end
  1150. else
  1151. result:='';
  1152. end;
  1153. function Win32AnsiLowerCase(const s: string): string;
  1154. begin
  1155. if length(s)>0 then
  1156. begin
  1157. result:=s;
  1158. UniqueString(result);
  1159. CharLowerBuffA(pchar(result),length(result));
  1160. end
  1161. else
  1162. result:='';
  1163. end;
  1164. function Win32AnsiCompareStr(const S1, S2: string): PtrInt;
  1165. begin
  1166. result:=CompareStringA(LOCALE_USER_DEFAULT,0,pchar(s1),length(s1),
  1167. pchar(s2),length(s2))-2;
  1168. end;
  1169. function Win32AnsiCompareText(const S1, S2: string): PtrInt;
  1170. begin
  1171. result:=CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE,pchar(s1),length(s1),
  1172. pchar(s2),length(s2))-2;
  1173. end;
  1174. function Win32AnsiStrComp(S1, S2: PChar): PtrInt;
  1175. begin
  1176. result:=CompareStringA(LOCALE_USER_DEFAULT,0,s1,-1,s2,-1)-2;
  1177. end;
  1178. function Win32AnsiStrIComp(S1, S2: PChar): PtrInt;
  1179. begin
  1180. result:=CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE,s1,-1,s2,-1)-2;
  1181. end;
  1182. function Win32AnsiStrLComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  1183. begin
  1184. result:=CompareStringA(LOCALE_USER_DEFAULT,0,s1,maxlen,s2,maxlen)-2;
  1185. end;
  1186. function Win32AnsiStrLIComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  1187. begin
  1188. result:=CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE,s1,maxlen,s2,maxlen)-2;
  1189. end;
  1190. function Win32AnsiStrLower(Str: PChar): PChar;
  1191. begin
  1192. CharLowerA(str);
  1193. result:=str;
  1194. end;
  1195. function Win32AnsiStrUpper(Str: PChar): PChar;
  1196. begin
  1197. CharUpperA(str);
  1198. result:=str;
  1199. end;
  1200. function Win32CompareUnicodeString(const s1, s2 : UnicodeString; Options : TCompareOptions) : PtrInt;
  1201. Var
  1202. O : LongWord;
  1203. CO : TCompareOption;
  1204. begin
  1205. O:=0;
  1206. for CO in TCompareOption do
  1207. if CO in Options then
  1208. O:=O or WinAPICompareFlags[CO];
  1209. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), O);
  1210. end;
  1211. function Win32CompareTextUnicodeString(const s1, s2 : UnicodeString) : PtrInt;
  1212. begin
  1213. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), NORM_IGNORECASE);
  1214. end;
  1215. { there is a similiar procedure in the system unit which inits the fields which
  1216. are relevant already for the system unit }
  1217. procedure InitWin32Widestrings;
  1218. begin
  1219. { return value: number of code points in the string. Whenever an invalid
  1220. code point is encountered, all characters part of this invalid code point
  1221. are considered to form one "character" and the next character is
  1222. considered to be the start of a new (possibly also invalid) code point }
  1223. //!!! CharLengthPCharProc : function(const Str: PChar): PtrInt;
  1224. { return value:
  1225. -1 if incomplete or invalid code point
  1226. 0 if NULL character,
  1227. > 0 if that's the length in bytes of the code point }
  1228. //!!!! CodePointLengthProc : function(const Str: PChar; MaxLookAead: PtrInt): Ptrint;
  1229. widestringmanager.CompareWideStringProc:=@Win32CompareWideString;
  1230. widestringmanager.UpperAnsiStringProc:=@Win32AnsiUpperCase;
  1231. widestringmanager.LowerAnsiStringProc:=@Win32AnsiLowerCase;
  1232. widestringmanager.CompareStrAnsiStringProc:=@Win32AnsiCompareStr;
  1233. widestringmanager.CompareTextAnsiStringProc:=@Win32AnsiCompareText;
  1234. widestringmanager.StrCompAnsiStringProc:=@Win32AnsiStrComp;
  1235. widestringmanager.StrICompAnsiStringProc:=@Win32AnsiStrIComp;
  1236. widestringmanager.StrLCompAnsiStringProc:=@Win32AnsiStrLComp;
  1237. widestringmanager.StrLICompAnsiStringProc:=@Win32AnsiStrLIComp;
  1238. widestringmanager.StrLowerAnsiStringProc:=@Win32AnsiStrLower;
  1239. widestringmanager.StrUpperAnsiStringProc:=@Win32AnsiStrUpper;
  1240. widestringmanager.CompareUnicodeStringProc:=@Win32CompareUnicodeString;
  1241. end;
  1242. { Platform-specific exception support }
  1243. function WinExceptionObject(code: Longint; const rec: TExceptionRecord): Exception;
  1244. var
  1245. entry: PExceptMapEntry;
  1246. begin
  1247. entry := FindExceptMapEntry(code);
  1248. if assigned(entry) then
  1249. result:=entry^.cls.CreateRes(entry^.msg)
  1250. else
  1251. result:=EExternalException.CreateResFmt(@SExternalException,[rec.ExceptionCode]);
  1252. if result is EExternal then
  1253. EExternal(result).FExceptionRecord:=rec;
  1254. end;
  1255. function WinExceptionClass(code: longint): ExceptClass;
  1256. var
  1257. entry: PExceptMapEntry;
  1258. begin
  1259. entry := FindExceptMapEntry(code);
  1260. if assigned(entry) then
  1261. result:=entry^.cls
  1262. else
  1263. result:=EExternalException;
  1264. end;
  1265. Initialization
  1266. InitWin32Widestrings;
  1267. InitExceptions; { Initialize exceptions. OS independent }
  1268. {$ifdef mswindows} { Keeps exe size down for systems that do not use SEH }
  1269. ExceptObjProc:=@WinExceptionObject;
  1270. ExceptClsProc:=@WinExceptionClass;
  1271. {$endif mswindows}
  1272. InitInternational; { Initialize internationalization settings }
  1273. LoadVersionInfo;
  1274. InitSysConfigDir;
  1275. OnBeep:=@SysBeep;
  1276. Finalization
  1277. DoneExceptions;
  1278. end.