You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

395 lines
15 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. function utlEventEqual(const aEvent1, aEvent2): Boolean;
  82. implementation
  83. uses
  84. {uutlTiming needs to be included after Windows because of GetTickCount64}
  85. uutlLogger{$IFDEF WINDOWS},Windows{$ENDIF}, uutlTiming;
  86. {$IFNDEF WINDOWS}
  87. function CharNext(const C: PChar): PChar;
  88. begin
  89. //TODO: prüfen ob das für UnicodeString auch stimmt
  90. Result:= C;
  91. if Result^>#0 then
  92. inc(Result);
  93. end;
  94. {$IFEND}
  95. function utlEventEqual(const aEvent1, aEvent2): Boolean;
  96. begin
  97. result :=
  98. (TMethod(aEvent1).Code = TMethod(aEvent2).Code) and
  99. (TMethod(aEvent1).Data = TMethod(aEvent2).Data);
  100. end;
  101. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  102. //TutlStringStack//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  103. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  104. procedure TutlStringStack.Push(const aStr: String);
  105. begin
  106. Insert(0, aStr);
  107. end;
  108. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  109. function TutlStringStack.Pop: String;
  110. begin
  111. result := '';
  112. if Count > 0 then begin
  113. result := Strings[0];
  114. Delete(0);
  115. end;
  116. end;
  117. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  118. function TutlStringStack.Seek: String;
  119. begin
  120. result := '';
  121. if Count > 0 then
  122. result := Strings[0];
  123. end;
  124. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  125. //TutlInterfaceNoRefCount///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  126. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  127. function TutlInterfaceNoRefCount.QueryInterface(constref iid: tguid; out obj): longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  128. begin
  129. if getinterface(iid,obj) then
  130. result:=S_OK
  131. else
  132. result:=longint(E_NOINTERFACE);
  133. end;
  134. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  135. function TutlInterfaceNoRefCount._AddRef: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  136. begin
  137. result := InterLockedIncrement(fRefCount);
  138. end;
  139. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  140. function TutlInterfaceNoRefCount._Release: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  141. begin
  142. result := InterLockedDecrement(fRefCount);
  143. end;
  144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  145. //TutlCSVList///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  146. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  147. function TutlCSVList.GetStrictDelText: string;
  148. var
  149. S: string;
  150. I, J, Cnt: Integer;
  151. q: boolean;
  152. LDelimiters: TSysCharSet;
  153. begin
  154. Cnt := GetCount;
  155. if (Cnt = 1) and (Get(0) = '') then
  156. Result := QuoteChar + QuoteChar
  157. else
  158. begin
  159. Result := '';
  160. LDelimiters := [QuoteChar, Delimiter];
  161. for I := 0 to Cnt - 1 do
  162. begin
  163. S := Get(I);
  164. q:= false;
  165. if S>'' then begin
  166. for J:= 1 to length(S) do
  167. if S[J] in LDelimiters then begin
  168. q:= true;
  169. break;
  170. end;
  171. if q then S := AnsiQuotedStr(S, QuoteChar);
  172. end else
  173. S := AnsiQuotedStr(S, QuoteChar);
  174. Result := Result + S + Delimiter;
  175. end;
  176. System.Delete(Result, Length(Result), 1);
  177. end;
  178. end;
  179. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  180. procedure TutlCSVList.SetStrictDelText(const Value: string);
  181. var
  182. S: String;
  183. P, P1: PChar;
  184. begin
  185. BeginUpdate;
  186. try
  187. Clear;
  188. P:= PChar(Value);
  189. if FSkipDelims then begin
  190. while (P^<>#0) and (P^=Delimiter) do begin
  191. P:= CharNext(P);
  192. end;
  193. end;
  194. while (P^<>#0) do begin
  195. if (P^ = QuoteChar) then begin
  196. S:= AnsiExtractQuotedStr(P, QuoteChar);
  197. end else begin
  198. P1:= P;
  199. while (P^<>#0) and (P^<>Delimiter) do begin
  200. P:= CharNext(P);
  201. end;
  202. SetString(S, P1, P - P1);
  203. end;
  204. Add(S);
  205. while (P^<>#0) and (P^<>Delimiter) do begin
  206. P:= CharNext(P);
  207. end;
  208. if (P^<>#0) then
  209. P:= CharNext(P);
  210. if FSkipDelims then begin
  211. while (P^<>#0) and (P^=Delimiter) do begin
  212. P:= CharNext(P);
  213. end;
  214. end;
  215. end;
  216. finally
  217. EndUpdate;
  218. end;
  219. end;
  220. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  221. //TutlCheckSynchronizeEvent/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  222. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  223. function TutlCheckSynchronizeEvent.WaitMainThread(const aTimeout: Cardinal): TWaitResult;
  224. var
  225. timeout: qword;
  226. begin
  227. timeout:= GetTickCount64 + aTimeout;
  228. repeat
  229. result := fEvent.WaitFor(TutlCheckSynchronizeEvent.MAIN_WAIT_GRANULARITY);
  230. CheckSynchronize();
  231. until (result <> wrTimeout) or ((GetTickCount64 > timeout) and (aTimeout <> INFINITE));
  232. end;
  233. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  234. procedure TutlCheckSynchronizeEvent.SetEvent;
  235. begin
  236. fEvent.SetEvent;
  237. end;
  238. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  239. procedure TutlCheckSynchronizeEvent.ResetEvent;
  240. begin
  241. fEvent.ResetEvent;
  242. end;
  243. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  244. function TutlCheckSynchronizeEvent.WaitFor(const aTimeout: Cardinal): TWaitResult;
  245. begin
  246. if (GetCurrentThreadId = MainThreadID) then
  247. result := WaitMainThread(aTimeout)
  248. else
  249. result := fEvent.WaitFor(aTimeout);
  250. end;
  251. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  252. constructor TutlCheckSynchronizeEvent.Create(const aEventAttributes: syncobjs.PSecurityAttributes;
  253. const aManualReset, aInitialState: Boolean; const aName: string);
  254. begin
  255. inherited Create;
  256. fEvent := TEvent.Create(aEventAttributes, aManualReset, aInitialState, aName);
  257. end;
  258. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  259. destructor TutlCheckSynchronizeEvent.Destroy;
  260. begin
  261. FreeAndNil(fEvent);
  262. inherited Destroy;
  263. end;
  264. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  265. //TutlEventList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  266. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  267. function TutlEventList.AddEvent(const aEventAttributes: syncobjs.PSecurityAttributes; const aManualReset,
  268. aInitialState: Boolean; const aName: string): TutlCheckSynchronizeEvent;
  269. begin
  270. result := TutlCheckSynchronizeEvent.Create(aEventAttributes, aManualReset, aInitialState, aName);
  271. Add(result);
  272. end;
  273. function TutlEventList.AddDefaultEvent: TutlCheckSynchronizeEvent;
  274. begin
  275. result := AddEvent(nil, true, false, '');
  276. result.ResetEvent;
  277. end;
  278. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  279. function TutlEventList.WaitAll(const aTimeout: Cardinal): TWaitResult;
  280. var
  281. i: integer;
  282. timeout, tick: qword;
  283. begin
  284. timeout := GetTickCount64 + aTimeout;
  285. for i := 0 to Count-1 do begin
  286. if (aTimeout <> INFINITE) then begin
  287. tick := GetTickCount64;
  288. if (tick >= timeout) then begin
  289. result := wrTimeout;
  290. exit;
  291. end else
  292. result := Items[i].WaitFor(timeout - tick);
  293. end else
  294. result := Items[i].WaitFor(INFINITE);
  295. if result <> wrSignaled then
  296. exit;
  297. end;
  298. end;
  299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  300. constructor TutlEventList.Create;
  301. begin
  302. inherited Create(true);
  303. end;
  304. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  305. //TutlVersionInfo///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  306. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  307. function TutlVersionInfo.GetFixedInfo: TVersionFixedInfo;
  308. begin
  309. result := fVersionRes.FixedInfo;
  310. end;
  311. function TutlVersionInfo.GetStringFileInfo: TVersionStringFileInfo;
  312. begin
  313. result := fVersionRes.StringFileInfo;
  314. end;
  315. function TutlVersionInfo.GetVarFileInfo: TVersionVarFileInfo;
  316. begin
  317. result := fVersionRes.VarFileInfo;
  318. end;
  319. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  320. function TutlVersionInfo.Load(const aInstance: THandle): Boolean;
  321. var
  322. Stream: TResourceStream;
  323. begin
  324. result := false;
  325. if (FindResource(aInstance, PChar(PtrInt(1)), PChar(RT_VERSION)) = 0) then
  326. exit;
  327. Stream := TResourceStream.CreateFromID(aInstance, 1, PChar(RT_VERSION));
  328. try
  329. fVersionRes.SetCustomRawDataStream(Stream);
  330. fVersionRes.FixedInfo;// access some property to force load from the stream
  331. fVersionRes.SetCustomRawDataStream(nil);
  332. finally
  333. Stream.Free;
  334. end;
  335. result := true;
  336. end;
  337. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  338. constructor TutlVersionInfo.Create;
  339. begin
  340. inherited Create;
  341. fVersionRes := TVersionResource.Create;
  342. end;
  343. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  344. destructor TutlVersionInfo.Destroy;
  345. begin
  346. FreeAndNil(fVersionRes);
  347. inherited Destroy;
  348. end;
  349. end.