sysutils.pp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271
  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. InitInternationalGeneric;
  689. old8087CW:=Get8087CW;
  690. SysLocale.MBCS:=GetSystemMetrics(SM_DBCSENABLED)<>0;
  691. SysLocale.RightToLeft:=GetSystemMetrics(SM_MIDEASTENABLED)<>0;
  692. SysLocale.DefaultLCID := $0409;
  693. SysLocale.PriLangID := LANG_ENGLISH;
  694. SysLocale.SubLangID := SUBLANG_ENGLISH_US;
  695. // probably needs update with getthreadlocale. post 2.0.2
  696. DefaultCustomLocaleID := GetThreadLocale;
  697. if DefaultCustomLocaleID <> 0 then
  698. begin
  699. { Locale Identifiers
  700. +-------------+---------+-------------------------+
  701. | Reserved | Sort ID | Language ID |
  702. +-------------+---------+-------------------------+
  703. 31 20 19 16 15 0 bit }
  704. DefaultCustomLanguageID := DefaultCustomLocaleID and $FFFF; // 2^16
  705. if DefaultCustomLanguageID <> 0 then
  706. begin
  707. SysLocale.DefaultLCID := DefaultCustomLocaleID;
  708. { Language Identifiers
  709. +-------------------------+-------------------------+
  710. | SubLanguage ID | Primary Language ID |
  711. +-------------------------+-------------------------+
  712. 15 10 9 0 bit }
  713. SysLocale.PriLangID := DefaultCustomLanguageID and $3ff; // 2^10
  714. SysLocale.SubLangID := DefaultCustomLanguageID shr 10;
  715. end;
  716. end;
  717. Set8087CW(old8087CW);
  718. GetFormatSettings;
  719. if SysLocale.FarEast then GetEraNamesAndYearOffsets;
  720. end;
  721. {****************************************************************************
  722. Target Dependent
  723. ****************************************************************************}
  724. function SysErrorMessage(ErrorCode: Integer): String;
  725. const
  726. MaxMsgSize = Format_Message_Max_Width_Mask;
  727. var
  728. MsgBuffer: pChar;
  729. begin
  730. GetMem(MsgBuffer, MaxMsgSize);
  731. FillChar(MsgBuffer^, MaxMsgSize, #0);
  732. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
  733. nil,
  734. ErrorCode,
  735. MakeLangId(LANG_NEUTRAL, SUBLANG_DEFAULT),
  736. MsgBuffer, { This function allocs the memory }
  737. MaxMsgSize, { Maximum message size }
  738. nil);
  739. SysErrorMessage := StrPas(MsgBuffer);
  740. FreeMem(MsgBuffer, MaxMsgSize);
  741. end;
  742. {****************************************************************************
  743. Initialization code
  744. ****************************************************************************}
  745. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  746. var
  747. s : string;
  748. i : longint;
  749. hp,p : pchar;
  750. begin
  751. Result:='';
  752. p:=GetEnvironmentStrings;
  753. hp:=p;
  754. while hp^<>#0 do
  755. begin
  756. s:=strpas(hp);
  757. i:=pos('=',s);
  758. if uppercase(copy(s,1,i-1))=upcase(envvar) then
  759. begin
  760. Result:=copy(s,i+1,length(s)-i);
  761. break;
  762. end;
  763. { next string entry}
  764. hp:=hp+strlen(hp)+1;
  765. end;
  766. FreeEnvironmentStrings(p);
  767. end;
  768. Function GetEnvironmentVariableCount : Integer;
  769. var
  770. hp,p : pchar;
  771. begin
  772. Result:=0;
  773. p:=GetEnvironmentStrings;
  774. hp:=p;
  775. If (Hp<>Nil) then
  776. while hp^<>#0 do
  777. begin
  778. Inc(Result);
  779. hp:=hp+strlen(hp)+1;
  780. end;
  781. FreeEnvironmentStrings(p);
  782. end;
  783. Function GetEnvironmentString(Index : Integer) : String;
  784. var
  785. hp,p : pchar;
  786. begin
  787. Result:='';
  788. p:=GetEnvironmentStrings;
  789. hp:=p;
  790. If (Hp<>Nil) then
  791. begin
  792. while (hp^<>#0) and (Index>1) do
  793. begin
  794. Dec(Index);
  795. hp:=hp+strlen(hp)+1;
  796. end;
  797. If (hp^<>#0) then
  798. Result:=StrPas(HP);
  799. end;
  800. FreeEnvironmentStrings(p);
  801. end;
  802. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
  803. // win specific function
  804. var
  805. SI: TStartupInfo;
  806. PI: TProcessInformation;
  807. Proc : THandle;
  808. l : DWord;
  809. CommandLine : ansistring;
  810. e : EOSError;
  811. ExecInherits : longbool;
  812. begin
  813. FillChar(SI, SizeOf(SI), 0);
  814. SI.cb:=SizeOf(SI);
  815. SI.wShowWindow:=1;
  816. { always surround the name of the application by quotes
  817. so that long filenames will always be accepted. But don't
  818. do it if there are already double quotes, since Win32 does not
  819. like double quotes which are duplicated!
  820. }
  821. if pos('"',path)=0 then
  822. CommandLine:='"'+path+'"'
  823. else
  824. CommandLine:=path;
  825. if ComLine <> '' then
  826. CommandLine:=Commandline+' '+ComLine+#0
  827. else
  828. CommandLine := CommandLine + #0;
  829. ExecInherits:=ExecInheritsHandles in Flags;
  830. if not CreateProcess(nil, pchar(CommandLine),
  831. Nil, Nil, ExecInherits,$20, Nil, Nil, SI, PI) then
  832. begin
  833. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
  834. e.ErrorCode:=GetLastError;
  835. raise e;
  836. end;
  837. Proc:=PI.hProcess;
  838. if WaitForSingleObject(Proc, dword($ffffffff)) <> $ffffffff then
  839. begin
  840. GetExitCodeProcess(Proc,l);
  841. CloseHandle(Proc);
  842. CloseHandle(PI.hThread);
  843. result:=l;
  844. end
  845. else
  846. begin
  847. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
  848. e.ErrorCode:=GetLastError;
  849. CloseHandle(Proc);
  850. CloseHandle(PI.hThread);
  851. raise e;
  852. end;
  853. end;
  854. function ExecuteProcess(Const Path: AnsiString; Const ComLine: Array of AnsiString;Flags:TExecuteFlags=[]):integer;
  855. var
  856. CommandLine: AnsiString;
  857. I: integer;
  858. begin
  859. Commandline := '';
  860. for I := 0 to High (ComLine) do
  861. if Pos (' ', ComLine [I]) <> 0 then
  862. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  863. else
  864. CommandLine := CommandLine + ' ' + Comline [I];
  865. ExecuteProcess := ExecuteProcess (Path, CommandLine,Flags);
  866. end;
  867. Procedure Sleep(Milliseconds : Cardinal);
  868. begin
  869. Windows.Sleep(MilliSeconds)
  870. end;
  871. Function GetLastOSError : Integer;
  872. begin
  873. Result:=GetLastError;
  874. end;
  875. {****************************************************************************
  876. Initialization code
  877. ****************************************************************************}
  878. var
  879. kernel32dll : THandle;
  880. Procedure LoadVersionInfo;
  881. // and getfreespaceex
  882. Var
  883. versioninfo : TOSVERSIONINFO;
  884. begin
  885. GetDiskFreeSpaceEx:=nil;
  886. versioninfo.dwOSVersionInfoSize:=sizeof(versioninfo);
  887. GetVersionEx(versioninfo);
  888. Win32Platform:=versionInfo.dwPlatformId;
  889. Win32MajorVersion:=versionInfo.dwMajorVersion;
  890. Win32MinorVersion:=versionInfo.dwMinorVersion;
  891. Win32BuildNumber:=versionInfo.dwBuildNumber;
  892. Move (versioninfo.szCSDVersion ,Win32CSDVersion[1],128);
  893. win32CSDVersion[0]:=chr(strlen(pchar(@versioninfo.szCSDVersion)));
  894. kernel32dll:=GetModuleHandle('kernel32');
  895. if kernel32dll<>0 then
  896. GetDiskFreeSpaceEx:=TGetDiskFreeSpaceEx(GetProcAddress(kernel32dll,'GetDiskFreeSpaceExA'));
  897. end;
  898. Function GetAppConfigDir(Global : Boolean) : String;
  899. begin
  900. If Global then
  901. Result:=GetWindowsSpecialDir(CSIDL_COMMON_APPDATA)
  902. else
  903. Result:=GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA);
  904. If (Result<>'') then
  905. begin
  906. if VendorName<>'' then
  907. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  908. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  909. end
  910. else
  911. Result:=IncludeTrailingPathDelimiter(DGetAppConfigDir(Global));
  912. end;
  913. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  914. begin
  915. result:=DGetAppConfigFile(Global,SubDir);
  916. end;
  917. Function GetUserDir : String;
  918. begin
  919. Result:=GetWindowsSpecialDir(CSIDL_PROFILE);
  920. end;
  921. Procedure InitSysConfigDir;
  922. begin
  923. SetLength(SysConfigDir, MAX_PATH);
  924. SetLength(SysConfigDir, GetWindowsDirectory(PChar(SysConfigDir), MAX_PATH));
  925. end;
  926. {****************************************************************************
  927. Target Dependent WideString stuff
  928. ****************************************************************************}
  929. { This is the case of Win9x. Limited to current locale of course, but it's better
  930. than not working at all. }
  931. function DoCompareStringA(P1, P2: PWideChar; L1, L2: PtrUInt; Flags: DWORD): PtrInt;
  932. var
  933. a1, a2: AnsiString;
  934. begin
  935. if L1>0 then
  936. widestringmanager.Wide2AnsiMoveProc(P1,a1,L1);
  937. if L2>0 then
  938. widestringmanager.Wide2AnsiMoveProc(P2,a2,L2);
  939. SetLastError(0);
  940. Result:=CompareStringA(LOCALE_USER_DEFAULT,Flags,pchar(a1),
  941. length(a1),pchar(a2),length(a2))-2;
  942. end;
  943. function DoCompareStringW(P1, P2: PWideChar; L1, L2: PtrUInt; Flags: DWORD): PtrInt;
  944. begin
  945. SetLastError(0);
  946. Result:=CompareStringW(LOCALE_USER_DEFAULT,Flags,P1,L1,P2,L2)-2;
  947. if GetLastError=0 then
  948. Exit;
  949. if GetLastError=ERROR_CALL_NOT_IMPLEMENTED then // Win9x case
  950. Result:=DoCompareStringA(P1, P2, L1, L2, Flags);
  951. if GetLastError<>0 then
  952. RaiseLastOSError;
  953. end;
  954. function Win32CompareWideString(const s1, s2 : WideString) : PtrInt;
  955. begin
  956. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), 0);
  957. end;
  958. function Win32CompareTextWideString(const s1, s2 : WideString) : PtrInt;
  959. begin
  960. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), NORM_IGNORECASE);
  961. end;
  962. function Win32AnsiUpperCase(const s: string): string;
  963. begin
  964. if length(s)>0 then
  965. begin
  966. result:=s;
  967. UniqueString(result);
  968. CharUpperBuff(pchar(result),length(result));
  969. end
  970. else
  971. result:='';
  972. end;
  973. function Win32AnsiLowerCase(const s: string): string;
  974. begin
  975. if length(s)>0 then
  976. begin
  977. result:=s;
  978. UniqueString(result);
  979. CharLowerBuff(pchar(result),length(result));
  980. end
  981. else
  982. result:='';
  983. end;
  984. function Win32AnsiCompareStr(const S1, S2: string): PtrInt;
  985. begin
  986. result:=CompareString(LOCALE_USER_DEFAULT,0,pchar(s1),length(s1),
  987. pchar(s2),length(s2))-2;
  988. end;
  989. function Win32AnsiCompareText(const S1, S2: string): PtrInt;
  990. begin
  991. result:=CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE,pchar(s1),length(s1),
  992. pchar(s2),length(s2))-2;
  993. end;
  994. function Win32AnsiStrComp(S1, S2: PChar): PtrInt;
  995. begin
  996. result:=CompareString(LOCALE_USER_DEFAULT,0,s1,-1,s2,-1)-2;
  997. end;
  998. function Win32AnsiStrIComp(S1, S2: PChar): PtrInt;
  999. begin
  1000. result:=CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE,s1,-1,s2,-1)-2;
  1001. end;
  1002. function Win32AnsiStrLComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  1003. begin
  1004. result:=CompareString(LOCALE_USER_DEFAULT,0,s1,maxlen,s2,maxlen)-2;
  1005. end;
  1006. function Win32AnsiStrLIComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  1007. begin
  1008. result:=CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE,s1,maxlen,s2,maxlen)-2;
  1009. end;
  1010. function Win32AnsiStrLower(Str: PChar): PChar;
  1011. begin
  1012. CharLower(str);
  1013. result:=str;
  1014. end;
  1015. function Win32AnsiStrUpper(Str: PChar): PChar;
  1016. begin
  1017. CharUpper(str);
  1018. result:=str;
  1019. end;
  1020. function Win32CompareUnicodeString(const s1, s2 : UnicodeString) : PtrInt;
  1021. begin
  1022. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), 0);
  1023. end;
  1024. function Win32CompareTextUnicodeString(const s1, s2 : UnicodeString) : PtrInt;
  1025. begin
  1026. Result:=DoCompareStringW(PWideChar(s1), PWideChar(s2), Length(s1), Length(s2), NORM_IGNORECASE);
  1027. end;
  1028. { there is a similiar procedure in the system unit which inits the fields which
  1029. are relevant already for the system unit }
  1030. procedure InitWin32Widestrings;
  1031. begin
  1032. { return value: number of code points in the string. Whenever an invalid
  1033. code point is encountered, all characters part of this invalid code point
  1034. are considered to form one "character" and the next character is
  1035. considered to be the start of a new (possibly also invalid) code point }
  1036. //!!! CharLengthPCharProc : function(const Str: PChar): PtrInt;
  1037. { return value:
  1038. -1 if incomplete or invalid code point
  1039. 0 if NULL character,
  1040. > 0 if that's the length in bytes of the code point }
  1041. //!!!! CodePointLengthProc : function(const Str: PChar; MaxLookAead: PtrInt): Ptrint;
  1042. widestringmanager.CompareWideStringProc:=@Win32CompareWideString;
  1043. widestringmanager.CompareTextWideStringProc:=@Win32CompareTextWideString;
  1044. widestringmanager.UpperAnsiStringProc:=@Win32AnsiUpperCase;
  1045. widestringmanager.LowerAnsiStringProc:=@Win32AnsiLowerCase;
  1046. widestringmanager.CompareStrAnsiStringProc:=@Win32AnsiCompareStr;
  1047. widestringmanager.CompareTextAnsiStringProc:=@Win32AnsiCompareText;
  1048. widestringmanager.StrCompAnsiStringProc:=@Win32AnsiStrComp;
  1049. widestringmanager.StrICompAnsiStringProc:=@Win32AnsiStrIComp;
  1050. widestringmanager.StrLCompAnsiStringProc:=@Win32AnsiStrLComp;
  1051. widestringmanager.StrLICompAnsiStringProc:=@Win32AnsiStrLIComp;
  1052. widestringmanager.StrLowerAnsiStringProc:=@Win32AnsiStrLower;
  1053. widestringmanager.StrUpperAnsiStringProc:=@Win32AnsiStrUpper;
  1054. widestringmanager.CompareUnicodeStringProc:=@Win32CompareUnicodeString;
  1055. widestringmanager.CompareTextUnicodeStringProc:=@Win32CompareTextUnicodeString;
  1056. end;
  1057. Initialization
  1058. InitWin32Widestrings;
  1059. InitExceptions; { Initialize exceptions. OS independent }
  1060. InitInternational; { Initialize internationalization settings }
  1061. LoadVersionInfo;
  1062. InitSysConfigDir;
  1063. OnBeep:=@SysBeep;
  1064. Finalization
  1065. DoneExceptions;
  1066. end.