classes.inc 53 KB

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