classes.inc 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by Michael Van Canneyt and Florian Klaempfl
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {**********************************************************************
  11. * Class implementations are in separate files. *
  12. **********************************************************************}
  13. var
  14. ClassList : TThreadlist;
  15. ClassAliasList : TStringList;
  16. {
  17. Include all message strings
  18. Add a language with IFDEF LANG_NAME
  19. just befor the final ELSE. This way English will always be the default.
  20. }
  21. {$IFDEF LANG_GERMAN}
  22. {$i constsg.inc}
  23. {$ELSE}
  24. {$IFDEF LANG_SPANISH}
  25. {$i constss.inc}
  26. {$ENDIF}
  27. {$ENDIF}
  28. { Utility routines }
  29. {$i util.inc}
  30. { TBits implementation }
  31. {$i bits.inc}
  32. { All streams implementations: }
  33. { Tstreams THandleStream TFileStream TResourcseStreams TStringStream }
  34. { TCustomMemoryStream TMemoryStream }
  35. {$i streams.inc}
  36. { TParser implementation}
  37. {$i parser.inc}
  38. { TCollection and TCollectionItem implementations }
  39. {$i collect.inc}
  40. { TList and TThreadList implementations }
  41. {$i lists.inc}
  42. { TStrings and TStringList implementations }
  43. {$i stringl.inc}
  44. { TThread implementation }
  45. { system independend threading code }
  46. var
  47. { event executed by SychronizeInternal to wake main thread if it sleeps in
  48. CheckSynchronize }
  49. SynchronizeTimeoutEvent: PRtlEvent;
  50. { the head of the queue containing the entries to be Synchronized - Nil if the
  51. queue is empty }
  52. ThreadQueueHead: TThread.PThreadQueueEntry;
  53. { the tail of the queue containing the entries to be Synchronized - Nil if the
  54. queue is empty }
  55. ThreadQueueTail: TThread.PThreadQueueEntry;
  56. { used for serialized access to the queue }
  57. ThreadQueueLock: TRtlCriticalSection;
  58. { this list holds all instances of external threads that need to be freed at
  59. the end of the program }
  60. ExternalThreads: TThreadList;
  61. threadvar
  62. { the instance of the current thread; in case of an external thread this is
  63. Nil until TThread.GetCurrentThread was called once (the RTLs need to ensure
  64. that threadvars are initialized with 0!) }
  65. CurrentThreadVar: TThread;
  66. type
  67. { this type is used if a thread is created using
  68. TThread.CreateAnonymousThread }
  69. TAnonymousThread = class(TThread)
  70. private
  71. fProc: TProcedure;
  72. protected
  73. procedure Execute; override;
  74. public
  75. { as in TThread aProc needs to be changed to TProc once closures are
  76. supported }
  77. constructor Create(aProc: TProcedure);
  78. end;
  79. procedure TAnonymousThread.Execute;
  80. begin
  81. fProc();
  82. end;
  83. constructor TAnonymousThread.Create(aProc: TProcedure);
  84. begin
  85. { an anonymous thread is created suspended and with FreeOnTerminate set }
  86. inherited Create(True);
  87. FreeOnTerminate := True;
  88. fProc := aProc;
  89. end;
  90. type
  91. { this type is used by TThread.GetCurrentThread if the thread does not yet
  92. have a value in CurrentThreadVar (Note: the main thread is also created as
  93. a TExternalThread) }
  94. TExternalThread = class(TThread)
  95. protected
  96. { dummy method to remove the warning }
  97. procedure Execute; override;
  98. public
  99. constructor Create;
  100. end;
  101. procedure TExternalThread.Execute;
  102. begin
  103. { empty }
  104. end;
  105. constructor TExternalThread.Create;
  106. begin
  107. FExternalThread := True;
  108. { the parameter is unimportant if FExternalThread is True }
  109. inherited Create(False);
  110. end;
  111. function ThreadProc(ThreadObjPtr: Pointer): PtrInt;
  112. var
  113. FreeThread: Boolean;
  114. Thread: TThread absolute ThreadObjPtr;
  115. begin
  116. { if Suspend checks FSuspended before doing anything, make sure it }
  117. { knows we're currently not suspended (this flag may have been set }
  118. { to true if CreateSuspended was true) }
  119. // Thread.FSuspended:=false;
  120. // wait until AfterConstruction has been called, so we cannot
  121. // free ourselves before TThread.Create has finished
  122. // (since that one may check our VTM in case of $R+, and
  123. // will call the AfterConstruction method in all cases)
  124. // Thread.Suspend;
  125. try
  126. { The thread may be already terminated at this point, e.g. if it was intially
  127. suspended, or if it wasn't ever scheduled for execution for whatever reason.
  128. So bypass user code if terminated. }
  129. if not Thread.Terminated then begin
  130. CurrentThreadVar := Thread;
  131. Thread.Execute;
  132. end;
  133. except
  134. Thread.FFatalException := TObject(AcquireExceptionObject);
  135. end;
  136. FreeThread := Thread.FFreeOnTerminate;
  137. Result := Thread.FReturnValue;
  138. Thread.FFinished := True;
  139. Thread.DoTerminate;
  140. if FreeThread then
  141. Thread.Free;
  142. EndThread(Result);
  143. end;
  144. { system-dependent code }
  145. {$i tthread.inc}
  146. constructor TThread.Create(CreateSuspended: Boolean;
  147. const StackSize: SizeUInt);
  148. begin
  149. inherited Create;
  150. if FExternalThread then
  151. FThreadID := GetCurrentThreadID
  152. else
  153. SysCreate(CreateSuspended, StackSize);
  154. end;
  155. destructor TThread.Destroy;
  156. begin
  157. if not FExternalThread then
  158. SysDestroy;
  159. RemoveQueuedEvents(Self);
  160. DoneSynchronizeEvent;
  161. { set CurrentThreadVar to Nil? }
  162. inherited Destroy;
  163. end;
  164. procedure TThread.Start;
  165. begin
  166. { suspend/resume are now deprecated in Delphi (they also don't work
  167. on most platforms in FPC), so a different method was required
  168. to start a thread if it's create with fSuspended=true -> that's
  169. what this method is for. }
  170. Resume;
  171. end;
  172. function TThread.GetSuspended: Boolean;
  173. begin
  174. GetSuspended:=FSuspended;
  175. end;
  176. procedure TThread.AfterConstruction;
  177. begin
  178. inherited AfterConstruction;
  179. // enable for all platforms once http://bugs.freepascal.org/view.php?id=16884
  180. // is fixed for all platforms (in case the fix for non-unix platforms also
  181. // requires this field at least)
  182. {$if defined(unix) or defined(windows)}
  183. if not FExternalThread and not FInitialSuspended then
  184. Resume;
  185. {$endif}
  186. end;
  187. procedure ExecuteThreadQueueEntry(aEntry: TThread.PThreadQueueEntry);
  188. begin
  189. if Assigned(aEntry^.Method) then
  190. aEntry^.Method()
  191. // enable once closures are supported
  192. {else
  193. aEntry^.ThreadProc();}
  194. end;
  195. procedure ThreadQueueAppend(aEntry: TThread.PThreadQueueEntry);
  196. begin
  197. { do we really need a synchronized call? }
  198. if GetCurrentThreadID = MainThreadID then begin
  199. ExecuteThreadQueueEntry(aEntry);
  200. if not Assigned(aEntry^.SyncEvent) then
  201. Dispose(aEntry);
  202. end else begin
  203. System.EnterCriticalSection(ThreadQueueLock);
  204. try
  205. { add the entry to the thread queue }
  206. if Assigned(ThreadQueueTail) then begin
  207. ThreadQueueTail^.Next := aEntry;
  208. end else
  209. ThreadQueueHead := aEntry;
  210. ThreadQueueTail := aEntry;
  211. finally
  212. System.LeaveCriticalSection(ThreadQueueLock);
  213. end;
  214. { ensure that the main thread knows that something awaits }
  215. RtlEventSetEvent(SynchronizeTimeoutEvent);
  216. if assigned(WakeMainThread) then
  217. WakeMainThread(aEntry^.Thread);
  218. { is this a Synchronize or Queue entry? }
  219. if Assigned(aEntry^.SyncEvent) then begin
  220. RtlEventWaitFor(aEntry^.SyncEvent);
  221. if Assigned(aEntry^.Exception) then
  222. raise aEntry^.Exception;
  223. end;
  224. end;
  225. end;
  226. procedure TThread.InitSynchronizeEvent;
  227. begin
  228. if Assigned(FSynchronizeEntry) then
  229. Exit;
  230. New(FSynchronizeEntry);
  231. FillChar(FSynchronizeEntry^, SizeOf(TThreadQueueEntry), 0);
  232. FSynchronizeEntry^.Thread := Self;
  233. FSynchronizeEntry^.SyncEvent := RtlEventCreate;
  234. end;
  235. procedure TThread.DoneSynchronizeEvent;
  236. begin
  237. if not Assigned(FSynchronizeEntry) then
  238. Exit;
  239. RtlEventDestroy(FSynchronizeEntry^.SyncEvent);
  240. Dispose(FSynchronizeEntry);
  241. FSynchronizeEntry := Nil;
  242. end;
  243. class procedure TThread.Synchronize(AThread: TThread; AMethod: TThreadMethod);
  244. begin
  245. { ensure that we have a TThread instance }
  246. if not Assigned(AThread) then
  247. AThread := CurrentThread;
  248. { the Synchronize event is instantiated on demand }
  249. AThread.InitSynchronizeEvent;
  250. AThread.FSynchronizeEntry^.Exception := Nil;
  251. AThread.FSynchronizeEntry^.Method := AMethod;
  252. ThreadQueueAppend(AThread.FSynchronizeEntry);
  253. AThread.FSynchronizeEntry^.Method := Nil;
  254. AThread.FSynchronizeEntry^.Next := Nil;
  255. end;
  256. procedure TThread.Synchronize(AMethod: TThreadMethod);
  257. begin
  258. TThread.Synchronize(self,AMethod);
  259. end;
  260. function CheckSynchronize(timeout : longint=0) : boolean;
  261. { assumes being called from GUI thread }
  262. var
  263. exceptobj: Exception;
  264. tmpentry: TThread.PThreadQueueEntry;
  265. begin
  266. result:=false;
  267. { first sanity check }
  268. if Not IsMultiThread then
  269. Exit
  270. { second sanity check }
  271. else if GetCurrentThreadID<>MainThreadID then
  272. raise EThread.CreateFmt(SCheckSynchronizeError,[GetCurrentThreadID])
  273. else
  274. begin
  275. if timeout>0 then
  276. begin
  277. RtlEventWaitFor(SynchronizeTimeoutEvent,timeout);
  278. end
  279. else
  280. RtlEventResetEvent(SynchronizeTimeoutEvent);
  281. System.EnterCriticalSection(ThreadQueueLock);
  282. try
  283. { Note: we don't need to pay attention to recursive calls to
  284. Synchronize as those calls will be executed in the context of
  285. the GUI thread and thus will be executed immediatly instead of
  286. queuing them }
  287. while Assigned(ThreadQueueHead) do begin
  288. { step 1: update the list }
  289. tmpentry := ThreadQueueHead;
  290. ThreadQueueHead := ThreadQueueHead^.Next;
  291. if not Assigned(ThreadQueueHead) then
  292. ThreadQueueTail := Nil;
  293. { step 2: execute the method }
  294. exceptobj := Nil;
  295. try
  296. ExecuteThreadQueueEntry(tmpentry);
  297. except
  298. exceptobj := Exception(AcquireExceptionObject);
  299. end;
  300. { step 3: error handling and cleanup }
  301. if Assigned(tmpentry^.SyncEvent) then begin
  302. { for Synchronize entries we pass back the Exception and trigger
  303. the event that Synchronize waits in }
  304. tmpentry^.Exception := exceptobj;
  305. RtlEventSetEvent(tmpentry^.SyncEvent)
  306. end else begin
  307. { for Queue entries we dispose the entry and raise the exception }
  308. Dispose(tmpentry);
  309. if Assigned(exceptobj) then
  310. raise exceptobj;
  311. end;
  312. end;
  313. finally
  314. System.LeaveCriticalSection(ThreadQueueLock);
  315. end;
  316. end;
  317. end;
  318. class function TThread.GetCurrentThread: TThread;
  319. begin
  320. { if this is the first time GetCurrentThread is called for an external thread
  321. we need to create a corresponding TExternalThread instance }
  322. Result := CurrentThreadVar;
  323. if not Assigned(Result) then begin
  324. Result := TExternalThread.Create;
  325. CurrentThreadVar := Result;
  326. end;
  327. end;
  328. class function TThread.GetIsSingleProcessor: Boolean;
  329. begin
  330. Result := FProcessorCount <= 1;
  331. end;
  332. procedure TThread.Queue(aMethod: TThreadMethod);
  333. begin
  334. Queue(Self, aMethod);
  335. end;
  336. class procedure TThread.Queue(aThread: TThread; aMethod: TThreadMethod); static;
  337. var
  338. queueentry: PThreadQueueEntry;
  339. begin
  340. { ensure that we have a valid TThread instance }
  341. if not Assigned(aThread) then
  342. aThread := CurrentThread;
  343. New(queueentry);
  344. FillChar(queueentry^, SizeOf(TThreadQueueEntry), 0);
  345. queueentry^.Thread := aThread;
  346. queueentry^.Method := aMethod;
  347. { the queueentry is freed by CheckSynchronize (or by RemoveQueuedEvents) }
  348. ThreadQueueAppend(queueentry);
  349. end;
  350. class procedure TThread.RemoveQueuedEvents(aThread: TThread; aMethod: TThreadMethod);
  351. var
  352. entry, tmpentry, lastentry: PThreadQueueEntry;
  353. begin
  354. { anything to do at all? }
  355. if not Assigned(aThread) or not Assigned(aMethod) then
  356. Exit;
  357. System.EnterCriticalSection(ThreadQueueLock);
  358. try
  359. lastentry := Nil;
  360. entry := ThreadQueueHead;
  361. while Assigned(entry) do begin
  362. { first check for the thread }
  363. if Assigned(aThread) and (entry^.Thread <> aThread) then begin
  364. lastentry := entry;
  365. entry := entry^.Next;
  366. Continue;
  367. end;
  368. { then check for the method }
  369. if entry^.Method <> aMethod then begin
  370. lastentry := entry;
  371. entry := entry^.Next;
  372. Continue;
  373. end;
  374. { skip entries added by Synchronize }
  375. if Assigned(entry^.SyncEvent) then begin
  376. lastentry := entry;
  377. entry := entry^.Next;
  378. Continue;
  379. end;
  380. { ok, we need to remove this entry }
  381. tmpentry := entry;
  382. if Assigned(lastentry) then
  383. lastentry^.Next := entry^.Next;
  384. entry := entry^.Next;
  385. if ThreadQueueHead = tmpentry then
  386. ThreadQueueHead := entry;
  387. if ThreadQueueTail = tmpentry then
  388. ThreadQueueTail := lastentry;
  389. { only dispose events added by Queue }
  390. if not Assigned(tmpentry^.SyncEvent) then
  391. Dispose(tmpentry);
  392. end;
  393. finally
  394. System.LeaveCriticalSection(ThreadQueueLock);
  395. end;
  396. end;
  397. class procedure TThread.RemoveQueuedEvents(aMethod: TThreadMethod);
  398. begin
  399. RemoveQueuedEvents(Nil, aMethod);
  400. end;
  401. class procedure TThread.RemoveQueuedEvents(aThread: TThread);
  402. begin
  403. RemoveQueuedEvents(aThread, Nil);
  404. end;
  405. class function TThread.CheckTerminated: Boolean;
  406. begin
  407. { this method only works with threads created by TThread, so we can make a
  408. shortcut here }
  409. if not Assigned(CurrentThreadVar) then
  410. raise EThreadExternalException.Create(SThreadExternal);
  411. Result := CurrentThreadVar.FTerminated;
  412. end;
  413. class procedure TThread.SetReturnValue(aValue: Integer);
  414. begin
  415. { this method only works with threads created by TThread, so we can make a
  416. shortcut here }
  417. if not Assigned(CurrentThreadVar) then
  418. raise EThreadExternalException.Create(SThreadExternal);
  419. CurrentThreadVar.FReturnValue := aValue;
  420. end;
  421. class function TThread.CreateAnonymousThread(aProc: TProcedure): TThread;
  422. begin
  423. if not Assigned(aProc) then
  424. raise Exception.Create(SNoProcGiven);
  425. Result := TAnonymousThread.Create(aProc);
  426. end;
  427. {$ifdef THREADNAME_IS_ANSISTRING}
  428. { the platform implements the AnsiString variant and the UnicodeString variant
  429. simply calls the AnsiString variant }
  430. class procedure TThread.NameThreadForDebugging(aThreadName: UnicodeString; aThreadID: TThreadID);
  431. begin
  432. NameThreadForDebugging(AnsiString(aThreadName), aThreadID);
  433. end;
  434. {$ifndef HAS_TTHREAD_NAMETHREADFORDEBUGGING}
  435. class procedure TThread.NameThreadForDebugging(aThreadName: AnsiString; aThreadID: TThreadID);
  436. begin
  437. { empty }
  438. end;
  439. {$endif}
  440. {$else}
  441. {$ifndef HAS_TTHREAD_NAMETHREADFORDEBUGGING}
  442. { the platform implements the UnicodeString variant and the AnsiString variant
  443. simply calls the UnicodeString variant }
  444. class procedure TThread.NameThreadForDebugging(aThreadName: UnicodeString; aThreadID: TThreadID);
  445. begin
  446. { empty }
  447. end;
  448. {$endif}
  449. class procedure TThread.NameThreadForDebugging(aThreadName: AnsiString; aThreadID: TThreadID);
  450. begin
  451. NameThreadForDebugging(UnicodeString(aThreadName), aThreadID);
  452. end;
  453. {$endif}
  454. class procedure TThread.Yield;
  455. begin
  456. ThreadSwitch;
  457. end;
  458. class procedure TThread.Sleep(aMilliseconds: Cardinal);
  459. begin
  460. SysUtils.Sleep(aMilliseconds);
  461. end;
  462. class procedure TThread.SpinWait(aIterations: LongWord);
  463. begin
  464. { yes, it's just a simple busy wait to burn some cpu cycles... and as the job
  465. of this loop is to burn CPU cycles we switch off any optimizations that
  466. could interfere with this (e.g. loop unrolling) }
  467. {$PUSH}
  468. {$OPTIMIZATION OFF}
  469. while aIterations > 0 do
  470. Dec(aIterations);
  471. {$POP}
  472. end;
  473. {$ifndef HAS_TTHREAD_GETSYSTEMTIMES}
  474. class procedure TThread.GetSystemTimes(out aSystemTimes: TSystemTimes);
  475. begin
  476. { by default we just return a zeroed out record }
  477. FillChar(aSystemTimes, SizeOf(aSystemTimes), 0);
  478. end;
  479. {$endif}
  480. class function TThread.GetTickCount: LongWord;
  481. begin
  482. Result := SysUtils.GetTickCount;
  483. end;
  484. class function TThread.GetTickCount64: QWord;
  485. begin
  486. Result := SysUtils.GetTickCount64;
  487. end;
  488. { TPersistent implementation }
  489. {$i persist.inc }
  490. {$i sllist.inc}
  491. {$i resref.inc}
  492. { TComponent implementation }
  493. {$i compon.inc}
  494. { TBasicAction implementation }
  495. {$i action.inc}
  496. { TDataModule implementation }
  497. {$i dm.inc}
  498. { Class and component registration routines }
  499. {$I cregist.inc}
  500. { Interface related stuff }
  501. {$I intf.inc}
  502. {**********************************************************************
  503. * Miscellaneous procedures and functions *
  504. **********************************************************************}
  505. function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; Strings: TStrings): Integer;
  506. var
  507. b, c : pchar;
  508. procedure SkipWhitespace;
  509. begin
  510. while (c^ in Whitespace) do
  511. inc (c);
  512. end;
  513. procedure AddString;
  514. var
  515. l : integer;
  516. s : string;
  517. begin
  518. l := c-b;
  519. if l > 0 then
  520. begin
  521. if assigned(Strings) then
  522. begin
  523. setlength(s, l);
  524. move (b^, s[1],l);
  525. Strings.Add (s);
  526. end;
  527. inc (result);
  528. end;
  529. end;
  530. var
  531. quoted : char;
  532. begin
  533. result := 0;
  534. c := Content;
  535. Quoted := #0;
  536. Separators := Separators + [#13, #10] - ['''','"'];
  537. SkipWhitespace;
  538. b := c;
  539. while (c^ <> #0) do
  540. begin
  541. if (c^ = Quoted) then
  542. begin
  543. if ((c+1)^ = Quoted) then
  544. inc (c)
  545. else
  546. Quoted := #0
  547. end
  548. else if (Quoted = #0) and (c^ in ['''','"']) then
  549. Quoted := c^;
  550. if (Quoted = #0) and (c^ in Separators) then
  551. begin
  552. AddString;
  553. inc (c);
  554. SkipWhitespace;
  555. b := c;
  556. end
  557. else
  558. inc (c);
  559. end;
  560. if (c <> b) then
  561. AddString;
  562. end;
  563. { Point and rectangle constructors }
  564. function Point(AX, AY: Integer): TPoint;
  565. begin
  566. with Result do
  567. begin
  568. X := AX;
  569. Y := AY;
  570. end;
  571. end;
  572. function SmallPoint(AX, AY: SmallInt): TSmallPoint;
  573. begin
  574. with Result do
  575. begin
  576. X := AX;
  577. Y := AY;
  578. end;
  579. end;
  580. function Rect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  581. begin
  582. with Result do
  583. begin
  584. Left := ALeft;
  585. Top := ATop;
  586. Right := ARight;
  587. Bottom := ABottom;
  588. end;
  589. end;
  590. function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  591. begin
  592. with Result do
  593. begin
  594. Left := ALeft;
  595. Top := ATop;
  596. Right := ALeft + AWidth;
  597. Bottom := ATop + AHeight;
  598. end;
  599. end;
  600. function PointsEqual(const P1, P2: TPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  601. begin
  602. { lazy, but should work }
  603. result:=QWord(P1)=QWord(P2);
  604. end;
  605. function PointsEqual(const P1, P2: TSmallPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  606. begin
  607. { lazy, but should work }
  608. result:=DWord(P1)=DWord(P2);
  609. end;
  610. function InvalidPoint(X, Y: Integer): Boolean;
  611. begin
  612. result:=(X=-1) and (Y=-1);
  613. end;
  614. function InvalidPoint(const At: TPoint): Boolean;
  615. begin
  616. result:=(At.x=-1) and (At.y=-1);
  617. end;
  618. function InvalidPoint(const At: TSmallPoint): Boolean;
  619. begin
  620. result:=(At.x=-1) and (At.y=-1);
  621. end;
  622. { Object filing routines }
  623. var
  624. IntConstList: TThreadList;
  625. type
  626. TIntConst = class
  627. IntegerType: PTypeInfo; // The integer type RTTI pointer
  628. IdentToIntFn: TIdentToInt; // Identifier to Integer conversion
  629. IntToIdentFn: TIntToIdent; // Integer to Identifier conversion
  630. constructor Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  631. AIntToIdent: TIntToIdent);
  632. end;
  633. constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  634. AIntToIdent: TIntToIdent);
  635. begin
  636. IntegerType := AIntegerType;
  637. IdentToIntFn := AIdentToInt;
  638. IntToIdentFn := AIntToIdent;
  639. end;
  640. procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;
  641. IntToIdentFn: TIntToIdent);
  642. begin
  643. IntConstList.Add(TIntConst.Create(IntegerType, IdentToIntFn, IntToIdentFn));
  644. end;
  645. function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
  646. var
  647. i: Integer;
  648. begin
  649. with IntConstList.LockList do
  650. try
  651. for i := 0 to Count - 1 do
  652. if TIntConst(Items[i]).IntegerType = AIntegerType then
  653. exit(TIntConst(Items[i]).IntToIdentFn);
  654. Result := nil;
  655. finally
  656. IntConstList.UnlockList;
  657. end;
  658. end;
  659. function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;
  660. var
  661. i: Integer;
  662. begin
  663. with IntConstList.LockList do
  664. try
  665. for i := 0 to Count - 1 do
  666. with TIntConst(Items[I]) do
  667. if TIntConst(Items[I]).IntegerType = AIntegerType then
  668. exit(IdentToIntFn);
  669. Result := nil;
  670. finally
  671. IntConstList.UnlockList;
  672. end;
  673. end;
  674. function IdentToInt(const Ident: String; var Int: LongInt;
  675. const Map: array of TIdentMapEntry): Boolean;
  676. var
  677. i: Integer;
  678. begin
  679. for i := Low(Map) to High(Map) do
  680. if CompareText(Map[i].Name, Ident) = 0 then
  681. begin
  682. Int := Map[i].Value;
  683. exit(True);
  684. end;
  685. Result := False;
  686. end;
  687. function IntToIdent(Int: LongInt; var Ident: String;
  688. const Map: array of TIdentMapEntry): Boolean;
  689. var
  690. i: Integer;
  691. begin
  692. for i := Low(Map) to High(Map) do
  693. if Map[i].Value = Int then
  694. begin
  695. Ident := Map[i].Name;
  696. exit(True);
  697. end;
  698. Result := False;
  699. end;
  700. function GlobalIdentToInt(const Ident: String; var Int: LongInt):boolean;
  701. var
  702. i : Integer;
  703. begin
  704. with IntConstList.LockList do
  705. try
  706. for i := 0 to Count - 1 do
  707. if TIntConst(Items[I]).IdentToIntFn(Ident, Int) then
  708. Exit(True);
  709. Result := false;
  710. finally
  711. IntConstList.UnlockList;
  712. end;
  713. end;
  714. { TPropFixup }
  715. // Tainted. TPropFixup is being removed.
  716. Type
  717. TInitHandler = Class(TObject)
  718. AHandler : TInitComponentHandler;
  719. AClass : TComponentClass;
  720. end;
  721. Var
  722. InitHandlerList : TList;
  723. FindGlobalComponentList : TList;
  724. procedure RegisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  725. begin
  726. if not(assigned(FindGlobalComponentList)) then
  727. FindGlobalComponentList:=TList.Create;
  728. if FindGlobalComponentList.IndexOf(Pointer(AFindGlobalComponent))<0 then
  729. FindGlobalComponentList.Add(Pointer(AFindGlobalComponent));
  730. end;
  731. procedure UnregisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  732. begin
  733. if assigned(FindGlobalComponentList) then
  734. FindGlobalComponentList.Remove(Pointer(AFindGlobalComponent));
  735. end;
  736. function FindGlobalComponent(const Name: string): TComponent;
  737. var
  738. i : sizeint;
  739. begin
  740. FindGlobalComponent:=nil;
  741. if assigned(FindGlobalComponentList) then
  742. begin
  743. for i:=FindGlobalComponentList.Count-1 downto 0 do
  744. begin
  745. FindGlobalComponent:=TFindGlobalComponent(FindGlobalComponentList[i])(name);
  746. if assigned(FindGlobalComponent) then
  747. break;
  748. end;
  749. end;
  750. end;
  751. procedure RegisterInitComponentHandler(ComponentClass: TComponentClass; Handler: TInitComponentHandler);
  752. Var
  753. I : Integer;
  754. H: TInitHandler;
  755. begin
  756. If (InitHandlerList=Nil) then
  757. InitHandlerList:=TList.Create;
  758. H:=TInitHandler.Create;
  759. H.Aclass:=ComponentClass;
  760. H.AHandler:=Handler;
  761. try
  762. With InitHandlerList do
  763. begin
  764. I:=0;
  765. While (I<Count) and not H.AClass.InheritsFrom(TInitHandler(Items[I]).AClass) do
  766. Inc(I);
  767. { override? }
  768. if (I<Count) and (TInitHandler(Items[I]).AClass=H.AClass) then
  769. begin
  770. TInitHandler(Items[I]).AHandler:=Handler;
  771. H.Free;
  772. end
  773. else
  774. InitHandlerList.Insert(I,H);
  775. end;
  776. except
  777. H.Free;
  778. raise;
  779. end;
  780. end;
  781. { all targets should at least include the sysres.inc dummy in the system unit to compile this }
  782. function CreateComponentfromRes(const res : string;Inst : THandle;var Component : TComponent) : Boolean;
  783. var
  784. ResStream : TResourceStream;
  785. begin
  786. result:=true;
  787. if Inst=0 then
  788. Inst:=HInstance;
  789. try
  790. ResStream:=TResourceStream.Create(Inst,res,RT_RCDATA);
  791. try
  792. Component:=ResStream.ReadComponent(Component);
  793. finally
  794. ResStream.Free;
  795. end;
  796. except
  797. on EResNotFound do
  798. result:=false;
  799. end;
  800. end;
  801. function DefaultInitHandler(Instance: TComponent; RootAncestor: TClass): Boolean;
  802. function doinit(_class : TClass) : boolean;
  803. begin
  804. result:=false;
  805. if (_class.ClassType=TComponent) or (_class.ClassType=RootAncestor) then
  806. exit;
  807. result:=doinit(_class.ClassParent);
  808. result:=CreateComponentfromRes(_class.ClassName,0,Instance) or result;
  809. end;
  810. begin
  811. GlobalNameSpace.BeginWrite;
  812. try
  813. result:=doinit(Instance.ClassType);
  814. finally
  815. GlobalNameSpace.EndWrite;
  816. end;
  817. end;
  818. function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
  819. Var
  820. I : Integer;
  821. begin
  822. I:=0;
  823. if not Assigned(InitHandlerList) then begin
  824. Result := True;
  825. Exit;
  826. end;
  827. Result:=False;
  828. With InitHandlerList do
  829. begin
  830. I:=0;
  831. // Instance is the normally the lowest one, so that one should be used when searching.
  832. While Not result and (I<Count) do
  833. begin
  834. If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
  835. Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
  836. Inc(I);
  837. end;
  838. end;
  839. end;
  840. function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
  841. begin
  842. { !!!: Too Win32-specific }
  843. InitComponentRes := False;
  844. end;
  845. function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
  846. begin
  847. { !!!: Too Win32-specific }
  848. ReadComponentRes := nil;
  849. end;
  850. function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
  851. begin
  852. { !!!: Too Win32-specific in VCL }
  853. ReadComponentResEx := nil;
  854. end;
  855. function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
  856. var
  857. FileStream: TStream;
  858. begin
  859. FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
  860. try
  861. Result := FileStream.ReadComponentRes(Instance);
  862. finally
  863. FileStream.Free;
  864. end;
  865. end;
  866. procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
  867. var
  868. FileStream: TStream;
  869. begin
  870. FileStream := TFileStream.Create(FileName, fmCreate);
  871. try
  872. FileStream.WriteComponentRes(Instance.ClassName, Instance);
  873. finally
  874. FileStream.Free;
  875. end;
  876. end;
  877. Function FindNestedComponent(Root : TComponent; APath : String; CStyle : Boolean = True) : TComponent;
  878. Function GetNextName : String; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  879. Var
  880. P : Integer;
  881. CM : Boolean;
  882. begin
  883. P:=Pos('.',APath);
  884. CM:=False;
  885. If (P=0) then
  886. begin
  887. If CStyle then
  888. begin
  889. P:=Pos('->',APath);
  890. CM:=P<>0;
  891. end;
  892. If (P=0) Then
  893. P:=Length(APath)+1;
  894. end;
  895. Result:=Copy(APath,1,P-1);
  896. Delete(APath,1,P+Ord(CM));
  897. end;
  898. Var
  899. C : TComponent;
  900. S : String;
  901. begin
  902. If (APath='') then
  903. Result:=Nil
  904. else
  905. begin
  906. Result:=Root;
  907. While (APath<>'') And (Result<>Nil) do
  908. begin
  909. C:=Result;
  910. S:=Uppercase(GetNextName);
  911. Result:=C.FindComponent(S);
  912. If (Result=Nil) And (S='OWNER') then
  913. Result:=C;
  914. end;
  915. end;
  916. end;
  917. threadvar
  918. GlobalLoaded, GlobalLists: TFpList;
  919. procedure BeginGlobalLoading;
  920. begin
  921. if not Assigned(GlobalLists) then
  922. GlobalLists := TFpList.Create;
  923. GlobalLists.Add(GlobalLoaded);
  924. GlobalLoaded := TFpList.Create;
  925. end;
  926. { Notify all global components that they have been loaded completely }
  927. procedure NotifyGlobalLoading;
  928. var
  929. i: Integer;
  930. begin
  931. for i := 0 to GlobalLoaded.Count - 1 do
  932. TComponent(GlobalLoaded[i]).Loaded;
  933. end;
  934. procedure EndGlobalLoading;
  935. begin
  936. { Free the memory occupied by BeginGlobalLoading }
  937. GlobalLoaded.Free;
  938. GlobalLoaded := TFpList(GlobalLists.Last);
  939. GlobalLists.Delete(GlobalLists.Count - 1);
  940. if GlobalLists.Count = 0 then
  941. begin
  942. GlobalLists.Free;
  943. GlobalLists := nil;
  944. end;
  945. end;
  946. function CollectionsEqual(C1, C2: TCollection): Boolean;
  947. begin
  948. // !!!: Implement this
  949. CollectionsEqual:=false;
  950. end;
  951. function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;
  952. procedure stream_collection(s : tstream;c : tcollection;o : tcomponent);
  953. var
  954. w : twriter;
  955. begin
  956. w:=twriter.create(s,4096);
  957. try
  958. w.root:=o;
  959. w.flookuproot:=o;
  960. w.writecollection(c);
  961. finally
  962. w.free;
  963. end;
  964. end;
  965. var
  966. s1,s2 : tmemorystream;
  967. begin
  968. result:=false;
  969. if (c1.classtype<>c2.classtype) or
  970. (c1.count<>c2.count) then
  971. exit;
  972. if c1.count = 0 then
  973. begin
  974. result:= true;
  975. exit;
  976. end;
  977. s1:=tmemorystream.create;
  978. try
  979. s2:=tmemorystream.create;
  980. try
  981. stream_collection(s1,c1,owner1);
  982. stream_collection(s2,c2,owner2);
  983. result:=(s1.size=s2.size) and (CompareChar(s1.memory^,s2.memory^,s1.size)=0);
  984. finally
  985. s2.free;
  986. end;
  987. finally
  988. s1.free;
  989. end;
  990. end;
  991. { Object conversion routines }
  992. type
  993. CharToOrdFuncty = Function(var charpo: Pointer): Cardinal;
  994. function CharToOrd(var P: Pointer): Cardinal;
  995. begin
  996. result:= ord(pchar(P)^);
  997. inc(pchar(P));
  998. end;
  999. function WideCharToOrd(var P: Pointer): Cardinal;
  1000. begin
  1001. result:= ord(pwidechar(P)^);
  1002. inc(pwidechar(P));
  1003. end;
  1004. function Utf8ToOrd(var P:Pointer): Cardinal;
  1005. begin
  1006. // Should also check for illegal utf8 combinations
  1007. Result := Ord(PChar(P)^);
  1008. Inc(P);
  1009. if (Result and $80) <> 0 then
  1010. if (Ord(Result) and %11100000) = %11000000 then begin
  1011. Result := ((Result and %00011111) shl 6)
  1012. or (ord(PChar(P)^) and %00111111);
  1013. Inc(P);
  1014. end else if (Ord(Result) and %11110000) = %11100000 then begin
  1015. Result := ((Result and %00011111) shl 12)
  1016. or ((ord(PChar(P)^) and %00111111) shl 6)
  1017. or (ord((PChar(P)+1)^) and %00111111);
  1018. Inc(P,2);
  1019. end else begin
  1020. Result := ((ord(Result) and %00011111) shl 18)
  1021. or ((ord(PChar(P)^) and %00111111) shl 12)
  1022. or ((ord((PChar(P)+1)^) and %00111111) shl 6)
  1023. or (ord((PChar(P)+2)^) and %00111111);
  1024. Inc(P,3);
  1025. end;
  1026. end;
  1027. procedure ObjectBinaryToText(Input, Output: TStream; Encoding: TObjectTextEncoding);
  1028. procedure OutStr(s: String);
  1029. begin
  1030. if Length(s) > 0 then
  1031. Output.Write(s[1], Length(s));
  1032. end;
  1033. procedure OutLn(s: String);
  1034. begin
  1035. OutStr(s + LineEnding);
  1036. end;
  1037. procedure Outchars(P, LastP : Pointer; CharToOrdFunc: CharToOrdFuncty;
  1038. UseBytes: boolean = false);
  1039. var
  1040. res, NewStr: String;
  1041. w: Cardinal;
  1042. InString, NewInString: Boolean;
  1043. begin
  1044. if p = nil then begin
  1045. res:= '''''';
  1046. end
  1047. else
  1048. begin
  1049. res := '';
  1050. InString := False;
  1051. while P < LastP do
  1052. begin
  1053. NewInString := InString;
  1054. w := CharToOrdfunc(P);
  1055. if w = ord('''') then
  1056. begin //quote char
  1057. if not InString then
  1058. NewInString := True;
  1059. NewStr := '''''';
  1060. end
  1061. else if (Ord(w) >= 32) and ((Ord(w) < 127) or (UseBytes and (Ord(w)<256))) then
  1062. begin //printable ascii or bytes
  1063. if not InString then
  1064. NewInString := True;
  1065. NewStr := char(w);
  1066. end
  1067. else
  1068. begin //ascii control chars, non ascii
  1069. if InString then
  1070. NewInString := False;
  1071. NewStr := '#' + IntToStr(w);
  1072. end;
  1073. if NewInString <> InString then
  1074. begin
  1075. NewStr := '''' + NewStr;
  1076. InString := NewInString;
  1077. end;
  1078. res := res + NewStr;
  1079. end;
  1080. if InString then
  1081. res := res + '''';
  1082. end;
  1083. OutStr(res);
  1084. end;
  1085. procedure OutString(s: String);
  1086. begin
  1087. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd,Encoding=oteLFM);
  1088. end;
  1089. procedure OutWString(W: WideString);
  1090. begin
  1091. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1092. end;
  1093. procedure OutUString(W: UnicodeString);
  1094. begin
  1095. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1096. end;
  1097. procedure OutUtf8Str(s: String);
  1098. begin
  1099. if Encoding=oteLFM then
  1100. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd)
  1101. else
  1102. OutChars(Pointer(S),PChar(S)+Length(S),@Utf8ToOrd);
  1103. end;
  1104. function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1105. begin
  1106. Result:=Input.ReadWord;
  1107. Result:=LEtoN(Result);
  1108. end;
  1109. function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1110. begin
  1111. Result:=Input.ReadDWord;
  1112. Result:=LEtoN(Result);
  1113. end;
  1114. function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1115. begin
  1116. Input.ReadBuffer(Result,sizeof(Result));
  1117. Result:=LEtoN(Result);
  1118. end;
  1119. {$ifndef FPUNONE}
  1120. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1121. function ExtendedToDouble(e : pointer) : double;
  1122. var mant : qword;
  1123. exp : smallint;
  1124. sign : boolean;
  1125. d : qword;
  1126. begin
  1127. move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
  1128. move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
  1129. mant:=LEtoN(mant);
  1130. exp:=LetoN(word(exp));
  1131. sign:=(exp and $8000)<>0;
  1132. if sign then exp:=exp and $7FFF;
  1133. case exp of
  1134. 0 : mant:=0; //if denormalized, value is too small for double,
  1135. //so it's always zero
  1136. $7FFF : exp:=2047 //either infinity or NaN
  1137. else
  1138. begin
  1139. dec(exp,16383-1023);
  1140. if (exp>=-51) and (exp<=0) then //can be denormalized
  1141. begin
  1142. mant:=mant shr (-exp);
  1143. exp:=0;
  1144. end
  1145. else
  1146. if (exp<-51) or (exp>2046) then //exponent too large.
  1147. begin
  1148. Result:=0;
  1149. exit;
  1150. end
  1151. else //normalized value
  1152. mant:=mant shl 1; //hide most significant bit
  1153. end;
  1154. end;
  1155. d:=word(exp);
  1156. d:=d shl 52;
  1157. mant:=mant shr 12;
  1158. d:=d or mant;
  1159. if sign then d:=d or $8000000000000000;
  1160. Result:=pdouble(@d)^;
  1161. end;
  1162. {$ENDIF}
  1163. {$endif}
  1164. function ReadInt(ValueType: TValueType): Int64;
  1165. begin
  1166. case ValueType of
  1167. vaInt8: Result := ShortInt(Input.ReadByte);
  1168. vaInt16: Result := SmallInt(ReadWord);
  1169. vaInt32: Result := LongInt(ReadDWord);
  1170. vaInt64: Result := Int64(ReadQWord);
  1171. end;
  1172. end;
  1173. function ReadInt: Int64;
  1174. begin
  1175. Result := ReadInt(TValueType(Input.ReadByte));
  1176. end;
  1177. {$ifndef FPUNONE}
  1178. function ReadExtended : extended;
  1179. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1180. var ext : array[0..9] of byte;
  1181. {$ENDIF}
  1182. begin
  1183. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1184. Input.ReadBuffer(ext[0],10);
  1185. Result:=ExtendedToDouble(@(ext[0]));
  1186. {$ELSE}
  1187. Input.ReadBuffer(Result,sizeof(Result));
  1188. {$ENDIF}
  1189. end;
  1190. {$endif}
  1191. function ReadSStr: String;
  1192. var
  1193. len: Byte;
  1194. begin
  1195. len := Input.ReadByte;
  1196. SetLength(Result, len);
  1197. if (len > 0) then
  1198. Input.ReadBuffer(Result[1], len);
  1199. end;
  1200. function ReadLStr: String;
  1201. var
  1202. len: DWord;
  1203. begin
  1204. len := ReadDWord;
  1205. SetLength(Result, len);
  1206. if (len > 0) then
  1207. Input.ReadBuffer(Result[1], len);
  1208. end;
  1209. function ReadWStr: WideString;
  1210. var
  1211. len: DWord;
  1212. {$IFDEF ENDIAN_BIG}
  1213. i : integer;
  1214. {$ENDIF}
  1215. begin
  1216. len := ReadDWord;
  1217. SetLength(Result, len);
  1218. if (len > 0) then
  1219. begin
  1220. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1221. {$IFDEF ENDIAN_BIG}
  1222. for i:=1 to len do
  1223. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1224. {$ENDIF}
  1225. end;
  1226. end;
  1227. function ReadUStr: UnicodeString;
  1228. var
  1229. len: DWord;
  1230. {$IFDEF ENDIAN_BIG}
  1231. i : integer;
  1232. {$ENDIF}
  1233. begin
  1234. len := ReadDWord;
  1235. SetLength(Result, len);
  1236. if (len > 0) then
  1237. begin
  1238. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1239. {$IFDEF ENDIAN_BIG}
  1240. for i:=1 to len do
  1241. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1242. {$ENDIF}
  1243. end;
  1244. end;
  1245. procedure ReadPropList(indent: String);
  1246. procedure ProcessValue(ValueType: TValueType; Indent: String);
  1247. procedure ProcessBinary;
  1248. var
  1249. ToDo, DoNow, i: LongInt;
  1250. lbuf: array[0..31] of Byte;
  1251. s: String;
  1252. begin
  1253. ToDo := ReadDWord;
  1254. OutLn('{');
  1255. while ToDo > 0 do begin
  1256. DoNow := ToDo;
  1257. if DoNow > 32 then DoNow := 32;
  1258. Dec(ToDo, DoNow);
  1259. s := Indent + ' ';
  1260. Input.ReadBuffer(lbuf, DoNow);
  1261. for i := 0 to DoNow - 1 do
  1262. s := s + IntToHex(lbuf[i], 2);
  1263. OutLn(s);
  1264. end;
  1265. OutLn(indent + '}');
  1266. end;
  1267. var
  1268. s: String;
  1269. { len: LongInt; }
  1270. IsFirst: Boolean;
  1271. {$ifndef FPUNONE}
  1272. ext: Extended;
  1273. {$endif}
  1274. begin
  1275. case ValueType of
  1276. vaList: begin
  1277. OutStr('(');
  1278. IsFirst := True;
  1279. while True do begin
  1280. ValueType := TValueType(Input.ReadByte);
  1281. if ValueType = vaNull then break;
  1282. if IsFirst then begin
  1283. OutLn('');
  1284. IsFirst := False;
  1285. end;
  1286. OutStr(Indent + ' ');
  1287. ProcessValue(ValueType, Indent + ' ');
  1288. end;
  1289. OutLn(Indent + ')');
  1290. end;
  1291. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  1292. vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
  1293. vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
  1294. vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
  1295. {$ifndef FPUNONE}
  1296. vaExtended: begin
  1297. ext:=ReadExtended;
  1298. Str(ext,S);// Do not use localized strings.
  1299. OutLn(S);
  1300. end;
  1301. {$endif}
  1302. vaString: begin
  1303. OutString(ReadSStr);
  1304. OutLn('');
  1305. end;
  1306. vaIdent: OutLn(ReadSStr);
  1307. vaFalse: OutLn('False');
  1308. vaTrue: OutLn('True');
  1309. vaBinary: ProcessBinary;
  1310. vaSet: begin
  1311. OutStr('[');
  1312. IsFirst := True;
  1313. while True do begin
  1314. s := ReadSStr;
  1315. if Length(s) = 0 then break;
  1316. if not IsFirst then OutStr(', ');
  1317. IsFirst := False;
  1318. OutStr(s);
  1319. end;
  1320. OutLn(']');
  1321. end;
  1322. vaLString:
  1323. begin
  1324. OutString(ReadLStr);
  1325. OutLn('');
  1326. end;
  1327. vaWString:
  1328. begin
  1329. OutWString(ReadWStr);
  1330. OutLn('');
  1331. end;
  1332. vaUString:
  1333. begin
  1334. OutWString(ReadWStr);
  1335. OutLn('');
  1336. end;
  1337. vaNil:
  1338. OutLn('nil');
  1339. vaCollection: begin
  1340. OutStr('<');
  1341. while Input.ReadByte <> 0 do begin
  1342. OutLn(Indent);
  1343. Input.Seek(-1, soFromCurrent);
  1344. OutStr(indent + ' item');
  1345. ValueType := TValueType(Input.ReadByte);
  1346. if ValueType <> vaList then
  1347. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  1348. OutLn('');
  1349. ReadPropList(indent + ' ');
  1350. OutStr(indent + ' end');
  1351. end;
  1352. OutLn('>');
  1353. end;
  1354. {vaSingle: begin OutLn('!!Single!!'); exit end;
  1355. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  1356. vaDate: begin OutLn('!!Date!!'); exit end;}
  1357. vaUTF8String: begin
  1358. OutUtf8Str(ReadLStr);
  1359. OutLn('');
  1360. end;
  1361. else
  1362. Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
  1363. end;
  1364. end;
  1365. begin
  1366. while Input.ReadByte <> 0 do begin
  1367. Input.Seek(-1, soFromCurrent);
  1368. OutStr(indent + ReadSStr + ' = ');
  1369. ProcessValue(TValueType(Input.ReadByte), Indent);
  1370. end;
  1371. end;
  1372. procedure ReadObject(indent: String);
  1373. var
  1374. b: Byte;
  1375. ObjClassName, ObjName: String;
  1376. ChildPos: LongInt;
  1377. begin
  1378. // Check for FilerFlags
  1379. b := Input.ReadByte;
  1380. if (b and $f0) = $f0 then begin
  1381. if (b and 2) <> 0 then ChildPos := ReadInt;
  1382. end else begin
  1383. b := 0;
  1384. Input.Seek(-1, soFromCurrent);
  1385. end;
  1386. ObjClassName := ReadSStr;
  1387. ObjName := ReadSStr;
  1388. OutStr(Indent);
  1389. if (b and 1) <> 0 then OutStr('inherited')
  1390. else
  1391. if (b and 4) <> 0 then OutStr('inline')
  1392. else OutStr('object');
  1393. OutStr(' ');
  1394. if ObjName <> '' then
  1395. OutStr(ObjName + ': ');
  1396. OutStr(ObjClassName);
  1397. if (b and 2) <> 0 then OutStr('[' + IntToStr(ChildPos) + ']');
  1398. OutLn('');
  1399. ReadPropList(indent + ' ');
  1400. while Input.ReadByte <> 0 do begin
  1401. Input.Seek(-1, soFromCurrent);
  1402. ReadObject(indent + ' ');
  1403. end;
  1404. OutLn(indent + 'end');
  1405. end;
  1406. type
  1407. PLongWord = ^LongWord;
  1408. const
  1409. signature: PChar = 'TPF0';
  1410. begin
  1411. if Input.ReadDWord <> PLongWord(Pointer(signature))^ then
  1412. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  1413. ReadObject('');
  1414. end;
  1415. procedure ObjectBinaryToText(Input, Output: TStream);
  1416. begin
  1417. ObjectBinaryToText(Input,Output,oteDFM);
  1418. end;
  1419. procedure ObjectTextToBinary(Input, Output: TStream);
  1420. var
  1421. parser: TParser;
  1422. procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1423. begin
  1424. w:=NtoLE(w);
  1425. Output.WriteWord(w);
  1426. end;
  1427. procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1428. begin
  1429. lw:=NtoLE(lw);
  1430. Output.WriteDWord(lw);
  1431. end;
  1432. procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1433. begin
  1434. qw:=NtoLE(qw);
  1435. Output.WriteBuffer(qw,sizeof(qword));
  1436. end;
  1437. {$ifndef FPUNONE}
  1438. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1439. procedure DoubleToExtended(d : double; e : pointer);
  1440. var mant : qword;
  1441. exp : smallint;
  1442. sign : boolean;
  1443. begin
  1444. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  1445. exp :=(qword(d) shr 52) and $7FF;
  1446. sign:=(qword(d) and $8000000000000000)<>0;
  1447. case exp of
  1448. 0 : begin
  1449. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  1450. begin
  1451. exp:=16383-1022;
  1452. while (mant and $8000000000000000)=0 do
  1453. begin
  1454. dec(exp);
  1455. mant:=mant shl 1;
  1456. end;
  1457. dec(exp); //don't shift, most significant bit is not hidden in extended
  1458. end;
  1459. end;
  1460. 2047 : exp:=$7FFF //either infinity or NaN
  1461. else
  1462. begin
  1463. inc(exp,16383-1023);
  1464. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  1465. end;
  1466. end;
  1467. if sign then exp:=exp or $8000;
  1468. mant:=NtoLE(mant);
  1469. exp:=NtoLE(word(exp));
  1470. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  1471. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  1472. end;
  1473. {$ENDIF}
  1474. procedure WriteExtended(e : extended);
  1475. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1476. var ext : array[0..9] of byte;
  1477. {$ENDIF}
  1478. begin
  1479. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1480. DoubleToExtended(e,@(ext[0]));
  1481. Output.WriteBuffer(ext[0],10);
  1482. {$ELSE}
  1483. Output.WriteBuffer(e,sizeof(e));
  1484. {$ENDIF}
  1485. end;
  1486. {$endif}
  1487. procedure WriteString(s: String);
  1488. var size : byte;
  1489. begin
  1490. if length(s)>255 then size:=255
  1491. else size:=length(s);
  1492. Output.WriteByte(size);
  1493. if Length(s) > 0 then
  1494. Output.WriteBuffer(s[1], size);
  1495. end;
  1496. procedure WriteLString(Const s: String);
  1497. begin
  1498. WriteDWord(Length(s));
  1499. if Length(s) > 0 then
  1500. Output.WriteBuffer(s[1], Length(s));
  1501. end;
  1502. procedure WriteWString(Const s: WideString);
  1503. var len : longword;
  1504. {$IFDEF ENDIAN_BIG}
  1505. i : integer;
  1506. ws : widestring;
  1507. {$ENDIF}
  1508. begin
  1509. len:=Length(s);
  1510. WriteDWord(len);
  1511. if len > 0 then
  1512. begin
  1513. {$IFDEF ENDIAN_BIG}
  1514. setlength(ws,len);
  1515. for i:=1 to len do
  1516. ws[i]:=widechar(SwapEndian(word(s[i])));
  1517. Output.WriteBuffer(ws[1], len*sizeof(widechar));
  1518. {$ELSE}
  1519. Output.WriteBuffer(s[1], len*sizeof(widechar));
  1520. {$ENDIF}
  1521. end;
  1522. end;
  1523. procedure WriteInteger(value: Int64);
  1524. begin
  1525. if (value >= -128) and (value <= 127) then begin
  1526. Output.WriteByte(Ord(vaInt8));
  1527. Output.WriteByte(byte(value));
  1528. end else if (value >= -32768) and (value <= 32767) then begin
  1529. Output.WriteByte(Ord(vaInt16));
  1530. WriteWord(word(value));
  1531. end else if (value >= -2147483648) and (value <= 2147483647) then begin
  1532. Output.WriteByte(Ord(vaInt32));
  1533. WriteDWord(longword(value));
  1534. end else begin
  1535. Output.WriteByte(ord(vaInt64));
  1536. WriteQWord(qword(value));
  1537. end;
  1538. end;
  1539. procedure ProcessWideString(const left : widestring);
  1540. var ws : widestring;
  1541. begin
  1542. ws:=left+parser.TokenWideString;
  1543. while parser.NextToken = '+' do
  1544. begin
  1545. parser.NextToken; // Get next string fragment
  1546. if not (parser.Token in [toString,toWString]) then
  1547. parser.CheckToken(toWString);
  1548. ws:=ws+parser.TokenWideString;
  1549. end;
  1550. Output.WriteByte(Ord(vaWstring));
  1551. WriteWString(ws);
  1552. end;
  1553. procedure ProcessProperty; forward;
  1554. procedure ProcessValue;
  1555. var
  1556. {$ifndef FPUNONE}
  1557. flt: Extended;
  1558. {$endif}
  1559. s: String;
  1560. stream: TMemoryStream;
  1561. begin
  1562. case parser.Token of
  1563. toInteger:
  1564. begin
  1565. WriteInteger(parser.TokenInt);
  1566. parser.NextToken;
  1567. end;
  1568. {$ifndef FPUNONE}
  1569. toFloat:
  1570. begin
  1571. Output.WriteByte(Ord(vaExtended));
  1572. flt := Parser.TokenFloat;
  1573. WriteExtended(flt);
  1574. parser.NextToken;
  1575. end;
  1576. {$endif}
  1577. toString:
  1578. begin
  1579. s := parser.TokenString;
  1580. while parser.NextToken = '+' do
  1581. begin
  1582. parser.NextToken; // Get next string fragment
  1583. case parser.Token of
  1584. toString : s:=s+parser.TokenString;
  1585. toWString : begin
  1586. ProcessWideString(s);
  1587. exit;
  1588. end
  1589. else parser.CheckToken(toString);
  1590. end;
  1591. end;
  1592. if (length(S)>255) then
  1593. begin
  1594. Output.WriteByte(Ord(vaLString));
  1595. WriteLString(S);
  1596. end
  1597. else
  1598. begin
  1599. Output.WriteByte(Ord(vaString));
  1600. WriteString(s);
  1601. end;
  1602. end;
  1603. toWString:
  1604. ProcessWideString('');
  1605. toSymbol:
  1606. begin
  1607. if CompareText(parser.TokenString, 'True') = 0 then
  1608. Output.WriteByte(Ord(vaTrue))
  1609. else if CompareText(parser.TokenString, 'False') = 0 then
  1610. Output.WriteByte(Ord(vaFalse))
  1611. else if CompareText(parser.TokenString, 'nil') = 0 then
  1612. Output.WriteByte(Ord(vaNil))
  1613. else
  1614. begin
  1615. Output.WriteByte(Ord(vaIdent));
  1616. WriteString(parser.TokenComponentIdent);
  1617. end;
  1618. Parser.NextToken;
  1619. end;
  1620. // Set
  1621. '[':
  1622. begin
  1623. parser.NextToken;
  1624. Output.WriteByte(Ord(vaSet));
  1625. if parser.Token <> ']' then
  1626. while True do
  1627. begin
  1628. parser.CheckToken(toSymbol);
  1629. WriteString(parser.TokenString);
  1630. parser.NextToken;
  1631. if parser.Token = ']' then
  1632. break;
  1633. parser.CheckToken(',');
  1634. parser.NextToken;
  1635. end;
  1636. Output.WriteByte(0);
  1637. parser.NextToken;
  1638. end;
  1639. // List
  1640. '(':
  1641. begin
  1642. parser.NextToken;
  1643. Output.WriteByte(Ord(vaList));
  1644. while parser.Token <> ')' do
  1645. ProcessValue;
  1646. Output.WriteByte(0);
  1647. parser.NextToken;
  1648. end;
  1649. // Collection
  1650. '<':
  1651. begin
  1652. parser.NextToken;
  1653. Output.WriteByte(Ord(vaCollection));
  1654. while parser.Token <> '>' do
  1655. begin
  1656. parser.CheckTokenSymbol('item');
  1657. parser.NextToken;
  1658. // ConvertOrder
  1659. Output.WriteByte(Ord(vaList));
  1660. while not parser.TokenSymbolIs('end') do
  1661. ProcessProperty;
  1662. parser.NextToken; // Skip 'end'
  1663. Output.WriteByte(0);
  1664. end;
  1665. Output.WriteByte(0);
  1666. parser.NextToken;
  1667. end;
  1668. // Binary data
  1669. '{':
  1670. begin
  1671. Output.WriteByte(Ord(vaBinary));
  1672. stream := TMemoryStream.Create;
  1673. try
  1674. parser.HexToBinary(stream);
  1675. WriteDWord(stream.Size);
  1676. Output.WriteBuffer(Stream.Memory^, stream.Size);
  1677. finally
  1678. stream.Free;
  1679. end;
  1680. parser.NextToken;
  1681. end;
  1682. else
  1683. parser.Error(SInvalidProperty);
  1684. end;
  1685. end;
  1686. procedure ProcessProperty;
  1687. var
  1688. name: String;
  1689. begin
  1690. // Get name of property
  1691. parser.CheckToken(toSymbol);
  1692. name := parser.TokenString;
  1693. while True do begin
  1694. parser.NextToken;
  1695. if parser.Token <> '.' then break;
  1696. parser.NextToken;
  1697. parser.CheckToken(toSymbol);
  1698. name := name + '.' + parser.TokenString;
  1699. end;
  1700. WriteString(name);
  1701. parser.CheckToken('=');
  1702. parser.NextToken;
  1703. ProcessValue;
  1704. end;
  1705. procedure ProcessObject;
  1706. var
  1707. Flags: Byte;
  1708. ObjectName, ObjectType: String;
  1709. ChildPos: Integer;
  1710. begin
  1711. if parser.TokenSymbolIs('OBJECT') then
  1712. Flags :=0 { IsInherited := False }
  1713. else begin
  1714. if parser.TokenSymbolIs('INHERITED') then
  1715. Flags := 1 { IsInherited := True; }
  1716. else begin
  1717. parser.CheckTokenSymbol('INLINE');
  1718. Flags := 4;
  1719. end;
  1720. end;
  1721. parser.NextToken;
  1722. parser.CheckToken(toSymbol);
  1723. ObjectName := '';
  1724. ObjectType := parser.TokenString;
  1725. parser.NextToken;
  1726. if parser.Token = ':' then begin
  1727. parser.NextToken;
  1728. parser.CheckToken(toSymbol);
  1729. ObjectName := ObjectType;
  1730. ObjectType := parser.TokenString;
  1731. parser.NextToken;
  1732. if parser.Token = '[' then begin
  1733. parser.NextToken;
  1734. ChildPos := parser.TokenInt;
  1735. parser.NextToken;
  1736. parser.CheckToken(']');
  1737. parser.NextToken;
  1738. Flags := Flags or 2;
  1739. end;
  1740. end;
  1741. if Flags <> 0 then begin
  1742. Output.WriteByte($f0 or Flags);
  1743. if (Flags and 2) <> 0 then
  1744. WriteInteger(ChildPos);
  1745. end;
  1746. WriteString(ObjectType);
  1747. WriteString(ObjectName);
  1748. // Convert property list
  1749. while not (parser.TokenSymbolIs('END') or
  1750. parser.TokenSymbolIs('OBJECT') or
  1751. parser.TokenSymbolIs('INHERITED') or
  1752. parser.TokenSymbolIs('INLINE')) do
  1753. ProcessProperty;
  1754. Output.WriteByte(0); // Terminate property list
  1755. // Convert child objects
  1756. while not parser.TokenSymbolIs('END') do ProcessObject;
  1757. parser.NextToken; // Skip end token
  1758. Output.WriteByte(0); // Terminate property list
  1759. end;
  1760. const
  1761. signature: PChar = 'TPF0';
  1762. begin
  1763. parser := TParser.Create(Input);
  1764. try
  1765. Output.WriteBuffer(signature[0], 4);
  1766. ProcessObject;
  1767. finally
  1768. parser.Free;
  1769. end;
  1770. end;
  1771. procedure ObjectResourceToText(Input, Output: TStream);
  1772. begin
  1773. Input.ReadResHeader;
  1774. ObjectBinaryToText(Input, Output);
  1775. end;
  1776. procedure ObjectTextToResource(Input, Output: TStream);
  1777. var
  1778. StartPos, FixupInfo: LongInt;
  1779. parser: TParser;
  1780. name: String;
  1781. begin
  1782. // Get form type name
  1783. StartPos := Input.Position;
  1784. parser := TParser.Create(Input);
  1785. try
  1786. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  1787. parser.NextToken;
  1788. parser.CheckToken(toSymbol);
  1789. parser.NextToken;
  1790. parser.CheckToken(':');
  1791. parser.NextToken;
  1792. parser.CheckToken(toSymbol);
  1793. name := parser.TokenString;
  1794. finally
  1795. parser.Free;
  1796. Input.Position := StartPos;
  1797. end;
  1798. name := UpperCase(name);
  1799. Output.WriteResourceHeader(name,FixupInfo); // Write resource header
  1800. ObjectTextToBinary(Input, Output); // Convert the stuff!
  1801. Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
  1802. end;
  1803. { Utility routines }
  1804. function LineStart(Buffer, BufPos: PChar): PChar;
  1805. begin
  1806. Result := BufPos;
  1807. while Result > Buffer do begin
  1808. Dec(Result);
  1809. if Result[0] = #10 then break;
  1810. end;
  1811. end;
  1812. procedure CommonInit;
  1813. begin
  1814. SynchronizeTimeoutEvent:=RtlEventCreate;
  1815. InitCriticalSection(ThreadQueueLock);
  1816. MainThreadID:=GetCurrentThreadID;
  1817. ExternalThreads := TThreadList.Create;
  1818. TThread.FProcessorCount := CPUCount;
  1819. InitCriticalsection(ResolveSection);
  1820. InitHandlerList:=Nil;
  1821. FindGlobalComponentList:=nil;
  1822. IntConstList := TThreadList.Create;
  1823. ClassList := TThreadList.Create;
  1824. ClassAliasList := TStringList.Create;
  1825. { on unix this maps to a simple rw synchornizer }
  1826. GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  1827. RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  1828. end;
  1829. procedure CommonCleanup;
  1830. var
  1831. i: Integer;
  1832. tmpentry: TThread.PThreadQueueEntry;
  1833. begin
  1834. GlobalNameSpace.BeginWrite;
  1835. with IntConstList.LockList do
  1836. try
  1837. for i := 0 to Count - 1 do
  1838. TIntConst(Items[I]).Free;
  1839. finally
  1840. IntConstList.UnlockList;
  1841. end;
  1842. IntConstList.Free;
  1843. ClassList.Free;
  1844. ClassAliasList.Free;
  1845. RemoveFixupReferences(nil, '');
  1846. DoneCriticalsection(ResolveSection);
  1847. GlobalLists.Free;
  1848. ComponentPages.Free;
  1849. FreeAndNil(NeedResolving);
  1850. { GlobalNameSpace is an interface so this is enough }
  1851. GlobalNameSpace:=nil;
  1852. if (InitHandlerList<>Nil) then
  1853. for i := 0 to InitHandlerList.Count - 1 do
  1854. TInitHandler(InitHandlerList.Items[I]).Free;
  1855. InitHandlerList.Free;
  1856. InitHandlerList:=Nil;
  1857. FindGlobalComponentList.Free;
  1858. FindGlobalComponentList:=nil;
  1859. with ExternalThreads.LockList do
  1860. try
  1861. for i := 0 to Count - 1 do
  1862. TThread(Items[i]).Free;
  1863. finally
  1864. ExternalThreads.UnlockList;
  1865. end;
  1866. FreeAndNil(ExternalThreads);
  1867. RtlEventDestroy(SynchronizeTimeoutEvent);
  1868. { clean up the queue, but keep in mind that the entries used for Synchronize
  1869. are owned by the corresponding TThread }
  1870. while Assigned(ThreadQueueHead) do begin
  1871. tmpentry := ThreadQueueHead;
  1872. ThreadQueueHead := tmpentry^.Next;
  1873. if not Assigned(tmpentry^.SyncEvent) then
  1874. Dispose(tmpentry);
  1875. end;
  1876. DoneCriticalSection(ThreadQueueLock);
  1877. end;
  1878. { TFiler implementation }
  1879. {$i filer.inc}
  1880. { TReader implementation }
  1881. {$i reader.inc}
  1882. { TWriter implementations }
  1883. {$i writer.inc}
  1884. {$i twriter.inc}