Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

505 linhas
19 KiB

  1. unit uutlCommon;
  2. { Package: Utils
  3. Prefix: utl - UTiLs
  4. Beschreibung: diese Unit implementiert allgemein nützliche nicht-generische Klassen }
  5. {$mode objfpc}{$H+}
  6. {$modeswitch nestedprocvars}
  7. interface
  8. uses
  9. Classes, SysUtils, syncobjs, versionresource, versiontypes, typinfo, uutlGenerics
  10. {$IFDEF UNIX}, unixtype, pthreads {$ENDIF};
  11. type
  12. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  13. TutlStringStack = class(TStringList)
  14. public
  15. procedure Push(const aStr: String);
  16. function Pop: String;
  17. function Seek: String;
  18. end;
  19. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  20. TutlInterfaceNoRefCount = class(TObject, IUnknown)
  21. protected
  22. fRefCount : longint;
  23. { implement methods of IUnknown }
  24. function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  25. function _AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual;
  26. function _Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual;
  27. public
  28. property RefCount: LongInt read fRefCount;
  29. end;
  30. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  31. TutlCSVList = class(TStringList)
  32. private
  33. FSkipDelims: boolean;
  34. function GetStrictDelText: string;
  35. procedure SetStrictDelText(const Value: string);
  36. public
  37. property StrictDelimitedText: string read GetStrictDelText write SetStrictDelText;
  38. // Skip repeated delims instead of reading empty lines?
  39. property SkipDelims: boolean read FSkipDelims write FSkipDelims;
  40. end;
  41. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  42. TutlCheckSynchronizeEvent = class(TObject)
  43. private
  44. fEvent: TEvent;
  45. function WaitMainThread(const aTimeout: Cardinal): TWaitResult;
  46. public const
  47. MAIN_WAIT_GRANULARITY = 10;
  48. public
  49. procedure SetEvent;
  50. procedure ResetEvent;
  51. function WaitFor(const aTimeout: Cardinal): TWaitResult;
  52. constructor Create(const aEventAttributes: syncobjs.PSecurityAttributes;
  53. const aManualReset, aInitialState: Boolean; const aName: string);
  54. destructor Destroy; override;
  55. end;
  56. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  57. TutlBaseEventList = specialize TutlList<TutlCheckSynchronizeEvent>;
  58. TutlEventList = class(TutlBaseEventList)
  59. public
  60. function AddEvent(const aEventAttributes: syncobjs.PSecurityAttributes; const aManualReset,
  61. aInitialState: Boolean; const aName : string): TutlCheckSynchronizeEvent;
  62. function AddDefaultEvent: TutlCheckSynchronizeEvent;
  63. function WaitAll(const aTimeout: Cardinal): TWaitResult;
  64. constructor Create;
  65. end;
  66. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  67. TutlVersionInfo = class(TObject)
  68. private
  69. fVersionRes: TVersionResource;
  70. function GetFixedInfo: TVersionFixedInfo;
  71. function GetStringFileInfo: TVersionStringFileInfo;
  72. function GetVarFileInfo: TVersionVarFileInfo;
  73. public
  74. property FixedInfo: TVersionFixedInfo read GetFixedInfo;
  75. property StringFileInfo: TVersionStringFileInfo read GetStringFileInfo;
  76. property VarFileInfo: TVersionVarFileInfo read GetVarFileInfo;
  77. function Load(const aInstance: THandle): Boolean;
  78. constructor Create;
  79. destructor Destroy; override;
  80. end;
  81. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  82. IutlFilterBuilder = interface['{BC5039C7-42E7-428F-A3E7-DDF7757B1907}']
  83. function Add(aDescr, aMask: string; const aAppendFilterToDesc: boolean = true): IutlFilterBuilder;
  84. function AddFilter(aFilter: string): IutlFilterBuilder;
  85. function Compose(const aIncludeAllSupported: String = ''; const aIncludeAllFiles: String = ''): string;
  86. end;
  87. function utlEventEqual(const aEvent1, aEvent2): Boolean;
  88. function utlFilterBuilder: IutlFilterBuilder;
  89. implementation
  90. uses
  91. {uutlTiming needs to be included after Windows because of GetTickCount64}
  92. uutlLogger{$IFDEF WINDOWS},Windows{$ENDIF}, uutlTiming;
  93. {$IFNDEF WINDOWS}
  94. function CharNext(const C: PChar): PChar;
  95. begin
  96. //TODO: prüfen ob das für UnicodeString auch stimmt
  97. Result:= C;
  98. if Result^>#0 then
  99. inc(Result);
  100. end;
  101. {$IFEND}
  102. function utlEventEqual(const aEvent1, aEvent2): Boolean;
  103. begin
  104. result :=
  105. (TMethod(aEvent1).Code = TMethod(aEvent2).Code) and
  106. (TMethod(aEvent1).Data = TMethod(aEvent2).Data);
  107. end;
  108. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  109. //TutlStringStack//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  110. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  111. procedure TutlStringStack.Push(const aStr: String);
  112. begin
  113. Insert(0, aStr);
  114. end;
  115. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  116. function TutlStringStack.Pop: String;
  117. begin
  118. result := '';
  119. if Count > 0 then begin
  120. result := Strings[0];
  121. Delete(0);
  122. end;
  123. end;
  124. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  125. function TutlStringStack.Seek: String;
  126. begin
  127. result := '';
  128. if Count > 0 then
  129. result := Strings[0];
  130. end;
  131. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  132. //TutlInterfaceNoRefCount///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  133. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  134. function TutlInterfaceNoRefCount.QueryInterface(constref iid: tguid; out obj): longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  135. begin
  136. if getinterface(iid,obj) then
  137. result:=S_OK
  138. else
  139. result:=longint(E_NOINTERFACE);
  140. end;
  141. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  142. function TutlInterfaceNoRefCount._AddRef: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  143. begin
  144. result := InterLockedIncrement(fRefCount);
  145. end;
  146. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  147. function TutlInterfaceNoRefCount._Release: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  148. begin
  149. result := InterLockedDecrement(fRefCount);
  150. end;
  151. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  152. //TutlCSVList///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  154. function TutlCSVList.GetStrictDelText: string;
  155. var
  156. S: string;
  157. I, J, Cnt: Integer;
  158. q: boolean;
  159. LDelimiters: TSysCharSet;
  160. begin
  161. Cnt := GetCount;
  162. if (Cnt = 1) and (Get(0) = '') then
  163. Result := QuoteChar + QuoteChar
  164. else
  165. begin
  166. Result := '';
  167. LDelimiters := [QuoteChar, Delimiter];
  168. for I := 0 to Cnt - 1 do
  169. begin
  170. S := Get(I);
  171. q:= false;
  172. if S>'' then begin
  173. for J:= 1 to length(S) do
  174. if S[J] in LDelimiters then begin
  175. q:= true;
  176. break;
  177. end;
  178. if q then S := AnsiQuotedStr(S, QuoteChar);
  179. end else
  180. S := AnsiQuotedStr(S, QuoteChar);
  181. Result := Result + S + Delimiter;
  182. end;
  183. System.Delete(Result, Length(Result), 1);
  184. end;
  185. end;
  186. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  187. procedure TutlCSVList.SetStrictDelText(const Value: string);
  188. var
  189. S: String;
  190. P, P1: PChar;
  191. begin
  192. BeginUpdate;
  193. try
  194. Clear;
  195. P:= PChar(Value);
  196. if FSkipDelims then begin
  197. while (P^<>#0) and (P^=Delimiter) do begin
  198. P:= CharNext(P);
  199. end;
  200. end;
  201. while (P^<>#0) do begin
  202. if (P^ = QuoteChar) then begin
  203. S:= AnsiExtractQuotedStr(P, QuoteChar);
  204. end else begin
  205. P1:= P;
  206. while (P^<>#0) and (P^<>Delimiter) do begin
  207. P:= CharNext(P);
  208. end;
  209. SetString(S, P1, P - P1);
  210. end;
  211. Add(S);
  212. while (P^<>#0) and (P^<>Delimiter) do begin
  213. P:= CharNext(P);
  214. end;
  215. if (P^<>#0) then
  216. P:= CharNext(P);
  217. if FSkipDelims then begin
  218. while (P^<>#0) and (P^=Delimiter) do begin
  219. P:= CharNext(P);
  220. end;
  221. end;
  222. end;
  223. finally
  224. EndUpdate;
  225. end;
  226. end;
  227. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  228. //TutlCheckSynchronizeEvent/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  229. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  230. function TutlCheckSynchronizeEvent.WaitMainThread(const aTimeout: Cardinal): TWaitResult;
  231. var
  232. timeout: qword;
  233. begin
  234. timeout:= GetTickCount64 + aTimeout;
  235. repeat
  236. result := fEvent.WaitFor(TutlCheckSynchronizeEvent.MAIN_WAIT_GRANULARITY);
  237. CheckSynchronize();
  238. until (result <> wrTimeout) or ((GetTickCount64 > timeout) and (aTimeout <> INFINITE));
  239. end;
  240. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  241. procedure TutlCheckSynchronizeEvent.SetEvent;
  242. begin
  243. fEvent.SetEvent;
  244. end;
  245. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  246. procedure TutlCheckSynchronizeEvent.ResetEvent;
  247. begin
  248. fEvent.ResetEvent;
  249. end;
  250. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  251. function TutlCheckSynchronizeEvent.WaitFor(const aTimeout: Cardinal): TWaitResult;
  252. begin
  253. if (GetCurrentThreadId = MainThreadID) then
  254. result := WaitMainThread(aTimeout)
  255. else
  256. result := fEvent.WaitFor(aTimeout);
  257. end;
  258. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  259. constructor TutlCheckSynchronizeEvent.Create(const aEventAttributes: syncobjs.PSecurityAttributes;
  260. const aManualReset, aInitialState: Boolean; const aName: string);
  261. begin
  262. inherited Create;
  263. fEvent := TEvent.Create(aEventAttributes, aManualReset, aInitialState, aName);
  264. end;
  265. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  266. destructor TutlCheckSynchronizeEvent.Destroy;
  267. begin
  268. FreeAndNil(fEvent);
  269. inherited Destroy;
  270. end;
  271. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  272. //TutlEventList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  273. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  274. function TutlEventList.AddEvent(const aEventAttributes: syncobjs.PSecurityAttributes; const aManualReset,
  275. aInitialState: Boolean; const aName: string): TutlCheckSynchronizeEvent;
  276. begin
  277. result := TutlCheckSynchronizeEvent.Create(aEventAttributes, aManualReset, aInitialState, aName);
  278. Add(result);
  279. end;
  280. function TutlEventList.AddDefaultEvent: TutlCheckSynchronizeEvent;
  281. begin
  282. result := AddEvent(nil, true, false, '');
  283. result.ResetEvent;
  284. end;
  285. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  286. function TutlEventList.WaitAll(const aTimeout: Cardinal): TWaitResult;
  287. var
  288. i: integer;
  289. timeout, tick: qword;
  290. begin
  291. timeout := GetTickCount64 + aTimeout;
  292. for i := 0 to Count-1 do begin
  293. if (aTimeout <> INFINITE) then begin
  294. tick := GetTickCount64;
  295. if (tick >= timeout) then begin
  296. result := wrTimeout;
  297. exit;
  298. end else
  299. result := Items[i].WaitFor(timeout - tick);
  300. end else
  301. result := Items[i].WaitFor(INFINITE);
  302. if result <> wrSignaled then
  303. exit;
  304. end;
  305. end;
  306. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  307. constructor TutlEventList.Create;
  308. begin
  309. inherited Create(true);
  310. end;
  311. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  312. //TutlVersionInfo///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  313. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  314. function TutlVersionInfo.GetFixedInfo: TVersionFixedInfo;
  315. begin
  316. result := fVersionRes.FixedInfo;
  317. end;
  318. function TutlVersionInfo.GetStringFileInfo: TVersionStringFileInfo;
  319. begin
  320. result := fVersionRes.StringFileInfo;
  321. end;
  322. function TutlVersionInfo.GetVarFileInfo: TVersionVarFileInfo;
  323. begin
  324. result := fVersionRes.VarFileInfo;
  325. end;
  326. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  327. function TutlVersionInfo.Load(const aInstance: THandle): Boolean;
  328. var
  329. Stream: TResourceStream;
  330. begin
  331. result := false;
  332. if (FindResource(aInstance, PChar(PtrInt(1)), PChar(RT_VERSION)) = 0) then
  333. exit;
  334. Stream := TResourceStream.CreateFromID(aInstance, 1, PChar(RT_VERSION));
  335. try
  336. fVersionRes.SetCustomRawDataStream(Stream);
  337. fVersionRes.FixedInfo;// access some property to force load from the stream
  338. fVersionRes.SetCustomRawDataStream(nil);
  339. finally
  340. Stream.Free;
  341. end;
  342. result := true;
  343. end;
  344. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  345. constructor TutlVersionInfo.Create;
  346. begin
  347. inherited Create;
  348. fVersionRes := TVersionResource.Create;
  349. end;
  350. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  351. destructor TutlVersionInfo.Destroy;
  352. begin
  353. FreeAndNil(fVersionRes);
  354. inherited Destroy;
  355. end;
  356. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  357. //IutlFilterBuilder///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  358. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  359. type
  360. TFilterBuilderImpl = class(TInterfacedObject, IutlFilterBuilder)
  361. private type
  362. TFilterEntry = class
  363. Descr,
  364. Filter: String;
  365. end;
  366. TFilterList = specialize TutlList<TFilterEntry>;
  367. private
  368. fFilters: TFilterList;
  369. public
  370. constructor Create;
  371. destructor Destroy; override;
  372. function Add(aDescr, aMask: string; const aAppendFilterToDesc: boolean): IutlFilterBuilder;
  373. function AddFilter(aFilter: string): IutlFilterBuilder;
  374. function Compose(const aIncludeAllSupported: String = ''; const aIncludeAllFiles: String = ''): string;
  375. end;
  376. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  377. constructor TFilterBuilderImpl.Create;
  378. begin
  379. inherited Create;
  380. fFilters:= TFilterList.Create(true);
  381. end;
  382. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  383. destructor TFilterBuilderImpl.Destroy;
  384. begin
  385. FreeAndNil(fFilters);
  386. inherited Destroy;
  387. end;
  388. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  389. function TFilterBuilderImpl.Compose(const aIncludeAllSupported: String;
  390. const aIncludeAllFiles: String): string;
  391. var
  392. s: String;
  393. e: TFilterEntry;
  394. begin
  395. Result:= '';
  396. if (aIncludeAllSupported>'') and (fFilters.Count > 0) then begin
  397. s:= '';
  398. for e in fFilters do begin
  399. if s>'' then
  400. s += ';';
  401. s += e.Filter;
  402. end;
  403. Result+= Format('%s|%s', [aIncludeAllSupported, s, s]);
  404. end;
  405. for e in fFilters do begin
  406. if Result>'' then
  407. Result += '|';
  408. Result+= Format('%s|%s', [e.Descr, e.Filter]);
  409. end;
  410. if aIncludeAllFiles > '' then begin
  411. if Result>'' then
  412. Result += '|';
  413. Result+= Format('%s|%s', [aIncludeAllFiles, '*.*']);
  414. end;
  415. end;
  416. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  417. function TFilterBuilderImpl.Add(aDescr, aMask: string;
  418. const aAppendFilterToDesc: boolean): IutlFilterBuilder;
  419. var
  420. e: TFilterEntry;
  421. begin
  422. Result:= Self;
  423. e:= TFilterEntry.Create;
  424. if aAppendFilterToDesc then
  425. e.Descr:= Format('%s (%s)', [aDescr, aMask])
  426. else
  427. e.Descr:= aDescr;
  428. e.Filter:= aMask;
  429. fFilters.Add(e);
  430. end;
  431. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  432. function TFilterBuilderImpl.AddFilter(aFilter: string): IutlFilterBuilder;
  433. var
  434. c: integer;
  435. begin
  436. c:= Pos('|', aFilter);
  437. if c > 0 then
  438. Result:= (Self as IutlFilterBuilder).Add(Copy(aFilter, 1, c-1), Copy(aFilter, c+1, Maxint))
  439. else
  440. Result:= (Self as IutlFilterBuilder).Add(aFilter, aFilter, false);
  441. end;
  442. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  443. function utlFilterBuilder: IutlFilterBuilder;
  444. begin
  445. Result:= TFilterBuilderImpl.Create;
  446. end;
  447. end.