Quick.Commons.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. { ***************************************************************************
  2. Copyright (c) 2016-2017 Kike Pérez
  3. Unit : Quick.Commons
  4. Description : Common functions
  5. Author : Kike Pérez
  6. Version : 1.2
  7. Created : 14/07/2017
  8. Modified : 05/10/2017
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Commons;
  22. interface
  23. uses
  24. Classes,
  25. System.SysUtils,
  26. {$IFDEF MSWINDOWS}
  27. Windows,
  28. Winapi.ShlObj,
  29. System.Win.Registry,
  30. {$ENDIF MSWINDOWS}
  31. System.IOUtils,
  32. System.DateUtils;
  33. type
  34. TEventType = (etInfo, etSuccess, etWarning, etError, etDebug, etTrace);
  35. TLogVerbose = set of TEventType;
  36. const
  37. LOG_ONLYERRORS = [etInfo,etError];
  38. LOG_ERRORSANDWARNINGS = [etInfo,etWarning,etError];
  39. LOG_TRACE = [etInfo,etError,etWarning,etTrace];
  40. LOG_ALL = [etInfo,etSuccess,etWarning,etError,etTrace];
  41. LOG_DEBUG = [etInfo,etSuccess,etWarning,etError,etDebug];
  42. EventStr : array of string = ['INFO','SUCC','WARN','ERROR','DEBUG','TRACE'];
  43. type
  44. TPasswordComplexity = set of (pfIncludeNumbers,pfIncludeSigns);
  45. {$IFDEF MSWINDOWS}
  46. TEnvironmentPath = record
  47. EXEPATH : string;
  48. WINDOWS : string;
  49. SYSTEM : string;
  50. PROGRAMFILES : string;
  51. COMMONFILES : string;
  52. HOMEDRIVE : string;
  53. TEMP : string;
  54. USERPROFILE : string;
  55. INSTDRIVE : string;
  56. DESKTOP : string;
  57. STARTMENU : string;
  58. DESKTOP_ALLUSERS : string;
  59. STARTMENU_ALLUSERS : string;
  60. STARTUP : string;
  61. APPDATA : String;
  62. PROGRAMDATA : string;
  63. ALLUSERSPROFILE : string;
  64. end;
  65. {$ENDIF MSWINDOWS}
  66. TFileHelper = record helper for TFile
  67. class function IsInUse(const FileName : string) : Boolean; static;
  68. class function GetSize(const FileName: String): Int64; static;
  69. end;
  70. TDirectoryHelper = record helper for TDirectory
  71. class function GetSize(const Path: String): Int64; static;
  72. end;
  73. TTextFileOperation = (tfOpenRead,tfOpenOverwrite,tfOpenAppend);
  74. TTextStreamFile = class
  75. private
  76. fReadStream : TStreamReader;
  77. fWriteStream : TStreamWriter;
  78. function GetEOF : Boolean;
  79. public
  80. constructor Create(const FileName : string; OpenMode : TTextFileOperation);
  81. destructor Destroy; override;
  82. function ReadLn: string; overload;
  83. function ReadLn(out Data: string): Boolean; overload;
  84. procedure WriteLn (const Data : string);
  85. procedure Close;
  86. property EOF: Boolean read GetEOF;
  87. end;
  88. //generates a random password with complexity options
  89. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  90. //extracts file extension from a filename
  91. function ExtractFileNameWithoutExt(const FileName: String): String;
  92. //converts a Unix path to Windows path
  93. function UnixToWindowsPath(const UnixPath: string): string;
  94. //converts a Windows path to Unix path
  95. function WindowsToUnixPath(const WindowsPath: string): string;
  96. {$IFDEF MSWINDOWS}
  97. //get typical environment paths as temp, desktop, etc
  98. procedure GetEnvironmentPaths;
  99. function GetSpecialFolderPath(folderID : Integer) : string;
  100. //checks if running on a 64bit OS
  101. function Is64bitOS : Boolean;
  102. //checks if is a console app
  103. function IsConsole : Boolean;
  104. //checks if compiled in debug mode
  105. function IsDebug : Boolean;
  106. //checks if running as a service
  107. function IsService : Boolean;
  108. //gets number of seconds without user interaction (mouse, keyboard)
  109. function SecondsIdle: DWord;
  110. //frees process memory not needed
  111. procedure FreeUnusedMem;
  112. //changes screen resolution
  113. function SetScreenResolution(Width, Height: integer): Longint;
  114. {$ENDIF MSWINDOWS}
  115. //returns last day of current month
  116. function LastDayCurrentMonth: TDateTime;
  117. //checks if two datetimes are in same day
  118. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  119. //returns n times a char
  120. function FillStr(const C : Char; const Count : Byte) : string;
  121. //returns a number leading zero
  122. function Zeroes(const Number, Len : Int64) : string;
  123. //converts a number to thousand delimeter string
  124. function NumberToStr(const Number : Int64) : string;
  125. //returns n spaces
  126. function Spaces(const Count : Integer) : string;
  127. //returns current date as a string
  128. function NowStr : string;
  129. //returns a new GUID as string
  130. function NewGuidStr : string;
  131. //compare a string with a wildcard pattern (? or *)
  132. function IsLike(cText, Pattern: string) : Boolean;
  133. //Upper case for first letter
  134. function Capitalize(s: string): string;
  135. function CapitalizeWords(s: string): string;
  136. //returns current logged user
  137. function GetLoggedUserName : string;
  138. //returns computer name
  139. function GetComputerName : string;
  140. //Changes incorrect delims in path
  141. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  142. //Removes last segment of a path
  143. function RemoveLastPathSegment(cDir : string) : string;
  144. //finds swith in commandline params
  145. function ParamFindSwitch(const Switch : string) : Boolean;
  146. //gets value for a switch if exists
  147. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  148. //returns app version (major & minor)
  149. function GetAppVersionStr: string;
  150. //returns app version full (major, minor, release & compiled)
  151. function GetAppVersionFullStr: string;
  152. //UTC DateTime to Local DateTime
  153. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  154. //Local DateTime to UTC DateTime
  155. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  156. var
  157. {$IFDEF MSWINDOWS}
  158. path : TEnvironmentPath;
  159. {$ENDIF MSWINDOWS}
  160. implementation
  161. {TFileHelper}
  162. class function TFileHelper.IsInUse(const FileName : string) : Boolean;
  163. var
  164. HFileRes: HFILE;
  165. begin
  166. Result := False;
  167. if not FileExists(FileName) then Exit;
  168. try
  169. HFileRes := CreateFile(PChar(FileName)
  170. ,GENERIC_READ or GENERIC_WRITE
  171. ,0
  172. ,nil
  173. ,OPEN_EXISTING
  174. ,FILE_ATTRIBUTE_NORMAL
  175. ,0);
  176. Result := (HFileRes = INVALID_HANDLE_VALUE);
  177. if not(Result) then begin
  178. CloseHandle(HFileRes);
  179. end;
  180. except
  181. Result := True;
  182. end;
  183. end;
  184. class function TFileHelper.GetSize(const FileName: String): Int64;
  185. var
  186. info: TWin32FileAttributeData;
  187. begin
  188. Result := -1;
  189. if not GetFileAttributesEx(PWideChar(FileName), GetFileExInfoStandard, @info) then Exit;
  190. Result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
  191. end;
  192. {TDirectoryHelper}
  193. class function TDirectoryHelper.GetSize(const Path: String): Int64;
  194. var
  195. filename : string;
  196. begin
  197. Result := -1;
  198. for filename in TDirectory.GetFiles(Path) do
  199. begin
  200. Result := Result + TFile.GetSize(filename);
  201. end;
  202. end;
  203. {TTextStreamFile}
  204. constructor TTextStreamFile.Create(const FileName : string; OpenMode : TTextFileOperation);
  205. var
  206. Append : Boolean;
  207. begin
  208. if OpenMode = tfOpenRead then fReadStream := TStreamReader.Create(FileName,True)
  209. else
  210. begin
  211. if OpenMode = tfOpenAppend then Append := True
  212. else Append := False;
  213. fWriteStream := TStreamWriter.Create(FileName,Append);
  214. end;
  215. end;
  216. destructor TTextStreamFile.Destroy;
  217. begin
  218. if Assigned(fReadStream) then fReadStream.Free;
  219. if Assigned(fWriteStream) then fWriteStream.Free;
  220. inherited Destroy;
  221. end;
  222. function TTextStreamFile.ReadLn(out Data: string): Boolean;
  223. var
  224. Len, Start: Integer;
  225. EOLChar: ansiChar;
  226. begin
  227. Data := fReadStream.ReadLine;
  228. if Data <> '' then Result := True;
  229. end;
  230. function TTextStreamFile.ReadLn: string;
  231. begin
  232. Result := fReadStream.ReadLine;
  233. end;
  234. procedure TTextStreamFile.WriteLn (const Data : string);
  235. begin
  236. fWriteStream.WriteLine(Data);
  237. end;
  238. function TTextStreamFile.GetEOF : Boolean;
  239. begin
  240. Result := fReadStream.EndOfStream;
  241. end;
  242. procedure TTextStreamFile.Close;
  243. begin
  244. if Assigned(fReadStream) then fReadStream.Close;
  245. if Assigned(fWriteStream) then fWriteStream.Close;
  246. end;
  247. {other functions}
  248. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  249. const
  250. PassAlpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  251. PassSigns = '@!&$';
  252. PassNumbers = '1234567890';
  253. var
  254. MinNumbers,
  255. MinSigns : Integer;
  256. NumNumbers,
  257. NumSigns : Integer;
  258. begin
  259. Result := '';
  260. Randomize;
  261. //fill all alfa
  262. repeat
  263. Result := Result + PassAlpha[Random(Length(PassAlpha))+1];
  264. until (Length(Result) = PasswordLength);
  265. //checks if need include numbers
  266. if pfIncludeNumbers in Complexity then
  267. begin
  268. MinNumbers := Round(PasswordLength / 10 * 2);
  269. NumNumbers := 0;
  270. if MinNumbers = 0 then MinNumbers := 1;
  271. repeat
  272. Result[Random(PasswordLength)+1] := PassNumbers[Random(Length(PassNumbers))+1];
  273. Inc(NumNumbers);
  274. until NumNumbers = MinNumbers;
  275. end;
  276. //checks if need include signs
  277. if pfIncludeNumbers in Complexity then
  278. begin
  279. MinSigns := Round(PasswordLength / 10 * 1);
  280. NumSigns := 0;
  281. if MinSigns = 0 then MinSigns := 1;
  282. repeat
  283. Result[Random(PasswordLength)+1] := PassSigns[Random(Length(PassSigns))+1];
  284. Inc(NumSigns);
  285. until NumSigns = MinSigns;
  286. end;
  287. end;
  288. function ExtractFileNameWithoutExt(const FileName: String): String;
  289. begin
  290. Result := TPath.GetFileNameWithoutExtension(FileName);
  291. end;
  292. function UnixToWindowsPath(const UnixPath: string): string;
  293. begin
  294. Result:=StringReplace(UnixPath, '/', '\',[rfReplaceAll, rfIgnoreCase]);
  295. end;
  296. function WindowsToUnixPath(const WindowsPath: string): string;
  297. begin
  298. Result:=StringReplace(WindowsPath, '\', '/',[rfReplaceAll, rfIgnoreCase]);
  299. end;
  300. {$IFDEF MSWINDOWS}
  301. procedure GetEnvironmentPaths;
  302. begin
  303. //gets path
  304. path.EXEPATH := TPath.GetDirectoryName(ParamStr(0));
  305. path.WINDOWS := GetEnvironmentVariable('windir');
  306. path.PROGRAMFILES := GetEnvironmentVariable('ProgramFiles');
  307. path.COMMONFILES := GetEnvironmentVariable('CommonProgramFiles(x86)');
  308. path.HOMEDRIVE := GetEnvironmentVariable('SystemDrive');
  309. path.USERPROFILE := GetEnvironmentVariable('USERPROFILE');
  310. path.PROGRAMDATA := GetEnvironmentVariable('ProgramData');
  311. path.ALLUSERSPROFILE := GetEnvironmentVariable('AllUsersProfile');
  312. path.INSTDRIVE := path.HOMEDRIVE;
  313. path.TEMP := GetEnvironmentVariable('TEMP');
  314. path.SYSTEM := GetSpecialFolderPath(CSIDL_SYSTEM);
  315. path.DESKTOP := GetSpecialFolderPath(CSIDL_DESKTOP);
  316. try
  317. path.DESKTOP_ALLUSERS := GetSpecialFolderPath(CSIDL_COMMON_DESKTOPDIRECTORY);
  318. except
  319. path.DESKTOP_ALLUSERS := path.DESKTOP;
  320. end;
  321. path.STARTMENU:=GetSpecialFolderPath(CSIDL_PROGRAMS);
  322. try
  323. path.STARTMENU_ALLUSERS:=GetSpecialFolderPath(CSIDL_COMMON_PROGRAMS);
  324. except
  325. path.STARTMENU_ALLUSERS := path.STARTMENU;
  326. end;
  327. path.STARTUP:=GetSpecialFolderPath(CSIDL_STARTUP);
  328. path.APPDATA:=GetSpecialFolderPath(CSIDL_APPDATA);
  329. end;
  330. function GetSpecialFolderPath(folderID : Integer) : string;
  331. var
  332. ppidl: PItemIdList;
  333. begin
  334. SHGetSpecialFolderLocation(0, folderID, ppidl);
  335. SetLength(Result, MAX_PATH);
  336. if not SHGetPathFromIDList(ppidl, PChar(Result)) then
  337. begin
  338. raise exception.create(Format('GetSpecialFolderPath Error: Invalid PIPL (%d)',[folderID]));
  339. end;
  340. SetLength(Result, lStrLen(PChar(Result)));
  341. end;
  342. function Is64bitOS : Boolean;
  343. begin
  344. {$IFDEF WIN64}
  345. Result := True;
  346. {$ELSE}
  347. Result := False;
  348. {$ENDIF WIN64}
  349. end;
  350. function IsConsole: Boolean;
  351. begin
  352. {$IFDEF CONSOLE}
  353. Result := True;
  354. {$ELSE}
  355. Result := False;
  356. {$ENDIF CONSOLE}
  357. end;
  358. function IsDebug: Boolean;
  359. begin
  360. {$IFDEF DEBUG}
  361. Result := True;
  362. {$ELSE}
  363. Result := False;
  364. {$ENDIF DEBUG}
  365. end;
  366. function IsService : Boolean;
  367. begin
  368. //only working with my Quick.AppService unit
  369. try
  370. Result := (IsConsole) and (GetStdHandle(STD_OUTPUT_HANDLE) = 0);
  371. except
  372. Result := False;
  373. end;
  374. end;
  375. function SecondsIdle: DWord;
  376. var
  377. liInfo: TLastInputInfo;
  378. begin
  379. liInfo.cbSize := SizeOf(TLastInputInfo) ;
  380. GetLastInputInfo(liInfo) ;
  381. Result := (GetTickCount - liInfo.dwTime) DIV 1000;
  382. end;
  383. procedure FreeUnusedMem;
  384. begin
  385. if Win32Platform = VER_PLATFORM_WIN32_NT then SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
  386. end;
  387. function SetScreenResolution(Width, Height: integer): Longint;
  388. var
  389. DeviceMode: TDeviceMode;
  390. begin
  391. with DeviceMode do
  392. begin
  393. dmSize := SizeOf(TDeviceMode);
  394. dmPelsWidth := Width;
  395. dmPelsHeight := Height;
  396. dmFields := DM_PELSWIDTH or DM_PELSHEIGHT;
  397. end;
  398. Result := ChangeDisplaySettings(DeviceMode, CDS_UPDATEREGISTRY);
  399. end;
  400. {$ENDIF MSWINDOWS}
  401. function LastDayCurrentMonth: TDateTime;
  402. begin
  403. Result := EncodeDate(YearOf(Now),MonthOf(Now), DaysInMonth(Now));
  404. end;
  405. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  406. begin
  407. Result := DateTimeInRange(cNow,StartOfTheDay(cBefore),EndOfTheDay(cNow),True);
  408. end;
  409. function FillStr(const C : Char; const Count : Byte) : string;
  410. var
  411. i : Byte;
  412. begin
  413. Result := '';
  414. for i := 1 to Count do Result := Result + C;
  415. end;
  416. function Zeroes(const Number, Len : Int64) : string;
  417. begin
  418. if Len > Length(IntToStr(Number)) then Result := FillStr('0',Len - Length(IntToStr(Number))) + IntToStr(Number)
  419. else Result := IntToStr(Number);
  420. end;
  421. function NumberToStr(const Number : Int64) : string;
  422. begin
  423. try
  424. Result := FormatFloat('0,',Number);
  425. except
  426. Result := '#Error';
  427. end;
  428. end;
  429. function Spaces(const Count : Integer) : string;
  430. begin
  431. Result := FillStr(' ',Count);
  432. end;
  433. function NowStr : string;
  434. begin
  435. Result := DateTimeToStr(Now());
  436. end;
  437. function NewGuidStr : string;
  438. var
  439. guid : TGUID;
  440. begin
  441. guid.NewGuid;
  442. Result := guid.ToString
  443. //GUIDToString(guid);
  444. end;
  445. function IsLike(cText, Pattern: string) : Boolean;
  446. var
  447. i, n : Integer;
  448. match : Boolean;
  449. wildcard : Boolean;
  450. CurrentPattern : Char;
  451. aux : string;
  452. begin
  453. Result := False;
  454. wildcard := False;
  455. cText := LowerCase(cText);
  456. Pattern := LowerCase(Pattern);
  457. match := False;
  458. if (Pattern.Length > cText.Length) or (Pattern = '') then Exit;
  459. if Pattern = '*' then
  460. begin
  461. Result := True;
  462. Exit;
  463. end;
  464. for i := 1 to cText.Length do
  465. begin
  466. CurrentPattern := Pattern[i];
  467. if CurrentPattern = '*' then wildcard := True;
  468. if wildcard then
  469. begin
  470. aux := Copy(Pattern,i+1,Pattern.Length);
  471. n := Pos(Copy(Pattern,i+1,Pattern.Length),cText);
  472. if (n > i) or (Pattern.Length = i) then
  473. begin
  474. Result := True;
  475. Exit;
  476. end;
  477. end
  478. else
  479. begin
  480. if (cText[i] = CurrentPattern) or (CurrentPattern = '?') then match := True
  481. else match := False;
  482. end;
  483. end;
  484. Result := match;
  485. end;
  486. function Capitalize(s: string): string;
  487. begin
  488. Result := '';
  489. if s.Length = 0 then Exit;
  490. s := LowerCase(s,loUserLocale);
  491. Result := UpperCase(s[1],loUserLocale) + Trim(Copy(s, 2, s.Length));
  492. end;
  493. function CapitalizeWords(s: string): string;
  494. var
  495. cword : string;
  496. begin
  497. Result := '';
  498. if s.Length = 0 then Exit;
  499. s := LowerCase(s,loUserLocale);
  500. for cword in s.Split([' ']) do
  501. begin
  502. if Result = '' then Result := Capitalize(cword)
  503. else Result := Result + ' ' + Capitalize(cword);
  504. end;
  505. end;
  506. function GetLoggedUserName : string;
  507. const
  508. cnMaxUserNameLen = 254;
  509. var
  510. sUserName : string;
  511. dwUserNameLen : DWord;
  512. begin
  513. dwUserNameLen := cnMaxUserNameLen-1;
  514. SetLength( sUserName, cnMaxUserNameLen );
  515. GetUserName(PChar( sUserName ),dwUserNameLen );
  516. SetLength( sUserName, dwUserNameLen );
  517. Result := sUserName;
  518. end;
  519. function GetComputerName : string;
  520. var
  521. dwLength: dword;
  522. begin
  523. dwLength := 253;
  524. SetLength(Result, dwLength+1);
  525. if not Windows.GetComputerName(pchar(result), dwLength) then Result := 'Not detected!';
  526. Result := pchar(result);
  527. end;
  528. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  529. begin
  530. if Delim = '\' then Result := StringReplace(cPath,'/',Delim,[rfReplaceAll])
  531. else Result := StringReplace(cPath,'\',Delim,[rfReplaceAll]);
  532. end;
  533. function RemoveLastPathSegment(cDir : string) : string;
  534. var
  535. posi : Integer;
  536. delim : Char;
  537. EndsWithDelim : Boolean;
  538. begin
  539. if cDir.Contains('\') then delim := '\'
  540. else if cDir.Contains('/') then delim := '/'
  541. else
  542. begin
  543. Result := '';
  544. Exit;
  545. end;
  546. NormalizePathDelim(cDir,delim);
  547. if cDir.EndsWith(delim) then
  548. begin
  549. cDir := Copy(cDir,1,cDir.Length-1);
  550. EndsWithDelim := True;
  551. end
  552. else EndsWithDelim := False;
  553. if cDir.CountChar(delim) > 1 then posi := cDir.LastDelimiter(delim)
  554. else posi := Pos(delim,cDir)-1;
  555. if posi = cDir.Length then posi := 0;
  556. Result := Copy(cDir,1,posi);
  557. if (Result <> '') and (EndsWithDelim) then Result := Result + delim;
  558. end;
  559. function ParamFindSwitch(const Switch : string) : Boolean;
  560. begin
  561. Result := FindCmdLineSwitch(Switch,['-', '/'],True);
  562. end;
  563. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  564. begin
  565. Result := FindCmdLineSwitch(Switch,cvalue,True,[clstValueAppended]);
  566. end;
  567. function GetAppVersionStr: string;
  568. var
  569. Rec: LongRec;
  570. ver : Cardinal;
  571. begin
  572. ver := GetFileVersion(ParamStr(0));
  573. if ver <> Cardinal(-1) then
  574. begin
  575. Rec := LongRec(ver);
  576. Result := Format('%d.%d', [Rec.Hi, Rec.Lo]);
  577. end
  578. else Result := '';
  579. end;
  580. function GetAppVersionFullStr: string;
  581. var
  582. Exe: string;
  583. Size, Handle: DWORD;
  584. Buffer: TBytes;
  585. FixedPtr: PVSFixedFileInfo;
  586. begin
  587. Result := '';
  588. Exe := ParamStr(0);
  589. Size := GetFileVersionInfoSize(PChar(Exe), Handle);
  590. if Size = 0 then
  591. begin
  592. //RaiseLastOSError;
  593. //no version info in file
  594. Exit;
  595. end;
  596. SetLength(Buffer, Size);
  597. if not GetFileVersionInfo(PChar(Exe), Handle, Size, Buffer) then
  598. RaiseLastOSError;
  599. if not VerQueryValue(Buffer, '\', Pointer(FixedPtr), Size) then
  600. RaiseLastOSError;
  601. if (LongRec(FixedPtr.dwFileVersionLS).Hi = 0) and (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  602. begin
  603. Result := Format('%d.%d',
  604. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  605. LongRec(FixedPtr.dwFileVersionMS).Lo]); //minor
  606. end
  607. else if (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  608. begin
  609. Result := Format('%d.%d.%d',
  610. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  611. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  612. LongRec(FixedPtr.dwFileVersionLS).Hi]); //release
  613. end
  614. else
  615. begin
  616. Result := Format('%d.%d.%d.%d',
  617. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  618. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  619. LongRec(FixedPtr.dwFileVersionLS).Hi, //release
  620. LongRec(FixedPtr.dwFileVersionLS).Lo]); //build
  621. end;
  622. end;
  623. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  624. begin
  625. Result := TTimeZone.Local.ToLocalTime(GMTTime);
  626. end;
  627. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  628. begin
  629. Result := TTimeZone.Local.ToUniversalTime(LocalTime);
  630. end;
  631. initialization
  632. try
  633. GetEnvironmentPaths;
  634. except
  635. on E : Exception do if not IsService then raise Exception.Create(E.Message);
  636. end;
  637. end.