sysutils.pp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273
  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. uses
  19. windows;
  20. {$DEFINE HAS_SLEEP}
  21. {$DEFINE HAS_OSERROR}
  22. {$DEFINE HAS_OSCONFIG}
  23. {$DEFINE HAS_OSUSERDIR}
  24. {$DEFINE HAS_CREATEGUID}
  25. { Include platform independent interface part }
  26. {$i sysutilh.inc}
  27. type
  28. TSystemTime = Windows.TSystemTime;
  29. EWin32Error = class(Exception)
  30. public
  31. ErrorCode : DWORD;
  32. end;
  33. Var
  34. Win32Platform : Longint;
  35. Win32MajorVersion,
  36. Win32MinorVersion,
  37. Win32BuildNumber : dword;
  38. Win32CSDVersion : ShortString; // CSD record is 128 bytes only?
  39. const
  40. MaxEraCount = 7;
  41. var
  42. EraNames: array [1..MaxEraCount] of String;
  43. EraYearOffsets: array [1..MaxEraCount] of Integer;
  44. { Compatibility with Delphi }
  45. function Win32Check(res:boolean):boolean;inline;
  46. function WinCheck(res:boolean):boolean;
  47. function CheckWin32Version(Major,Minor : Integer ): Boolean;
  48. function CheckWin32Version(Major : Integer): Boolean;
  49. Procedure RaiseLastWin32Error;
  50. function GetFileVersion(const AFileName: string): Cardinal;
  51. procedure GetFormatSettings;
  52. procedure GetLocaleFormatSettings(LCID: Integer; var FormatSettings: TFormatSettings); platform;
  53. implementation
  54. uses
  55. sysconst,
  56. windirs;
  57. function WinCheck(res:boolean):boolean;
  58. begin
  59. if not res then
  60. RaiseLastOSError;
  61. result:=res;
  62. end;
  63. function Win32Check(res:boolean):boolean;inline;
  64. begin
  65. result:=WinCheck(res);
  66. end;
  67. procedure RaiseLastWin32Error;
  68. begin
  69. RaiseLastOSError;
  70. end;
  71. function CheckWin32Version(Major : Integer): Boolean;
  72. begin
  73. Result:=CheckWin32Version(Major,0)
  74. end;
  75. function CheckWin32Version(Major,Minor: Integer): Boolean;
  76. begin
  77. Result:=(Win32MajorVersion>dword(Major)) or
  78. ((Win32MajorVersion=dword(Major)) and (Win32MinorVersion>=dword(Minor)));
  79. end;
  80. function GetFileVersion(const AFileName:string):Cardinal;
  81. var
  82. { useful only as long as we don't need to touch different stack pages }
  83. buf : array[0..3071] of byte;
  84. bufp : pointer;
  85. fn : string;
  86. valsize,
  87. size : DWORD;
  88. h : DWORD;
  89. valrec : PVSFixedFileInfo;
  90. begin
  91. result:=$fffffff;
  92. fn:=AFileName;
  93. UniqueString(fn);
  94. size:=GetFileVersionInfoSize(pchar(fn),@h);
  95. if size>sizeof(buf) then
  96. begin
  97. getmem(bufp,size);
  98. try
  99. if GetFileVersionInfo(pchar(fn),h,size,bufp) then
  100. if VerQueryValue(bufp,'\',valrec,valsize) then
  101. result:=valrec^.dwFileVersionMS;
  102. finally
  103. freemem(bufp);
  104. end;
  105. end
  106. else
  107. begin
  108. if GetFileVersionInfo(pchar(fn),h,size,@buf) then
  109. if VerQueryValue(@buf,'\',valrec,valsize) then
  110. result:=valrec^.dwFileVersionMS;
  111. end;
  112. end;
  113. {$define HASCREATEGUID}
  114. {$define HASEXPANDUNCFILENAME}
  115. {$DEFINE FPC_NOGENERICANSIROUTINES}
  116. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  117. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  118. function ConvertEraYearString(Count ,Year,Month,Day : integer) : string; forward;
  119. function ConvertEraString(Count ,Year,Month,Day : integer) : string; forward;
  120. { Include platform independent implementation part }
  121. {$i sysutils.inc}
  122. function GetTempFileName(Dir,Prefix: PChar; uUnique: DWORD; TempFileName: PChar):DWORD;
  123. begin
  124. Result:= Windows.GetTempFileNameA(Dir,Prefix,uUnique,TempFileName);
  125. end;
  126. { UUID generation. }
  127. function CoCreateGuid(out guid: TGUID): HResult; stdcall; external 'ole32.dll' name 'CoCreateGuid';
  128. function SysCreateGUID(out Guid: TGUID): Integer;
  129. begin
  130. Result := Integer(CoCreateGuid(Guid));
  131. end;
  132. function ExpandUNCFileName (const filename:string) : string;
  133. { returns empty string on errors }
  134. var
  135. s : ansistring;
  136. size : dword;
  137. rc : dword;
  138. buf : pchar;
  139. begin
  140. s := ExpandFileName (filename);
  141. s := s + #0;
  142. size := max_path;
  143. getmem(buf,size);
  144. try
  145. rc := WNetGetUniversalName (pchar(s), UNIVERSAL_NAME_INFO_LEVEL, buf, @size);
  146. if rc=ERROR_MORE_DATA then
  147. begin
  148. buf:=reallocmem(buf,size);
  149. rc := WNetGetUniversalName (pchar(s), UNIVERSAL_NAME_INFO_LEVEL, buf, @size);
  150. end;
  151. if rc = NO_ERROR then
  152. Result := PRemoteNameInfo(buf)^.lpUniversalName
  153. else if rc = ERROR_NOT_CONNECTED then
  154. Result := filename
  155. else
  156. Result := '';
  157. finally
  158. freemem(buf);
  159. end;
  160. end;
  161. {****************************************************************************
  162. File Functions
  163. ****************************************************************************}
  164. Function FileOpen (Const FileName : string; Mode : Integer) : THandle;
  165. const
  166. AccessMode: array[0..2] of Cardinal = (
  167. GENERIC_READ,
  168. GENERIC_WRITE,
  169. GENERIC_READ or GENERIC_WRITE);
  170. ShareMode: array[0..4] of Integer = (
  171. 0,
  172. 0,
  173. FILE_SHARE_READ,
  174. FILE_SHARE_WRITE,
  175. FILE_SHARE_READ or FILE_SHARE_WRITE);
  176. begin
  177. result := CreateFile(PChar(FileName), dword(AccessMode[Mode and 3]),
  178. dword(ShareMode[(Mode and $F0) shr 4]), nil, OPEN_EXISTING,
  179. FILE_ATTRIBUTE_NORMAL, 0);
  180. //if fail api return feInvalidHandle (INVALIDE_HANDLE=feInvalidHandle=-1)
  181. end;
  182. Function FileCreate (Const FileName : String) : THandle;
  183. begin
  184. Result := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE,
  185. 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  186. end;
  187. Function FileCreate (Const FileName : String; Mode:longint) : THandle;
  188. begin
  189. FileCreate:=FileCreate(FileName);
  190. end;
  191. Function FileRead (Handle : THandle; out Buffer; Count : longint) : Longint;
  192. Var
  193. res : dword;
  194. begin
  195. if ReadFile(Handle, Buffer, Count, res, nil) then
  196. FileRead:=Res
  197. else
  198. FileRead:=-1;
  199. end;
  200. Function FileWrite (Handle : THandle; const Buffer; Count : Longint) : Longint;
  201. Var
  202. Res : dword;
  203. begin
  204. if WriteFile(Handle, Buffer, Count, Res, nil) then
  205. FileWrite:=Res
  206. else
  207. FileWrite:=-1;
  208. end;
  209. Function FileSeek (Handle : THandle;FOffset,Origin : Longint) : Longint;
  210. begin
  211. Result := longint(SetFilePointer(Handle, FOffset, nil, Origin));
  212. end;
  213. Function FileSeek (Handle : THandle; FOffset: Int64; Origin: Longint) : Int64;
  214. var
  215. rslt: Int64Rec;
  216. begin
  217. rslt := Int64Rec(FOffset);
  218. rslt.lo := SetFilePointer(Handle, rslt.lo, @rslt.hi, Origin);
  219. if (rslt.lo = $FFFFFFFF) and (GetLastError <> 0) then
  220. rslt.hi := $FFFFFFFF;
  221. Result := Int64(rslt);
  222. end;
  223. Procedure FileClose (Handle : THandle);
  224. begin
  225. if Handle<=4 then
  226. exit;
  227. CloseHandle(Handle);
  228. end;
  229. Function FileTruncate (Handle : THandle;Size: Int64) : boolean;
  230. begin
  231. {
  232. Result:=longint(SetFilePointer(handle,Size,nil,FILE_BEGIN))<>-1;
  233. }
  234. if FileSeek (Handle, Size, FILE_BEGIN) = Size then
  235. Result:=SetEndOfFile(handle)
  236. else
  237. Result := false;
  238. end;
  239. Function DosToWinTime (DTime:longint;Var Wtime : TFileTime):longbool;
  240. var
  241. lft : TFileTime;
  242. begin
  243. DosToWinTime:=DosDateTimeToFileTime(longrec(dtime).hi,longrec(dtime).lo,@lft) and
  244. LocalFileTimeToFileTime(lft,Wtime);
  245. end;
  246. Function WinToDosTime (Var Wtime : TFileTime;var DTime:longint):longbool;
  247. var
  248. lft : TFileTime;
  249. begin
  250. WinToDosTime:=FileTimeToLocalFileTime(WTime,lft) and
  251. FileTimeToDosDateTime(lft,Longrec(Dtime).Hi,LongRec(DTIME).lo);
  252. end;
  253. Function FileAge (Const FileName : String): Longint;
  254. var
  255. Handle: THandle;
  256. FindData: TWin32FindData;
  257. begin
  258. Handle := FindFirstFile(Pchar(FileName), FindData);
  259. if Handle <> INVALID_HANDLE_VALUE then
  260. begin
  261. Windows.FindClose(Handle);
  262. if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
  263. If WinToDosTime(FindData.ftLastWriteTime,Result) then
  264. exit;
  265. end;
  266. Result := -1;
  267. end;
  268. Function FileExists (Const FileName : String) : Boolean;
  269. var
  270. Attr:Dword;
  271. begin
  272. Attr:=GetFileAttributes(PChar(FileName));
  273. if Attr <> $ffffffff then
  274. Result:= (Attr and FILE_ATTRIBUTE_DIRECTORY) = 0
  275. else
  276. Result:=False;
  277. end;
  278. Function DirectoryExists (Const Directory : String) : Boolean;
  279. var
  280. Attr:Dword;
  281. begin
  282. Attr:=GetFileAttributes(PChar(Directory));
  283. if Attr <> $ffffffff then
  284. Result:= (Attr and FILE_ATTRIBUTE_DIRECTORY) > 0
  285. else
  286. Result:=False;
  287. end;
  288. Function FindMatch(var f: TSearchRec) : Longint;
  289. begin
  290. { Find file with correct attribute }
  291. While (F.FindData.dwFileAttributes and cardinal(F.ExcludeAttr))<>0 do
  292. begin
  293. if not FindNextFile (F.FindHandle,F.FindData) then
  294. begin
  295. Result:=GetLastError;
  296. exit;
  297. end;
  298. end;
  299. { Convert some attributes back }
  300. WinToDosTime(F.FindData.ftLastWriteTime,F.Time);
  301. f.size:=F.FindData.NFileSizeLow+(qword(maxdword)+1)*F.FindData.NFileSizeHigh;
  302. f.attr:=F.FindData.dwFileAttributes;
  303. f.Name:=StrPas(@F.FindData.cFileName[0]);
  304. Result:=0;
  305. end;
  306. Function FindFirst (Const Path : String; Attr : Longint; out Rslt : TSearchRec) : Longint;
  307. begin
  308. Rslt.Name:=Path;
  309. Rslt.Attr:=attr;
  310. Rslt.ExcludeAttr:=(not Attr) and ($1e);
  311. { $1e = faHidden or faSysFile or faVolumeID or faDirectory }
  312. { FindFirstFile is a Win32 Call }
  313. Rslt.FindHandle:=FindFirstFile (PChar(Path),Rslt.FindData);
  314. If Rslt.FindHandle=Invalid_Handle_value then
  315. begin
  316. Result:=GetLastError;
  317. exit;
  318. end;
  319. { Find file with correct attribute }
  320. Result:=FindMatch(Rslt);
  321. end;
  322. Function FindNext (Var Rslt : TSearchRec) : Longint;
  323. begin
  324. if FindNextFile(Rslt.FindHandle, Rslt.FindData) then
  325. Result := FindMatch(Rslt)
  326. else
  327. Result := GetLastError;
  328. end;
  329. Procedure FindClose (Var F : TSearchrec);
  330. begin
  331. if F.FindHandle <> INVALID_HANDLE_VALUE then
  332. Windows.FindClose(F.FindHandle);
  333. end;
  334. Function FileGetDate (Handle : THandle) : Longint;
  335. Var
  336. FT : TFileTime;
  337. begin
  338. If GetFileTime(Handle,nil,nil,@ft) and
  339. WinToDosTime(FT,Result) then
  340. exit;
  341. Result:=-1;
  342. end;
  343. Function FileSetDate (Handle : THandle;Age : Longint) : Longint;
  344. Var
  345. FT: TFileTime;
  346. begin
  347. Result := 0;
  348. if DosToWinTime(Age,FT) and
  349. SetFileTime(Handle, nil, nil, @FT) then
  350. Exit;
  351. Result := GetLastError;
  352. end;
  353. Function FileGetAttr (Const FileName : String) : Longint;
  354. begin
  355. Result:=GetFileAttributes(PChar(FileName));
  356. end;
  357. Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
  358. begin
  359. if SetFileAttributes(PChar(FileName), Attr) then
  360. Result:=0
  361. else
  362. Result := GetLastError;
  363. end;
  364. Function DeleteFile (Const FileName : String) : Boolean;
  365. begin
  366. Result:=Windows.DeleteFile(Pchar(FileName));
  367. end;
  368. Function RenameFile (Const OldName, NewName : String) : Boolean;
  369. begin
  370. Result := MoveFile(PChar(OldName), PChar(NewName));
  371. end;
  372. {****************************************************************************
  373. Disk Functions
  374. ****************************************************************************}
  375. type
  376. TGetDiskFreeSpaceEx = function(drive:pchar;var availableforcaller,total,free):longbool;stdcall;
  377. var
  378. GetDiskFreeSpaceEx : TGetDiskFreeSpaceEx;
  379. function diskfree(drive : byte) : int64;
  380. var
  381. disk : array[1..4] of char;
  382. secs,bytes,
  383. free,total : dword;
  384. qwtotal,qwfree,qwcaller : int64;
  385. begin
  386. if drive=0 then
  387. begin
  388. disk[1]:='\';
  389. disk[2]:=#0;
  390. end
  391. else
  392. begin
  393. disk[1]:=chr(drive+64);
  394. disk[2]:=':';
  395. disk[3]:='\';
  396. disk[4]:=#0;
  397. end;
  398. if assigned(GetDiskFreeSpaceEx) then
  399. begin
  400. if GetDiskFreeSpaceEx(@disk[1],qwcaller,qwtotal,qwfree) then
  401. diskfree:=qwfree
  402. else
  403. diskfree:=-1;
  404. end
  405. else
  406. begin
  407. if GetDiskFreeSpace(@disk[1],secs,bytes,free,total) then
  408. diskfree:=int64(free)*secs*bytes
  409. else
  410. diskfree:=-1;
  411. end;
  412. end;
  413. function disksize(drive : byte) : int64;
  414. var
  415. disk : array[1..4] of char;
  416. secs,bytes,
  417. free,total : dword;
  418. qwtotal,qwfree,qwcaller : int64;
  419. begin
  420. if drive=0 then
  421. begin
  422. disk[1]:='\';
  423. disk[2]:=#0;
  424. end
  425. else
  426. begin
  427. disk[1]:=chr(drive+64);
  428. disk[2]:=':';
  429. disk[3]:='\';
  430. disk[4]:=#0;
  431. end;
  432. if assigned(GetDiskFreeSpaceEx) then
  433. begin
  434. if GetDiskFreeSpaceEx(@disk[1],qwcaller,qwtotal,qwfree) then
  435. disksize:=qwtotal
  436. else
  437. disksize:=-1;
  438. end
  439. else
  440. begin
  441. if GetDiskFreeSpace(@disk[1],secs,bytes,free,total) then
  442. disksize:=int64(total)*secs*bytes
  443. else
  444. disksize:=-1;
  445. end;
  446. end;
  447. Function GetCurrentDir : String;
  448. begin
  449. GetDir(0, result);
  450. end;
  451. Function SetCurrentDir (Const NewDir : String) : Boolean;
  452. begin
  453. Result:=SetCurrentDirectory(PChar(NewDir));
  454. end;
  455. Function CreateDir (Const NewDir : String) : Boolean;
  456. begin
  457. Result:=CreateDirectory(PChar(NewDir),nil);
  458. end;
  459. Function RemoveDir (Const Dir : String) : Boolean;
  460. begin
  461. Result:=RemoveDirectory(PChar(Dir));
  462. end;
  463. {****************************************************************************
  464. Time Functions
  465. ****************************************************************************}
  466. Procedure GetLocalTime(var SystemTime: TSystemTime);
  467. begin
  468. windows.Getlocaltime(SystemTime);
  469. end;
  470. {****************************************************************************
  471. Misc Functions
  472. ****************************************************************************}
  473. procedure sysbeep;
  474. begin
  475. MessageBeep(0);
  476. end;
  477. {****************************************************************************
  478. Locale Functions
  479. ****************************************************************************}
  480. function GetLocaleStr(LID, LT: Longint; const Def: string): ShortString;
  481. var
  482. L: Integer;
  483. Buf: array[0..255] of Char;
  484. begin
  485. L := GetLocaleInfo(LID, LT, Buf, SizeOf(Buf));
  486. if L > 0 then
  487. SetString(Result, @Buf[0], L - 1)
  488. else
  489. Result := Def;
  490. end;
  491. function GetLocaleChar(LID, LT: Longint; Def: Char): Char;
  492. var
  493. Buf: array[0..3] of Char; // sdate allows 4 chars.
  494. begin
  495. if GetLocaleInfo(LID, LT, Buf, sizeof(buf)) > 0 then
  496. Result := Buf[0]
  497. else
  498. Result := Def;
  499. end;
  500. function ConvertEraString(Count ,Year,Month,Day : integer) : string;
  501. var
  502. ASystemTime: TSystemTime;
  503. buf: array[0..100] of char;
  504. ALCID : LCID;
  505. PriLangID : Word;
  506. SubLangID : Word;
  507. begin
  508. Result := ''; if (Count<=0) then exit;
  509. DateTimeToSystemTime(EncodeDate(Year,Month,Day),ASystemTime);
  510. ALCID := GetThreadLocale;
  511. // ALCID := SysLocale.DefaultLCID;
  512. if GetDateFormat(ALCID , DATE_USE_ALT_CALENDAR
  513. , @ASystemTime, PChar('gg')
  514. , @buf, SizeOf(buf)) > 0 then
  515. begin
  516. Result := buf;
  517. if Count = 1 then
  518. begin
  519. PriLangID := ALCID and $3FF;
  520. SubLangID := (ALCID and $FFFF) shr 10;
  521. case PriLangID of
  522. LANG_JAPANESE:
  523. begin
  524. Result := Copy(WideString(Result),1,1);
  525. end;
  526. LANG_CHINESE:
  527. if (SubLangID = SUBLANG_CHINESE_TRADITIONAL) then
  528. begin
  529. Result := Copy(WideString(Result),1,1);
  530. end;
  531. end;
  532. end;
  533. end;
  534. // if Result = '' then Result := StringOfChar('G',Count);
  535. end;
  536. function ConvertEraYearString(Count ,Year,Month,Day : integer) : string;
  537. var
  538. ALCID : LCID;
  539. ASystemTime : TSystemTime;
  540. AFormatText : string;
  541. buf : array[0..100] of Char;
  542. begin
  543. Result := '';
  544. DateTimeToSystemTime(EncodeDate(Year,Month,Day),ASystemTime);
  545. if Count <= 2 then
  546. AFormatText := 'yy'
  547. else
  548. AFormatText := 'yyyy';
  549. ALCID := GetThreadLocale;
  550. // ALCID := SysLocale.DefaultLCID;
  551. if GetDateFormat(ALCID, DATE_USE_ALT_CALENDAR
  552. , @ASystemTime, PChar(AFormatText)
  553. , @buf, SizeOf(buf)) > 0 then
  554. begin
  555. Result := buf;
  556. if (Count = 1) and (Result[1] = '0') then
  557. Result := Copy(Result, 2, Length(Result)-1);
  558. end;
  559. end;
  560. Function GetLocaleInt(LID,TP,Def: LongInt): LongInt;
  561. Var
  562. S: String;
  563. C: Integer;
  564. Begin
  565. S:=GetLocaleStr(LID,TP,'0');
  566. Val(S,Result,C);
  567. If C<>0 Then
  568. Result:=Def;
  569. End;
  570. function EnumEraNames(Names: PChar): WINBOOL; stdcall;
  571. var
  572. i : integer;
  573. begin
  574. Result := False;
  575. for i := Low(EraNames) to High(EraNames) do
  576. if (EraNames[i] = '') then
  577. begin
  578. EraNames[i] := Names;
  579. Result := True;
  580. break;
  581. end;
  582. end;
  583. function EnumEraYearOffsets(YearOffsets: PChar): WINBOOL; stdcall;
  584. var
  585. i : integer;
  586. begin
  587. Result := False;
  588. for i := Low(EraYearOffsets) to High(EraYearOffsets) do
  589. if (EraYearOffsets[i] = -1) then
  590. begin
  591. EraYearOffsets[i] := StrToIntDef(YearOffsets, 0);
  592. Result := True;
  593. break;
  594. end;
  595. end;
  596. procedure GetEraNamesAndYearOffsets;
  597. var
  598. ACALID : CALID;
  599. ALCID : LCID;
  600. buf : array[0..10] of char;
  601. i : integer;
  602. begin
  603. for i:= 1 to MaxEraCount do
  604. begin
  605. EraNames[i] := ''; EraYearOffsets[i] := -1;
  606. end;
  607. ALCID := GetThreadLocale;
  608. if GetLocaleInfo(ALCID , LOCALE_IOPTIONALCALENDAR, buf, sizeof(buf)) <= 0 then exit;
  609. ACALID := StrToIntDef(buf,1);
  610. if ACALID in [3..5] then
  611. begin
  612. EnumCalendarInfoA(@EnumEraNames, ALCID, ACALID , CAL_SERASTRING);
  613. EnumCalendarInfoA(@EnumEraYearOffsets, ALCID, ACALID, CAL_IYEAROFFSETRANGE);
  614. end;
  615. (*
  616. 1 CAL_GREGORIAN Gregorian (localized)
  617. 2 CAL_GREGORIAN_US Gregorian (English strings always)
  618. 3 CAL_JAPAN Japanese Emperor Era
  619. 4 CAL_TAIWAN Taiwan Calendar
  620. 5 CAL_KOREA Korean Tangun Era
  621. 6 CAL_HIJRI Hijri (Arabic Lunar)
  622. 7 CAL_THAI Thai
  623. 8 CAL_HEBREW Hebrew (Lunar)
  624. 9 CAL_GREGORIAN_ME_FRENCH Gregorian Middle East French
  625. 10 CAL_GREGORIAN_ARABIC Gregorian Arabic
  626. 11 CAL_GREGORIAN_XLIT_ENGLISH Gregorian transliterated English
  627. 12 CAL_GREGORIAN_XLIT_FRENCH Gregorian transliterated French
  628. 23 CAL_UMALQURA Windows Vista or later: Um Al Qura (Arabic lunar) calendar
  629. *)
  630. end;
  631. procedure GetLocaleFormatSettings(LCID: Integer; var FormatSettings: TFormatSettings);
  632. var
  633. HF : Shortstring;
  634. LID : Windows.LCID;
  635. I,Day : longint;
  636. begin
  637. LID := LCID;
  638. with FormatSettings do
  639. begin
  640. { Date stuff }
  641. for I := 1 to 12 do
  642. begin
  643. ShortMonthNames[I]:=GetLocaleStr(LID,LOCALE_SABBREVMONTHNAME1+I-1,ShortMonthNames[i]);
  644. LongMonthNames[I]:=GetLocaleStr(LID,LOCALE_SMONTHNAME1+I-1,LongMonthNames[i]);
  645. end;
  646. for I := 1 to 7 do
  647. begin
  648. Day := (I + 5) mod 7;
  649. ShortDayNames[I]:=GetLocaleStr(LID,LOCALE_SABBREVDAYNAME1+Day,ShortDayNames[i]);
  650. LongDayNames[I]:=GetLocaleStr(LID,LOCALE_SDAYNAME1+Day,LongDayNames[i]);
  651. end;
  652. DateSeparator := GetLocaleChar(LID, LOCALE_SDATE, '/');
  653. ShortDateFormat := GetLocaleStr(LID, LOCALE_SSHORTDATE, 'm/d/yy');
  654. LongDateFormat := GetLocaleStr(LID, LOCALE_SLONGDATE, 'mmmm d, yyyy');
  655. { Time stuff }
  656. TimeSeparator := GetLocaleChar(LID, LOCALE_STIME, ':');
  657. TimeAMString := GetLocaleStr(LID, LOCALE_S1159, 'AM');
  658. TimePMString := GetLocaleStr(LID, LOCALE_S2359, 'PM');
  659. if StrToIntDef(GetLocaleStr(LID, LOCALE_ITLZERO, '0'), 0) = 0 then
  660. HF:='h'
  661. else
  662. HF:='hh';
  663. // No support for 12 hour stuff at the moment...
  664. ShortTimeFormat := HF+':nn';
  665. LongTimeFormat := HF + ':nn:ss';
  666. { Currency stuff }
  667. CurrencyString:=GetLocaleStr(LID, LOCALE_SCURRENCY, '');
  668. CurrencyFormat:=StrToIntDef(GetLocaleStr(LID, LOCALE_ICURRENCY, '0'), 0);
  669. NegCurrFormat:=StrToIntDef(GetLocaleStr(LID, LOCALE_INEGCURR, '0'), 0);
  670. { Number stuff }
  671. ThousandSeparator:=GetLocaleChar(LID, LOCALE_STHOUSAND, ',');
  672. DecimalSeparator:=GetLocaleChar(LID, LOCALE_SDECIMAL, '.');
  673. CurrencyDecimals:=StrToIntDef(GetLocaleStr(LID, LOCALE_ICURRDIGITS, '0'), 0);
  674. end;
  675. end;
  676. procedure GetFormatSettings;
  677. begin
  678. GetlocaleFormatSettings(GetThreadLocale, DefaultFormatSettings);
  679. end;
  680. Procedure InitInternational;
  681. var
  682. { A call to GetSystemMetrics changes the value of the 8087 Control Word on
  683. Pentium4 with WinXP SP2 }
  684. old8087CW: word;
  685. DefaultCustomLocaleID : LCID; // typedef DWORD LCID;
  686. DefaultCustomLanguageID : Word; // typedef WORD LANGID;
  687. begin
  688. /// workaround for Windows 7 bug, see bug report #18574
  689. SetThreadLocale(GetUserDefaultLCID);
  690. InitInternationalGeneric;
  691. old8087CW:=Get8087CW;
  692. SysLocale.MBCS:=GetSystemMetrics(SM_DBCSENABLED)<>0;
  693. SysLocale.RightToLeft:=GetSystemMetrics(SM_MIDEASTENABLED)<>0;
  694. SysLocale.DefaultLCID := $0409;
  695. SysLocale.PriLangID := LANG_ENGLISH;
  696. SysLocale.SubLangID := SUBLANG_ENGLISH_US;
  697. // probably needs update with getthreadlocale. post 2.0.2
  698. DefaultCustomLocaleID := GetThreadLocale;
  699. if DefaultCustomLocaleID <> 0 then
  700. begin
  701. { Locale Identifiers
  702. +-------------+---------+-------------------------+
  703. | Reserved | Sort ID | Language ID |
  704. +-------------+---------+-------------------------+
  705. 31 20 19 16 15 0 bit }
  706. DefaultCustomLanguageID := DefaultCustomLocaleID and $FFFF; // 2^16
  707. if DefaultCustomLanguageID <> 0 then
  708. begin
  709. SysLocale.DefaultLCID := DefaultCustomLocaleID;
  710. { Language Identifiers
  711. +-------------------------+-------------------------+
  712. | SubLanguage ID | Primary Language ID |
  713. +-------------------------+-------------------------+
  714. 15 10 9 0 bit }
  715. SysLocale.PriLangID := DefaultCustomLanguageID and $3ff; // 2^10
  716. SysLocale.SubLangID := DefaultCustomLanguageID shr 10;
  717. end;
  718. end;
  719. Set8087CW(old8087CW);
  720. GetFormatSettings;
  721. if SysLocale.FarEast then GetEraNamesAndYearOffsets;
  722. end;
  723. {****************************************************************************
  724. Target Dependent
  725. ****************************************************************************}
  726. function SysErrorMessage(ErrorCode: Integer): String;
  727. const
  728. MaxMsgSize = Format_Message_Max_Width_Mask;
  729. var
  730. MsgBuffer: pChar;
  731. begin
  732. GetMem(MsgBuffer, MaxMsgSize);
  733. FillChar(MsgBuffer^, MaxMsgSize, #0);
  734. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
  735. nil,
  736. ErrorCode,
  737. MakeLangId(LANG_NEUTRAL, SUBLANG_DEFAULT),
  738. MsgBuffer, { This function allocs the memory }
  739. MaxMsgSize, { Maximum message size }
  740. nil);
  741. SysErrorMessage := StrPas(MsgBuffer);
  742. FreeMem(MsgBuffer, MaxMsgSize);
  743. end;
  744. {****************************************************************************
  745. Initialization code
  746. ****************************************************************************}
  747. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  748. var
  749. s : string;
  750. i : longint;
  751. hp,p : pchar;
  752. begin
  753. Result:='';
  754. p:=GetEnvironmentStrings;
  755. hp:=p;
  756. while hp^<>#0 do
  757. begin
  758. s:=strpas(hp);
  759. i:=pos('=',s);
  760. if uppercase(copy(s,1,i-1))=upcase(envvar) then
  761. begin
  762. Result:=copy(s,i+1,length(s)-i);
  763. break;
  764. end;
  765. { next string entry}
  766. hp:=hp+strlen(hp)+1;
  767. end;
  768. FreeEnvironmentStrings(p);
  769. end;
  770. Function GetEnvironmentVariableCount : Integer;
  771. var
  772. hp,p : pchar;
  773. begin
  774. Result:=0;
  775. p:=GetEnvironmentStrings;
  776. hp:=p;
  777. If (Hp<>Nil) then
  778. while hp^<>#0 do
  779. begin
  780. Inc(Result);
  781. hp:=hp+strlen(hp)+1;
  782. end;
  783. FreeEnvironmentStrings(p);
  784. end;
  785. Function GetEnvironmentString(Index : Integer) : String;
  786. var
  787. hp,p : pchar;
  788. begin
  789. Result:='';
  790. p:=GetEnvironmentStrings;
  791. hp:=p;
  792. If (Hp<>Nil) then
  793. begin
  794. while (hp^<>#0) and (Index>1) do
  795. begin
  796. Dec(Index);
  797. hp:=hp+strlen(hp)+1;
  798. end;
  799. If (hp^<>#0) then
  800. Result:=StrPas(HP);
  801. end;
  802. FreeEnvironmentStrings(p);
  803. end;
  804. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
  805. // win specific function
  806. var
  807. SI: TStartupInfo;
  808. PI: TProcessInformation;
  809. Proc : THandle;
  810. l : DWord;
  811. CommandLine : ansistring;
  812. e : EOSError;
  813. ExecInherits : longbool;
  814. begin
  815. FillChar(SI, SizeOf(SI), 0);
  816. SI.cb:=SizeOf(SI);
  817. SI.wShowWindow:=1;
  818. { always surround the name of the application by quotes
  819. so that long filenames will always be accepted. But don't
  820. do it if there are already double quotes, since Win32 does not
  821. like double quotes which are duplicated!
  822. }
  823. if pos('"',path)=0 then
  824. CommandLine:='"'+path+'"'
  825. else
  826. CommandLine:=path;
  827. if ComLine <> '' then
  828. CommandLine:=Commandline+' '+ComLine+#0
  829. else
  830. CommandLine := CommandLine + #0;
  831. ExecInherits:=ExecInheritsHandles in Flags;
  832. if not CreateProcess(nil, pchar(CommandLine),
  833. Nil, Nil, ExecInherits,$20, Nil, Nil, SI, PI) then
  834. begin
  835. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
  836. e.ErrorCode:=GetLastError;
  837. raise e;
  838. end;
  839. Proc:=PI.hProcess;
  840. if WaitForSingleObject(Proc, dword($ffffffff)) <> $ffffffff then
  841. begin
  842. GetExitCodeProcess(Proc,l);
  843. CloseHandle(Proc);
  844. CloseHandle(PI.hThread);
  845. result:=l;
  846. end
  847. else
  848. begin
  849. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
  850. e.ErrorCode:=GetLastError;
  851. CloseHandle(Proc);
  852. CloseHandle(PI.hThread);
  853. raise e;
  854. end;
  855. end;
  856. function ExecuteProcess(Const Path: AnsiString; Const ComLine: Array of AnsiString;Flags:TExecuteFlags=[]):integer;
  857. var
  858. CommandLine: AnsiString;
  859. I: integer;
  860. begin
  861. Commandline := '';
  862. for I := 0 to High (ComLine) do
  863. if Pos (' ', ComLine [I]) <> 0 then
  864. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  865. else
  866. CommandLine := CommandLine + ' ' + Comline [I];
  867. ExecuteProcess := ExecuteProcess (Path, CommandLine,Flags);
  868. end;
  869. Procedure Sleep(Milliseconds : Cardinal);
  870. begin
  871. Windows.Sleep(MilliSeconds)
  872. end;
  873. Function GetLastOSError : Integer;
  874. begin
  875. Result:=GetLastError;
  876. end;
  877. {****************************************************************************
  878. Initialization code
  879. ****************************************************************************}
  880. var
  881. kernel32dll : THandle;
  882. Procedure LoadVersionInfo;
  883. // and getfreespaceex
  884. Var
  885. versioninfo : TOSVERSIONINFO;
  886. begin
  887. GetDiskFreeSpaceEx:=nil;
  888. versioninfo.dwOSVersionInfoSize:=sizeof(versioninfo);
  889. GetVersionEx(versioninfo);
  890. Win32Platform:=versionInfo.dwPlatformId;
  891. Win32MajorVersion:=versionInfo.dwMajorVersion;
  892. Win32MinorVersion:=versionInfo.dwMinorVersion;
  893. Win32BuildNumber:=versionInfo.dwBuildNumber;
  894. Move (versioninfo.szCSDVersion ,Win32CSDVersion[1],128);
  895. win32CSDVersion[0]:=chr(strlen(pchar(@versioninfo.szCSDVersion)));
  896. kernel32dll:=GetModuleHandle('kernel32');
  897. if kernel32dll<>0 then
  898. GetDiskFreeSpaceEx:=TGetDiskFreeSpaceEx(GetProcAddress(kernel32dll,'GetDiskFreeSpaceExA'));
  899. end;
  900. Function GetAppConfigDir(Global : Boolean) : String;
  901. begin
  902. If Global then
  903. Result:=GetWindowsSpecialDir(CSIDL_COMMON_APPDATA)
  904. else
  905. Result:=GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA);
  906. If (Result<>'') then
  907. begin
  908. if VendorName<>'' then
  909. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  910. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  911. end
  912. else
  913. Result:=IncludeTrailingPathDelimiter(DGetAppConfigDir(Global));
  914. end;
  915. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  916. begin
  917. result:=DGetAppConfigFile(Global,SubDir);
  918. end;
  919. Function GetUserDir : String;
  920. begin
  921. Result:=GetWindowsSpecialDir(CSIDL_PROFILE);
  922. end;
  923. Procedure InitSysConfigDir;
  924. begin
  925. SetLength(SysConfigDir, MAX_PATH);
  926. SetLength(SysConfigDir, GetWindowsDirectory(PChar(SysConfigDir), MAX_PATH));
  927. end;
  928. {****************************************************************************
  929. Target Dependent WideString stuff
  930. ****************************************************************************}
  931. { This is the case of Win9x. Limited to current locale of course, but it's better
  932. than not working at all. }
  933. function DoCompareStringA(P1, P2: PWideChar; L1, L2: PtrUInt; Flags: DWORD): PtrInt;
  934. var
  935. a1, a2: AnsiString;
  936. begin
  937. if L1>0 then
  938. widestringmanager.Wide2AnsiMoveProc(P1,a1,L1);
  939. if L2>0 then
  940. widestringmanager.Wide2AnsiMoveProc(P2,a2,L2);
  941. SetLastError(0);
  942. Result:=CompareStringA(LOCALE_USER_DEFAULT,Flags,pchar(a1),
  943. length(a1),pchar(a2),length(a2))-2;
  944. end;
  945. function DoCompareStringW(P1, P2: PWideChar; L1, L2: PtrUInt; Flags: DWORD): PtrInt;
  946. begin
  947. SetLastError(0);
  948. Result:=CompareStringW(LOCALE_USER_DEFAULT,Flags,P1,L1,P2,L2)-2;
  949. if GetLastError=0 then
  950. Exit;
  951. if GetLastError=ERROR_CALL_NOT_IMPLEMENTED then // Win9x case
  952. Result:=DoCompareStringA(P1, P2, L1, L2, Flags);
  953. if GetLastError<>0 then
  954. RaiseLastOSError;
  955. end;
  956. function Win32CompareWideString(const s1, s2 : WideString) : PtrInt;
  957. begin
  958. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), 0);
  959. end;
  960. function Win32CompareTextWideString(const s1, s2 : WideString) : PtrInt;
  961. begin
  962. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), NORM_IGNORECASE);
  963. end;
  964. function Win32AnsiUpperCase(const s: string): string;
  965. begin
  966. if length(s)>0 then
  967. begin
  968. result:=s;
  969. UniqueString(result);
  970. CharUpperBuff(pchar(result),length(result));
  971. end
  972. else
  973. result:='';
  974. end;
  975. function Win32AnsiLowerCase(const s: string): string;
  976. begin
  977. if length(s)>0 then
  978. begin
  979. result:=s;
  980. UniqueString(result);
  981. CharLowerBuff(pchar(result),length(result));
  982. end
  983. else
  984. result:='';
  985. end;
  986. function Win32AnsiCompareStr(const S1, S2: string): PtrInt;
  987. begin
  988. result:=CompareString(LOCALE_USER_DEFAULT,0,pchar(s1),length(s1),
  989. pchar(s2),length(s2))-2;
  990. end;
  991. function Win32AnsiCompareText(const S1, S2: string): PtrInt;
  992. begin
  993. result:=CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE,pchar(s1),length(s1),
  994. pchar(s2),length(s2))-2;
  995. end;
  996. function Win32AnsiStrComp(S1, S2: PChar): PtrInt;
  997. begin
  998. result:=CompareString(LOCALE_USER_DEFAULT,0,s1,-1,s2,-1)-2;
  999. end;
  1000. function Win32AnsiStrIComp(S1, S2: PChar): PtrInt;
  1001. begin
  1002. result:=CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE,s1,-1,s2,-1)-2;
  1003. end;
  1004. function Win32AnsiStrLComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  1005. begin
  1006. result:=CompareString(LOCALE_USER_DEFAULT,0,s1,maxlen,s2,maxlen)-2;
  1007. end;
  1008. function Win32AnsiStrLIComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  1009. begin
  1010. result:=CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE,s1,maxlen,s2,maxlen)-2;
  1011. end;
  1012. function Win32AnsiStrLower(Str: PChar): PChar;
  1013. begin
  1014. CharLower(str);
  1015. result:=str;
  1016. end;
  1017. function Win32AnsiStrUpper(Str: PChar): PChar;
  1018. begin
  1019. CharUpper(str);
  1020. result:=str;
  1021. end;
  1022. function Win32CompareUnicodeString(const s1, s2 : UnicodeString) : PtrInt;
  1023. begin
  1024. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), 0);
  1025. end;
  1026. function Win32CompareTextUnicodeString(const s1, s2 : UnicodeString) : PtrInt;
  1027. begin
  1028. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), NORM_IGNORECASE);
  1029. end;
  1030. { there is a similiar procedure in the system unit which inits the fields which
  1031. are relevant already for the system unit }
  1032. procedure InitWin32Widestrings;
  1033. begin
  1034. { return value: number of code points in the string. Whenever an invalid
  1035. code point is encountered, all characters part of this invalid code point
  1036. are considered to form one "character" and the next character is
  1037. considered to be the start of a new (possibly also invalid) code point }
  1038. //!!! CharLengthPCharProc : function(const Str: PChar): PtrInt;
  1039. { return value:
  1040. -1 if incomplete or invalid code point
  1041. 0 if NULL character,
  1042. > 0 if that's the length in bytes of the code point }
  1043. //!!!! CodePointLengthProc : function(const Str: PChar; MaxLookAead: PtrInt): Ptrint;
  1044. widestringmanager.CompareWideStringProc:=@Win32CompareWideString;
  1045. widestringmanager.CompareTextWideStringProc:=@Win32CompareTextWideString;
  1046. widestringmanager.UpperAnsiStringProc:=@Win32AnsiUpperCase;
  1047. widestringmanager.LowerAnsiStringProc:=@Win32AnsiLowerCase;
  1048. widestringmanager.CompareStrAnsiStringProc:=@Win32AnsiCompareStr;
  1049. widestringmanager.CompareTextAnsiStringProc:=@Win32AnsiCompareText;
  1050. widestringmanager.StrCompAnsiStringProc:=@Win32AnsiStrComp;
  1051. widestringmanager.StrICompAnsiStringProc:=@Win32AnsiStrIComp;
  1052. widestringmanager.StrLCompAnsiStringProc:=@Win32AnsiStrLComp;
  1053. widestringmanager.StrLICompAnsiStringProc:=@Win32AnsiStrLIComp;
  1054. widestringmanager.StrLowerAnsiStringProc:=@Win32AnsiStrLower;
  1055. widestringmanager.StrUpperAnsiStringProc:=@Win32AnsiStrUpper;
  1056. widestringmanager.CompareUnicodeStringProc:=@Win32CompareUnicodeString;
  1057. widestringmanager.CompareTextUnicodeStringProc:=@Win32CompareTextUnicodeString;
  1058. end;
  1059. Initialization
  1060. InitWin32Widestrings;
  1061. InitExceptions; { Initialize exceptions. OS independent }
  1062. InitInternational; { Initialize internationalization settings }
  1063. LoadVersionInfo;
  1064. InitSysConfigDir;
  1065. OnBeep:=@SysBeep;
  1066. Finalization
  1067. DoneExceptions;
  1068. end.