Quick.Commons.pas 20 KB

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