Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

552 строки
19 KiB

  1. unit uutlCommon;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, versionresource, versiontypes, typinfo
  6. {$IFDEF UNIX}, unixtype, pthreads {$ENDIF};
  7. type
  8. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. TutlInterfaceNoRefCount = class(TObject, IUnknown)
  10. protected
  11. fRefCount: longint;
  12. { implement methods of IUnknown }
  13. function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  14. function _AddRef: longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual;
  15. function _Release: longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual;
  16. public
  17. property RefCount: LongInt read fRefCount;
  18. end;
  19. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  20. TutlCSVList = class(TStringList)
  21. private
  22. fSkipDelims: boolean;
  23. function GetStrictDelText: string;
  24. procedure SetStrictDelText(const Value: string);
  25. public
  26. property StrictDelimitedText: string read GetStrictDelText write SetStrictDelText;
  27. // Skip repeated delims instead of reading empty lines?
  28. property SkipDelims: Boolean read fSkipDelims write fSkipDelims;
  29. end;
  30. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  31. TutlVersionInfo = class(TObject)
  32. private
  33. fVersionRes: TVersionResource;
  34. function GetFixedInfo: TVersionFixedInfo;
  35. function GetStringFileInfo: TVersionStringFileInfo;
  36. function GetVarFileInfo: TVersionVarFileInfo;
  37. public
  38. property FixedInfo: TVersionFixedInfo read GetFixedInfo;
  39. property StringFileInfo: TVersionStringFileInfo read GetStringFileInfo;
  40. property VarFileInfo: TVersionVarFileInfo read GetVarFileInfo;
  41. function Load(const aInstance: THandle): Boolean;
  42. constructor Create;
  43. destructor Destroy; override;
  44. end;
  45. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  46. EOutOfRangeException = class(Exception)
  47. private
  48. fMin: Integer;
  49. fMax: Integer;
  50. fIndex: Integer;
  51. public
  52. property Min: Integer read fMin;
  53. property Max: Integer read fMax;
  54. property Index: Integer read fIndex;
  55. constructor Create(const aIndex, aMin, aMax: Integer);
  56. constructor Create(const aMsg: String; const aIndex, aMin, aMax: Integer);
  57. end;
  58. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  59. IutlFilterBuilder = interface['{BC5039C7-42E7-428F-A3E7-DDF7757B1907}']
  60. function Add(aDescr, aMask: string; const aAppendFilterToDesc: boolean = true): IutlFilterBuilder;
  61. function AddFilter(aFilter: string): IutlFilterBuilder;
  62. function Compose(const aIncludeAllSupported: String = ''; const aIncludeAllFiles: String = ''): string;
  63. end;
  64. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  65. function Supports (const aInstance: TObject; const aClass: TClass; out aObj): Boolean;
  66. function GetTickCount64 (): QWord;
  67. function GetMicroTime (): QWord;
  68. function GetPlatformIdentitfier(): String;
  69. function utlRateLimited (const Reference: QWord; const Interval: QWord): boolean;
  70. procedure utlFinalizeObject (var obj; const aTypeInfo: PTypeInfo; const aFreeObject: Boolean);
  71. function utlFilterBuilder (): IutlFilterBuilder;
  72. implementation
  73. uses
  74. {$IFDEF WINDOWS}
  75. Windows,
  76. {$ELSE}
  77. Unix, BaseUnix,
  78. {$ENDIF}
  79. uutlGenerics;
  80. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  81. type
  82. TFilterBuilderImpl = class(
  83. TInterfacedObject,
  84. IutlFilterBuilder)
  85. private type
  86. TFilterEntry = class
  87. Descr,
  88. Filter: String;
  89. end;
  90. TFilterList = specialize TutlList<TFilterEntry>;
  91. private
  92. fFilters: TFilterList;
  93. public
  94. function Add (aDescr, aMask: string; const aAppendFilterToDesc: boolean): IutlFilterBuilder;
  95. function AddFilter(aFilter: string): IutlFilterBuilder;
  96. function Compose (const aIncludeAllSupported: String = ''; const aIncludeAllFiles: String = ''): string;
  97. constructor Create;
  98. destructor Destroy; override;
  99. end;
  100. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  101. //Helper Methods////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  102. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  103. function Supports(const aInstance: TObject; const aClass: TClass; out aObj): Boolean;
  104. begin
  105. result := Assigned(aInstance) and aInstance.InheritsFrom(aClass);
  106. if result
  107. then TObject(aObj) := aInstance
  108. else TObject(aObj) := nil;
  109. end;
  110. {$IF DEFINED(WINDOWS)}
  111. var
  112. PERF_FREQ: Int64;
  113. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  114. function GetTickCount64: QWord;
  115. begin
  116. // GetTickCount64 is better, but we need to check the Windows version to use it
  117. Result := Windows.GetTickCount();
  118. end;
  119. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  120. function GetMicroTime: QWord;
  121. var
  122. pc: Int64;
  123. begin
  124. pc := 0;
  125. QueryPerformanceCounter(pc);
  126. result := (pc * 1000*1000) div PERF_FREQ;
  127. end;
  128. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  129. {$ELSEIF DEFINED(UNIX)}
  130. function GetTickCount64: QWord;
  131. var
  132. tp: TTimeVal;
  133. begin
  134. fpgettimeofday(@tp, nil);
  135. Result := (Int64(tp.tv_sec) * 1000) + (tp.tv_usec div 1000);
  136. end;
  137. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  138. function GetMicroTime: QWord;
  139. var
  140. tp: TTimeVal;
  141. begin
  142. fpgettimeofday(@tp, nil);
  143. Result := (Int64(tp.tv_sec) * 1000*1000) + tp.tv_usec;
  144. end;
  145. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  146. {$ELSE}
  147. function GetTickCount64: QWord;
  148. begin
  149. Result := Trunc(Now * 24 * 60 * 60 * 1000);
  150. end;
  151. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  152. function GetMicroTime: QWord;
  153. begin
  154. Result := Trunc(Now * 24 * 60 * 60 * 1000*1000);
  155. end;
  156. {$ENDIF}
  157. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  158. function GetPlatformIdentitfier: String;
  159. {$IFDEF WINDOWS}
  160. function GetWindowsVersionStr(const aDefault: String): string;
  161. var
  162. osv: TOSVERSIONINFO;
  163. ver: cardinal;
  164. begin
  165. result := aDefault;
  166. osv.dwOSVersionInfoSize := SizeOf(osv);
  167. if GetVersionEx(osv) then begin
  168. ver := MAKELONG(osv.dwMinorVersion, osv.dwMajorVersion);
  169. // positive overflow: if system is newer, always detect as newest we knew instead of failing
  170. if ver >= $000A0000 then
  171. result := '10'
  172. else if ver >= $00060003 then
  173. result := '8_1'
  174. else if ver >= $00060002 then
  175. result := '8'
  176. else if ver >= $00060001 then
  177. result := '7'
  178. else if ver >= $00060000 then
  179. result := 'Vista'
  180. else if ver >= $00050002 then
  181. result := '2003'
  182. else if ver >= $00050001 then
  183. result := 'XP'
  184. else if ver >= $00050000 then
  185. result := '2000'
  186. else if ver >= $00040000 then
  187. result := 'NT4';
  188. // ignore NT3, hmkay?;
  189. end;
  190. end;
  191. {$ENDIF}
  192. var
  193. os,ver,arch: string;
  194. begin
  195. result := '';
  196. os := '';
  197. ver := 'generic';
  198. arch := '';
  199. {$IF DEFINED(WINDOWS)}
  200. os := 'mswin';
  201. ver := GetWindowsVersionStr(ver);
  202. {$ELSEIF DEFINED(LINUX)}
  203. os := 'linux';
  204. {$Warning System Version String missing!}
  205. {$ENDIF}
  206. {$IF DEFINED(CPUX86)}
  207. arch := 'x86';
  208. {$ELSEIF DEFINED(cpux86_64)}
  209. arch := 'x64';
  210. {$ELSE}
  211. {$ERROR Unknown Architecture!}
  212. {$ENDIF}
  213. result := Format('%s-%s-%s', [os, ver, arch]);
  214. end;
  215. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  216. function utlRateLimited(const Reference: QWord; const Interval: QWord): boolean;
  217. begin
  218. Result := GetMicroTime - Reference > Interval;
  219. end;
  220. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  221. procedure utlFinalizeObject(var obj; const aTypeInfo: PTypeInfo; const aFreeObject: Boolean);
  222. var
  223. o: TObject;
  224. begin
  225. case aTypeInfo^.Kind of
  226. tkClass: begin
  227. if (aFreeObject) then begin
  228. o := TObject(obj);
  229. Pointer(obj) := nil;
  230. if Assigned(o) then
  231. o.Free;
  232. end;
  233. end;
  234. tkInterface: begin
  235. IUnknown(obj) := nil;
  236. end;
  237. tkAString: begin
  238. AnsiString(Obj) := '';
  239. end;
  240. tkUString: begin
  241. UnicodeString(Obj) := '';
  242. end;
  243. tkString: begin
  244. String(Obj) := '';
  245. end;
  246. end;
  247. end;
  248. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  249. function utlFilterBuilder: IutlFilterBuilder;
  250. begin
  251. result := TFilterBuilderImpl.Create;
  252. end;
  253. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  254. //TutlInterfaceNoRefCount///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  255. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  256. function TutlInterfaceNoRefCount.QueryInterface(constref iid: tguid; out obj): longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  257. begin
  258. if getinterface(iid,obj) then
  259. result:=S_OK
  260. else
  261. result:=longint(E_NOINTERFACE);
  262. end;
  263. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  264. function TutlInterfaceNoRefCount._AddRef: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  265. begin
  266. result := InterLockedIncrement(fRefCount);
  267. end;
  268. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  269. function TutlInterfaceNoRefCount._Release: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  270. begin
  271. result := InterLockedDecrement(fRefCount);
  272. end;
  273. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  274. //TutlCSVList///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  275. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  276. function TutlCSVList.GetStrictDelText: string;
  277. var
  278. S: string;
  279. I, J, Cnt: Integer;
  280. q: boolean;
  281. LDelimiters: TSysCharSet;
  282. begin
  283. Cnt := GetCount;
  284. if (Cnt = 1) and (Get(0) = '') then
  285. Result := QuoteChar + QuoteChar
  286. else
  287. begin
  288. Result := '';
  289. LDelimiters := [QuoteChar, Delimiter];
  290. for I := 0 to Cnt - 1 do
  291. begin
  292. S := Get(I);
  293. q:= false;
  294. if S>'' then begin
  295. for J:= 1 to length(S) do
  296. if S[J] in LDelimiters then begin
  297. q:= true;
  298. break;
  299. end;
  300. if q then S := AnsiQuotedStr(S, QuoteChar);
  301. end else
  302. S := AnsiQuotedStr(S, QuoteChar);
  303. Result := Result + S + Delimiter;
  304. end;
  305. System.Delete(Result, Length(Result), 1);
  306. end;
  307. end;
  308. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  309. procedure TutlCSVList.SetStrictDelText(const Value: string);
  310. var
  311. S: String;
  312. P, P1: PChar;
  313. begin
  314. BeginUpdate;
  315. try
  316. Clear;
  317. P:= PChar(Value);
  318. if fSkipDelims then begin
  319. while (P^<>#0) and (P^=Delimiter) do begin
  320. P:= CharNext(P);
  321. end;
  322. end;
  323. while (P^<>#0) do begin
  324. if (P^ = QuoteChar) then begin
  325. S:= AnsiExtractQuotedStr(P, QuoteChar);
  326. end else begin
  327. P1:= P;
  328. while (P^<>#0) and (P^<>Delimiter) do begin
  329. P:= CharNext(P);
  330. end;
  331. SetString(S, P1, P - P1);
  332. end;
  333. Add(S);
  334. while (P^<>#0) and (P^<>Delimiter) do begin
  335. P:= CharNext(P);
  336. end;
  337. if (P^<>#0) then
  338. P:= CharNext(P);
  339. if fSkipDelims then begin
  340. while (P^<>#0) and (P^=Delimiter) do begin
  341. P:= CharNext(P);
  342. end;
  343. end;
  344. end;
  345. finally
  346. EndUpdate;
  347. end;
  348. end;
  349. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  350. //TutlVersionInfo///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  351. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  352. function TutlVersionInfo.GetFixedInfo: TVersionFixedInfo;
  353. begin
  354. result := fVersionRes.FixedInfo;
  355. end;
  356. function TutlVersionInfo.GetStringFileInfo: TVersionStringFileInfo;
  357. begin
  358. result := fVersionRes.StringFileInfo;
  359. end;
  360. function TutlVersionInfo.GetVarFileInfo: TVersionVarFileInfo;
  361. begin
  362. result := fVersionRes.VarFileInfo;
  363. end;
  364. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  365. function TutlVersionInfo.Load(const aInstance: THandle): Boolean;
  366. var
  367. Stream: TResourceStream;
  368. begin
  369. result := false;
  370. if (FindResource(aInstance, PChar(PtrInt(1)), PChar(RT_VERSION)) = 0) then
  371. exit;
  372. Stream := TResourceStream.CreateFromID(aInstance, 1, PChar(RT_VERSION));
  373. try
  374. fVersionRes.SetCustomRawDataStream(Stream);
  375. fVersionRes.FixedInfo;// access some property to force load from the stream
  376. fVersionRes.SetCustomRawDataStream(nil);
  377. finally
  378. Stream.Free;
  379. end;
  380. result := true;
  381. end;
  382. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  383. constructor TutlVersionInfo.Create;
  384. begin
  385. inherited Create;
  386. fVersionRes := TVersionResource.Create;
  387. end;
  388. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  389. destructor TutlVersionInfo.Destroy;
  390. begin
  391. FreeAndNil(fVersionRes);
  392. inherited Destroy;
  393. end;
  394. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  395. //EOutOfRange///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  396. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  397. constructor EOutOfRangeException.Create(const aIndex, aMin, aMax: Integer);
  398. begin
  399. Create('', aIndex, aMin, aMax);
  400. end;
  401. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  402. constructor EOutOfRangeException.Create(const aMsg: String; const aIndex, aMin, aMax: Integer);
  403. var
  404. s: String;
  405. begin
  406. fIndex := aIndex;
  407. fMin := aMin;
  408. fMax := aMax;
  409. s := Format('index (%d) out of range (%d:%d)', [fIndex, fMin, fMax]);
  410. if (aMsg <> '') then
  411. s := s + ': ' + aMsg;
  412. inherited Create(s);
  413. end;
  414. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  415. //TutlFilterBuilder///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  416. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  417. function TFilterBuilderImpl.Compose(const aIncludeAllSupported: String; const aIncludeAllFiles: String): string;
  418. var
  419. s: String;
  420. e: TFilterEntry;
  421. begin
  422. result := '';
  423. if (aIncludeAllSupported>'') and (fFilters.Count > 0) then begin
  424. s:= '';
  425. for e in fFilters do begin
  426. if s>'' then
  427. s += ';';
  428. s += e.Filter;
  429. end;
  430. Result+= Format('%s|%s', [aIncludeAllSupported, s, s]);
  431. end;
  432. for e in fFilters do begin
  433. if Result>'' then
  434. Result += '|';
  435. Result+= Format('%s|%s', [e.Descr, e.Filter]);
  436. end;
  437. if aIncludeAllFiles > '' then begin
  438. if Result>'' then
  439. Result += '|';
  440. Result+= Format('%s|%s', [aIncludeAllFiles, '*.*']);
  441. end;
  442. end;
  443. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  444. function TFilterBuilderImpl.Add(aDescr, aMask: string; const aAppendFilterToDesc: boolean): IutlFilterBuilder;
  445. var
  446. e: TFilterEntry;
  447. begin
  448. result := Self;
  449. e:= TFilterEntry.Create;
  450. if aAppendFilterToDesc then
  451. e.Descr:= Format('%s (%s)', [aDescr, aMask])
  452. else
  453. e.Descr:= aDescr;
  454. e.Filter:= aMask;
  455. fFilters.Add(e);
  456. end;
  457. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  458. function TFilterBuilderImpl.AddFilter(aFilter: string): IutlFilterBuilder;
  459. var
  460. c: integer;
  461. begin
  462. c:= Pos('|', aFilter);
  463. if c > 0 then
  464. result := (Self as IutlFilterBuilder).Add(Copy(aFilter, 1, c-1), Copy(aFilter, c+1, Maxint))
  465. else
  466. result := (Self as IutlFilterBuilder).Add(aFilter, aFilter, false);
  467. end;
  468. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  469. constructor TFilterBuilderImpl.Create;
  470. begin
  471. inherited Create;
  472. fFilters:= TFilterList.Create(true);
  473. end;
  474. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  475. destructor TFilterBuilderImpl.Destroy;
  476. begin
  477. FreeAndNil(fFilters);
  478. inherited Destroy;
  479. end;
  480. initialization
  481. {$IF DEFINED(WINDOWS)}
  482. PERF_FREQ := 0;
  483. QueryPerformanceFrequency(PERF_FREQ);
  484. {$ENDIF}
  485. end.