1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437 |
- {
- This file is part of the Free Component Library (FCL)
- Copyright (c) 1999-2000 by Michael Van Canneyt and Florian Klaempfl
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {**********************************************************************
- * Class implementations are in separate files. *
- **********************************************************************}
- type
- {$ifdef CPU16}
- TFilerFlagsInt = Byte;
- {$else CPU16}
- TFilerFlagsInt = LongInt;
- {$endif CPU16}
- var
- ClassList : TThreadlist;
- ClassAliasList : TStringList;
- {
- Include all message strings
- Add a language with IFDEF LANG_NAME
- just befor the final ELSE. This way English will always be the default.
- }
- {$IFDEF LANG_GERMAN}
- {$i constsg.inc}
- {$ELSE}
- {$IFDEF LANG_SPANISH}
- {$i constss.inc}
- {$ENDIF}
- {$ENDIF}
- { Utility routines }
- {$i util.inc}
- { TBits implementation }
- {$i bits.inc}
- { All streams implementations: }
- { Tstreams THandleStream TFileStream TResourcseStreams TStringStream }
- { TCustomMemoryStream TMemoryStream }
- {$i streams.inc}
- { TParser implementation}
- {$i parser.inc}
- { TCollection and TCollectionItem implementations }
- {$i collect.inc}
- { TList and TThreadList implementations }
- {$i lists.inc}
- { TStrings and TStringList implementations }
- {$i stringl.inc}
- { TThread implementation }
- { system independend threading code }
- var
- { event executed by SychronizeInternal to wake main thread if it sleeps in
- CheckSynchronize }
- SynchronizeTimeoutEvent: PRtlEvent;
- { the head of the queue containing the entries to be Synchronized - Nil if the
- queue is empty }
- ThreadQueueHead: TThread.PThreadQueueEntry;
- { the tail of the queue containing the entries to be Synchronized - Nil if the
- queue is empty }
- ThreadQueueTail: TThread.PThreadQueueEntry;
- { used for serialized access to the queue }
- ThreadQueueLock: TRtlCriticalSection;
- { this list holds all instances of external threads that need to be freed at
- the end of the program }
- ExternalThreads: TThreadList;
- { this list signals that the ExternalThreads list is cleared and thus the
- thread instances don't need to remove themselves }
- ExternalThreadsCleanup: Boolean = False;
- { this must be a global var, otherwise unwanted optimizations might happen in
- TThread.SpinWait() }
- SpinWaitDummy: LongWord;
- threadvar
- { the instance of the current thread; in case of an external thread this is
- Nil until TThread.GetCurrentThread was called once (the RTLs need to ensure
- that threadvars are initialized with 0!) }
- CurrentThreadVar: TThread;
- type
- { this type is used if a thread is created using
- TThread.CreateAnonymousThread }
- TAnonymousThread = class(TThread)
- private
- fProc: TProcedure;
- protected
- procedure Execute; override;
- public
- { as in TThread aProc needs to be changed to TProc once closures are
- supported }
- constructor Create(aProc: TProcedure);
- end;
- procedure TAnonymousThread.Execute;
- begin
- fProc();
- end;
- constructor TAnonymousThread.Create(aProc: TProcedure);
- begin
- { an anonymous thread is created suspended and with FreeOnTerminate set }
- inherited Create(True);
- FreeOnTerminate := True;
- fProc := aProc;
- end;
- type
- { this type is used by TThread.GetCurrentThread if the thread does not yet
- have a value in CurrentThreadVar (Note: the main thread is also created as
- a TExternalThread) }
- TExternalThread = class(TThread)
- protected
- { dummy method to remove the warning }
- procedure Execute; override;
- public
- constructor Create;
- destructor Destroy; override;
- end;
- procedure TExternalThread.Execute;
- begin
- { empty }
- end;
- constructor TExternalThread.Create;
- begin
- FExternalThread := True;
- { the parameter is unimportant if FExternalThread is True }
- inherited Create(False);
- with ExternalThreads.LockList do
- try
- Add(Self);
- finally
- ExternalThreads.UnlockList;
- end;
- end;
- destructor TExternalThread.Destroy;
- begin
- inherited;
- if not ExternalThreadsCleanup then
- with ExternalThreads.LockList do
- try
- Extract(Self);
- finally
- ExternalThreads.UnlockList;
- end;
- end;
- function ThreadProc(ThreadObjPtr: Pointer): PtrInt;
- var
- FreeThread: Boolean;
- Thread: TThread absolute ThreadObjPtr;
- begin
- { if Suspend checks FSuspended before doing anything, make sure it }
- { knows we're currently not suspended (this flag may have been set }
- { to true if CreateSuspended was true) }
- // Thread.FSuspended:=false;
- // wait until AfterConstruction has been called, so we cannot
- // free ourselves before TThread.Create has finished
- // (since that one may check our VTM in case of $R+, and
- // will call the AfterConstruction method in all cases)
- // Thread.Suspend;
- try
- { The thread may be already terminated at this point, e.g. if it was intially
- suspended, or if it wasn't ever scheduled for execution for whatever reason.
- So bypass user code if terminated. }
- if not Thread.Terminated then begin
- CurrentThreadVar := Thread;
- Thread.Execute;
- end;
- except
- Thread.FFatalException := TObject(AcquireExceptionObject);
- end;
- FreeThread := Thread.FFreeOnTerminate;
- Result := Thread.FReturnValue;
- Thread.FFinished := True;
- Thread.DoTerminate;
- if FreeThread then
- Thread.Free;
- EndThread(Result);
- end;
- { system-dependent code }
- {$i tthread.inc}
- constructor TThread.Create(CreateSuspended: Boolean;
- const StackSize: SizeUInt);
- begin
- inherited Create;
- if FExternalThread then
- FThreadID := GetCurrentThreadID
- else
- SysCreate(CreateSuspended, StackSize);
- end;
- destructor TThread.Destroy;
- begin
- if not FExternalThread then begin
- SysDestroy;
- if FHandle <> TThreadID(0) then
- CloseThread(FHandle);
- end;
- RemoveQueuedEvents(Self);
- DoneSynchronizeEvent;
- { set CurrentThreadVar to Nil? }
- inherited Destroy;
- end;
- procedure TThread.Start;
- begin
- { suspend/resume are now deprecated in Delphi (they also don't work
- on most platforms in FPC), so a different method was required
- to start a thread if it's create with fSuspended=true -> that's
- what this method is for. }
- Resume;
- end;
- function TThread.GetSuspended: Boolean;
- begin
- GetSuspended:=FSuspended;
- end;
- procedure TThread.AfterConstruction;
- begin
- inherited AfterConstruction;
- // enable for all platforms once http://bugs.freepascal.org/view.php?id=16884
- // is fixed for all platforms (in case the fix for non-unix platforms also
- // requires this field at least)
- {$if defined(unix) or defined(windows) or defined(os2) or defined(hasamiga)}
- if not FExternalThread and not FInitialSuspended then
- Resume;
- {$endif}
- end;
- procedure ExecuteThreadQueueEntry(aEntry: TThread.PThreadQueueEntry);
- begin
- if Assigned(aEntry^.Method) then
- aEntry^.Method()
- // enable once closures are supported
- {else
- aEntry^.ThreadProc();}
- end;
- procedure ThreadQueueAppend(aEntry: TThread.PThreadQueueEntry);
- begin
- { do we really need a synchronized call? }
- if GetCurrentThreadID = MainThreadID then begin
- ExecuteThreadQueueEntry(aEntry);
- if not Assigned(aEntry^.SyncEvent) then
- Dispose(aEntry);
- end else begin
- System.EnterCriticalSection(ThreadQueueLock);
- try
- { add the entry to the thread queue }
- if Assigned(ThreadQueueTail) then begin
- ThreadQueueTail^.Next := aEntry;
- end else
- ThreadQueueHead := aEntry;
- ThreadQueueTail := aEntry;
- finally
- System.LeaveCriticalSection(ThreadQueueLock);
- end;
- { ensure that the main thread knows that something awaits }
- RtlEventSetEvent(SynchronizeTimeoutEvent);
- if assigned(WakeMainThread) then
- WakeMainThread(aEntry^.Thread);
- { is this a Synchronize or Queue entry? }
- if Assigned(aEntry^.SyncEvent) then begin
- RtlEventWaitFor(aEntry^.SyncEvent);
- if Assigned(aEntry^.Exception) then
- raise aEntry^.Exception;
- end;
- end;
- end;
- procedure TThread.InitSynchronizeEvent;
- begin
- if Assigned(FSynchronizeEntry) then
- Exit;
- New(FSynchronizeEntry);
- FillChar(FSynchronizeEntry^, SizeOf(TThreadQueueEntry), 0);
- FSynchronizeEntry^.Thread := Self;
- FSynchronizeEntry^.SyncEvent := RtlEventCreate;
- end;
- procedure TThread.DoneSynchronizeEvent;
- begin
- if not Assigned(FSynchronizeEntry) then
- Exit;
- RtlEventDestroy(FSynchronizeEntry^.SyncEvent);
- Dispose(FSynchronizeEntry);
- FSynchronizeEntry := Nil;
- end;
- class procedure TThread.Synchronize(AThread: TThread; AMethod: TThreadMethod);
- begin
- { ensure that we have a TThread instance }
- if not Assigned(AThread) then
- AThread := CurrentThread;
- { the Synchronize event is instantiated on demand }
- AThread.InitSynchronizeEvent;
- AThread.FSynchronizeEntry^.Exception := Nil;
- AThread.FSynchronizeEntry^.Method := AMethod;
- ThreadQueueAppend(AThread.FSynchronizeEntry);
- AThread.FSynchronizeEntry^.Method := Nil;
- AThread.FSynchronizeEntry^.Next := Nil;
- end;
- procedure TThread.Synchronize(AMethod: TThreadMethod);
- begin
- TThread.Synchronize(self,AMethod);
- end;
- Function PopThreadQueueHead : TThread.PThreadQueueEntry;
- begin
- Result:=ThreadQueueHead;
- if (Result<>Nil) then
- begin
- System.EnterCriticalSection(ThreadQueueLock);
- try
- Result:=ThreadQueueHead;
- if Result<>Nil then
- ThreadQueueHead:=ThreadQueueHead^.Next;
- if Not Assigned(ThreadQueueHead) then
- ThreadQueueTail := Nil;
- finally
- System.LeaveCriticalSection(ThreadQueueLock);
- end;
- end;
- end;
- function CheckSynchronize(timeout : longint=0) : boolean;
- { assumes being called from GUI thread }
- var
- ExceptObj: Exception;
- tmpentry: TThread.PThreadQueueEntry;
- begin
- result:=false;
- { first sanity check }
- if Not IsMultiThread then
- Exit
- { second sanity check }
- else if GetCurrentThreadID<>MainThreadID then
- raise EThread.CreateFmt(SCheckSynchronizeError,[GetCurrentThreadID]);
- if timeout>0 then
- RtlEventWaitFor(SynchronizeTimeoutEvent,timeout)
- else
- RtlEventResetEvent(SynchronizeTimeoutEvent);
- tmpentry := PopThreadQueueHead;
- while Assigned(tmpentry) do
- begin
- { step 2: execute the method }
- exceptobj := Nil;
- try
- ExecuteThreadQueueEntry(tmpentry);
- except
- exceptobj := Exception(AcquireExceptionObject);
- end;
- { step 3: error handling and cleanup }
- if Assigned(tmpentry^.SyncEvent) then
- begin
- { for Synchronize entries we pass back the Exception and trigger
- the event that Synchronize waits in }
- tmpentry^.Exception := exceptobj;
- RtlEventSetEvent(tmpentry^.SyncEvent)
- end
- else
- begin
- { for Queue entries we dispose the entry and raise the exception }
- Dispose(tmpentry);
- if Assigned(exceptobj) then
- raise exceptobj;
- end;
- tmpentry := PopThreadQueueHead;
- end;
- end;
- class function TThread.GetCurrentThread: TThread;
- begin
- { if this is the first time GetCurrentThread is called for an external thread
- we need to create a corresponding TExternalThread instance }
- Result := CurrentThreadVar;
- if not Assigned(Result) then begin
- Result := TExternalThread.Create;
- CurrentThreadVar := Result;
- end;
- end;
- class function TThread.GetIsSingleProcessor: Boolean;
- begin
- Result := FProcessorCount <= 1;
- end;
- procedure TThread.Queue(aMethod: TThreadMethod);
- begin
- Queue(Self, aMethod);
- end;
- class procedure TThread.Queue(aThread: TThread; aMethod: TThreadMethod); static;
- var
- queueentry: PThreadQueueEntry;
- begin
- { ensure that we have a valid TThread instance }
- if not Assigned(aThread) then
- aThread := CurrentThread;
- New(queueentry);
- FillChar(queueentry^, SizeOf(TThreadQueueEntry), 0);
- queueentry^.Thread := aThread;
- queueentry^.Method := aMethod;
- { the queueentry is freed by CheckSynchronize (or by RemoveQueuedEvents) }
- ThreadQueueAppend(queueentry);
- end;
- class procedure TThread.RemoveQueuedEvents(aThread: TThread; aMethod: TThreadMethod);
- var
- entry, tmpentry, lastentry: PThreadQueueEntry;
- begin
- { anything to do at all? }
- if not Assigned(aThread) or not Assigned(aMethod) then
- Exit;
- System.EnterCriticalSection(ThreadQueueLock);
- try
- lastentry := Nil;
- entry := ThreadQueueHead;
- while Assigned(entry) do begin
- { first check for the thread }
- if Assigned(aThread) and (entry^.Thread <> aThread) then begin
- lastentry := entry;
- entry := entry^.Next;
- Continue;
- end;
- { then check for the method }
- if entry^.Method <> aMethod then begin
- lastentry := entry;
- entry := entry^.Next;
- Continue;
- end;
- { skip entries added by Synchronize }
- if Assigned(entry^.SyncEvent) then begin
- lastentry := entry;
- entry := entry^.Next;
- Continue;
- end;
- { ok, we need to remove this entry }
- tmpentry := entry;
- if Assigned(lastentry) then
- lastentry^.Next := entry^.Next;
- entry := entry^.Next;
- if ThreadQueueHead = tmpentry then
- ThreadQueueHead := entry;
- if ThreadQueueTail = tmpentry then
- ThreadQueueTail := lastentry;
- { only dispose events added by Queue }
- if not Assigned(tmpentry^.SyncEvent) then
- Dispose(tmpentry);
- end;
- finally
- System.LeaveCriticalSection(ThreadQueueLock);
- end;
- end;
- class procedure TThread.RemoveQueuedEvents(aMethod: TThreadMethod);
- begin
- RemoveQueuedEvents(Nil, aMethod);
- end;
- class procedure TThread.RemoveQueuedEvents(aThread: TThread);
- begin
- RemoveQueuedEvents(aThread, Nil);
- end;
- class function TThread.CheckTerminated: Boolean;
- begin
- { this method only works with threads created by TThread, so we can make a
- shortcut here }
- if not Assigned(CurrentThreadVar) then
- raise EThreadExternalException.Create(SThreadExternal);
- Result := CurrentThreadVar.FTerminated;
- end;
- class procedure TThread.SetReturnValue(aValue: Integer);
- begin
- { this method only works with threads created by TThread, so we can make a
- shortcut here }
- if not Assigned(CurrentThreadVar) then
- raise EThreadExternalException.Create(SThreadExternal);
- CurrentThreadVar.FReturnValue := aValue;
- end;
- class function TThread.CreateAnonymousThread(aProc: TProcedure): TThread;
- begin
- if not Assigned(aProc) then
- raise Exception.Create(SNoProcGiven);
- Result := TAnonymousThread.Create(aProc);
- end;
- {$ifdef THREADNAME_IS_ANSISTRING}
- { the platform implements the AnsiString variant and the UnicodeString variant
- simply calls the AnsiString variant }
- class procedure TThread.NameThreadForDebugging(aThreadName: UnicodeString; aThreadID: TThreadID);
- begin
- NameThreadForDebugging(AnsiString(aThreadName), aThreadID);
- end;
- {$ifndef HAS_TTHREAD_NAMETHREADFORDEBUGGING}
- class procedure TThread.NameThreadForDebugging(aThreadName: AnsiString; aThreadID: TThreadID);
- begin
- { empty }
- end;
- {$endif}
- {$else}
- {$ifndef HAS_TTHREAD_NAMETHREADFORDEBUGGING}
- { the platform implements the UnicodeString variant and the AnsiString variant
- simply calls the UnicodeString variant }
- class procedure TThread.NameThreadForDebugging(aThreadName: UnicodeString; aThreadID: TThreadID);
- begin
- { empty }
- end;
- {$endif}
- class procedure TThread.NameThreadForDebugging(aThreadName: AnsiString; aThreadID: TThreadID);
- begin
- NameThreadForDebugging(UnicodeString(aThreadName), aThreadID);
- end;
- {$endif}
- class procedure TThread.Yield;
- begin
- ThreadSwitch;
- end;
- class procedure TThread.Sleep(aMilliseconds: Cardinal);
- begin
- SysUtils.Sleep(aMilliseconds);
- end;
- class procedure TThread.SpinWait(aIterations: LongWord);
- var
- i: LongWord;
- begin
- { yes, it's just a simple busy wait to burn some cpu cycles... and as the job
- of this loop is to burn CPU cycles we switch off any optimizations that
- could interfere with this (e.g. loop unrolling) }
- { Do *NOT* do $PUSH, $OPTIMIZATIONS OFF, <code>, $POP because optimization is
- not a local switch, which means $PUSH/POP doesn't affect it, so that turns
- off *ALL* optimizations for code below this point. Thanks to this we shipped
- large parts of the classes unit with optimizations off between 2012-12-27
- and 2014-06-06.
- Instead, use a global var for the spinlock, because that is always handled
- as volatile, so the access won't be optimized away by the compiler. (KB) }
- for i:=1 to aIterations do
- begin
- Inc(SpinWaitDummy); // SpinWaitDummy *MUST* be global
- end;
- end;
- {$ifndef HAS_TTHREAD_GETSYSTEMTIMES}
- class procedure TThread.GetSystemTimes(out aSystemTimes: TSystemTimes);
- begin
- { by default we just return a zeroed out record }
- FillChar(aSystemTimes, SizeOf(aSystemTimes), 0);
- end;
- {$endif}
- class function TThread.GetTickCount: LongWord;
- begin
- Result := SysUtils.GetTickCount;
- end;
- class function TThread.GetTickCount64: QWord;
- begin
- Result := SysUtils.GetTickCount64;
- end;
- { TSimpleThread allows objects to create a threading method without defining
- a new thread class }
- Type
- TSimpleThread = class(TThread)
- private
- FExecuteMethod: TThreadExecuteHandler;
- protected
- procedure Execute; override;
- public
- constructor Create(ExecuteMethod: TThreadExecuteHandler; AOnterminate : TNotifyEvent);
- end;
- TSimpleStatusThread = class(TThread)
- private
- FExecuteMethod: TThreadExecuteStatusHandler;
- FStatus : String;
- FOnStatus : TThreadStatusNotifyEvent;
- protected
- procedure Execute; override;
- Procedure DoStatus;
- Procedure SetStatus(Const AStatus : String);
- public
- constructor Create(ExecuteMethod: TThreadExecuteStatusHandler; AOnStatus : TThreadStatusNotifyEvent; AOnterminate : TNotifyEvent);
- end;
- TSimpleProcThread = class(TThread)
- private
- FExecuteMethod: TThreadExecuteCallBack;
- FCallOnTerminate : TNotifyCallBack;
- FData : Pointer;
- protected
- Procedure TerminateCallBack(Sender : TObject);
- procedure Execute; override;
- public
- constructor Create(ExecuteMethod: TThreadExecuteCallBack; AData : Pointer; AOnterminate : TNotifyCallBack);
- end;
- TSimpleStatusProcThread = class(TThread)
- private
- FExecuteMethod: TThreadExecuteStatusCallBack;
- FCallOnTerminate : TNotifyCallBack;
- FStatus : String;
- FOnStatus : TThreadStatusNotifyCallBack;
- FData : Pointer;
- protected
- procedure Execute; override;
- Procedure DoStatus;
- Procedure SetStatus(Const AStatus : String);
- Procedure TerminateCallBack(Sender : TObject);
- public
- constructor Create(ExecuteMethod: TThreadExecuteStatusCallBack; AData : Pointer; AOnStatus : TThreadStatusNotifyCallBack; AOnterminate : TNotifyCallBack);
- end;
- { TSimpleThread }
-
- constructor TSimpleThread.Create(ExecuteMethod: TThreadExecuteHandler; AOnTerminate: TNotifyEvent);
- begin
- FExecuteMethod := ExecuteMethod;
- OnTerminate := AOnTerminate;
- inherited Create(False);
- end;
- procedure TSimpleThread.Execute;
- begin
- FreeOnTerminate := True;
- FExecuteMethod;
- end;
- { TSimpleStatusThread }
-
- constructor TSimpleStatusThread.Create(ExecuteMethod: TThreadExecuteStatusHandler;AOnStatus : TThreadStatusNotifyEvent; AOnTerminate: TNotifyEvent);
- begin
- FExecuteMethod := ExecuteMethod;
- OnTerminate := AOnTerminate;
- FOnStatus:=AOnStatus;
- FStatus:='';
- inherited Create(False);
- end;
- procedure TSimpleStatusThread.Execute;
- begin
- FreeOnTerminate := True;
- FExecuteMethod(@SetStatus);
- end;
- procedure TSimpleStatusThread.SetStatus(Const AStatus : String);
- begin
- If (AStatus=FStatus) then
- exit;
- FStatus:=AStatus;
- If Assigned(FOnStatus) then
- Synchronize(@DoStatus);
- end;
- procedure TSimpleStatusThread.DoStatus;
- begin
- FOnStatus(Self,FStatus);
- end;
- { TSimpleProcThread }
-
- constructor TSimpleProcThread.Create(ExecuteMethod: TThreadExecuteCallBack; AData : Pointer; AOnTerminate: TNotifyCallBack);
- begin
- FExecuteMethod := ExecuteMethod;
- FCallOnTerminate := AOnTerminate;
- FData:=AData;
- If Assigned(FCallOnTerminate) then
- OnTerminate:=@TerminateCallBack;
- inherited Create(False);
- end;
- procedure TSimpleProcThread.Execute;
- begin
- FreeOnTerminate := True;
- FExecuteMethod(FData);
- end;
- procedure TSimpleProcThread.TerminateCallBack(Sender : TObject);
- begin
- if Assigned(FCallOnTerminate) then
- FCallOnTerminate(Sender,FData);
- end;
- { TSimpleStatusProcThread }
-
- constructor TSimpleStatusProcThread.Create(ExecuteMethod: TThreadExecuteStatusCallback; AData : Pointer; AOnStatus : TThreadStatusNotifyCallBack; AOnTerminate: TNotifyCallBack);
- begin
- FExecuteMethod := ExecuteMethod;
- FCallOnTerminate := AOnTerminate;
- FData:=AData;
- If Assigned(FCallOnTerminate) then
- OnTerminate:=@TerminateCallBack;
- FOnStatus:=AOnStatus;
- FStatus:='';
- inherited Create(False);
- end;
- procedure TSimpleStatusProcThread.Execute;
- begin
- FreeOnTerminate := True;
- FExecuteMethod(FData,@SetStatus);
- end;
- procedure TSimpleStatusProcThread.SetStatus(Const AStatus : String);
- begin
- If (AStatus=FStatus) then
- exit;
- FStatus:=AStatus;
- If Assigned(FOnStatus) then
- Synchronize(@DoStatus);
- end;
- procedure TSimpleStatusProcThread.DoStatus;
- begin
- FOnStatus(Self,FData,FStatus);
- end;
- procedure TSimpleStatusProcThread.TerminateCallBack(Sender : TObject);
- begin
- if Assigned(FCallOnTerminate) then
- FCallOnTerminate(Sender,FData);
- end;
- Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteHandler; AOnTerminate : TNotifyEvent = Nil) : TThread;
- begin
- Result:=TSimpleThread.Create(AMethod,AOnTerminate);
- end;
- Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteCallback; AData : Pointer; AOnTerminate : TNotifyCallback = Nil) : TThread;
- begin
- Result:=TSimpleProcThread.Create(AMethod,AData,AOnTerminate);
- end;
- Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteStatusHandler; AOnStatus : TThreadStatusNotifyEvent; AOnTerminate : TNotifyEvent = Nil) : TThread;
- begin
- If Not Assigned(AOnStatus) then
- Raise EThread.Create(SErrStatusCallBackRequired);
- Result:=TSimpleStatusThread.Create(AMethod,AOnStatus,AOnTerminate);
- end;
- Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteStatusCallback; AOnStatus : TThreadStatusNotifyCallback;AData : Pointer = Nil; AOnTerminate : TNotifyCallBack = Nil) : TThread;
- begin
- If Not Assigned(AOnStatus) then
- Raise EThread.Create(SErrStatusCallBackRequired);
- Result:=TSimpleStatusProcThread.Create(AMethod,AData,AOnStatus,AOnTerminate);
- end;
- { TPersistent implementation }
- {$i persist.inc }
- {$i sllist.inc}
- {$i resref.inc}
- { TComponent implementation }
- {$i compon.inc}
- { TBasicAction implementation }
- {$i action.inc}
- { TDataModule implementation }
- {$i dm.inc}
- { Class and component registration routines }
- {$I cregist.inc}
- { Interface related stuff }
- {$I intf.inc}
- {**********************************************************************
- * Miscellaneous procedures and functions *
- **********************************************************************}
- function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; Strings: TStrings; AddEmptyStrings : Boolean = False): Integer;
- var
- b, c : pchar;
- procedure SkipWhitespace;
- begin
- while (c^ in Whitespace) do
- inc (c);
- end;
- procedure AddString;
- var
- l : integer;
- s : string;
- begin
- l := c-b;
- if (l > 0) or AddEmptyStrings then
- begin
- if assigned(Strings) then
- begin
- setlength(s, l);
- if l>0 then
- move (b^, s[1],l*SizeOf(char));
- Strings.Add (s);
- end;
- inc (result);
- end;
- end;
- var
- quoted : char;
- begin
- result := 0;
- c := Content;
- Quoted := #0;
- Separators := Separators + [#13, #10] - ['''','"'];
- SkipWhitespace;
- b := c;
- while (c^ <> #0) do
- begin
- if (c^ = Quoted) then
- begin
- if ((c+1)^ = Quoted) then
- inc (c)
- else
- Quoted := #0
- end
- else if (Quoted = #0) and (c^ in ['''','"']) then
- Quoted := c^;
- if (Quoted = #0) and (c^ in Separators) then
- begin
- AddString;
- inc (c);
- SkipWhitespace;
- b := c;
- end
- else
- inc (c);
- end;
- if (c <> b) then
- AddString;
- end;
- { Point and rectangle constructors }
- function Point(AX, AY: Integer): TPoint;
- begin
- with Result do
- begin
- X := AX;
- Y := AY;
- end;
- end;
- function SmallPoint(AX, AY: SmallInt): TSmallPoint;
- begin
- with Result do
- begin
- X := AX;
- Y := AY;
- end;
- end;
- function Rect(ALeft, ATop, ARight, ABottom: Integer): TRect;
- begin
- with Result do
- begin
- Left := ALeft;
- Top := ATop;
- Right := ARight;
- Bottom := ABottom;
- end;
- end;
- function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
- begin
- with Result do
- begin
- Left := ALeft;
- Top := ATop;
- Right := ALeft + AWidth;
- Bottom := ATop + AHeight;
- end;
- end;
- function PointsEqual(const P1, P2: TPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- { lazy, but should work }
- result:=QWord(P1)=QWord(P2);
- end;
- function PointsEqual(const P1, P2: TSmallPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- { lazy, but should work }
- result:=DWord(P1)=DWord(P2);
- end;
- function InvalidPoint(X, Y: Integer): Boolean;
- begin
- result:=(X=-1) and (Y=-1);
- end;
- function InvalidPoint(const At: TPoint): Boolean;
- begin
- result:=(At.x=-1) and (At.y=-1);
- end;
- function InvalidPoint(const At: TSmallPoint): Boolean;
- begin
- result:=(At.x=-1) and (At.y=-1);
- end;
- { Object filing routines }
- var
- IntConstList: TThreadList;
- type
- TIntConst = class
- IntegerType: PTypeInfo; // The integer type RTTI pointer
- IdentToIntFn: TIdentToInt; // Identifier to Integer conversion
- IntToIdentFn: TIntToIdent; // Integer to Identifier conversion
- constructor Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
- AIntToIdent: TIntToIdent);
- end;
- constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
- AIntToIdent: TIntToIdent);
- begin
- IntegerType := AIntegerType;
- IdentToIntFn := AIdentToInt;
- IntToIdentFn := AIntToIdent;
- end;
- procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;
- IntToIdentFn: TIntToIdent);
- begin
- IntConstList.Add(TIntConst.Create(IntegerType, IdentToIntFn, IntToIdentFn));
- end;
- function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
- var
- i: Integer;
- begin
- with IntConstList.LockList do
- try
- for i := 0 to Count - 1 do
- if TIntConst(Items[i]).IntegerType = AIntegerType then
- exit(TIntConst(Items[i]).IntToIdentFn);
- Result := nil;
- finally
- IntConstList.UnlockList;
- end;
- end;
- function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;
- var
- i: Integer;
- begin
- with IntConstList.LockList do
- try
- for i := 0 to Count - 1 do
- with TIntConst(Items[I]) do
- if TIntConst(Items[I]).IntegerType = AIntegerType then
- exit(IdentToIntFn);
- Result := nil;
- finally
- IntConstList.UnlockList;
- end;
- end;
- function IdentToInt(const Ident: String; out Int: LongInt;
- const Map: array of TIdentMapEntry): Boolean;
- var
- i: Integer;
- begin
- for i := Low(Map) to High(Map) do
- if CompareText(Map[i].Name, Ident) = 0 then
- begin
- Int := Map[i].Value;
- exit(True);
- end;
- Result := False;
- end;
- function IntToIdent(Int: LongInt; var Ident: String;
- const Map: array of TIdentMapEntry): Boolean;
- var
- i: Integer;
- begin
- for i := Low(Map) to High(Map) do
- if Map[i].Value = Int then
- begin
- Ident := Map[i].Name;
- exit(True);
- end;
- Result := False;
- end;
- function GlobalIdentToInt(const Ident: String; var Int: LongInt):boolean;
- var
- i : Integer;
- begin
- with IntConstList.LockList do
- try
- for i := 0 to Count - 1 do
- if TIntConst(Items[I]).IdentToIntFn(Ident, Int) then
- Exit(True);
- Result := false;
- finally
- IntConstList.UnlockList;
- end;
- end;
- { TPropFixup }
- // Tainted. TPropFixup is being removed.
- Type
- TInitHandler = Class(TObject)
- AHandler : TInitComponentHandler;
- AClass : TComponentClass;
- end;
- {$ifndef i8086}
- type
- TCodePtrList = TList;
- {$endif i8086}
- Var
- InitHandlerList : TList;
- FindGlobalComponentList : TCodePtrList;
- procedure RegisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
- begin
- if not(assigned(FindGlobalComponentList)) then
- FindGlobalComponentList:=TCodePtrList.Create;
- if FindGlobalComponentList.IndexOf(CodePointer(AFindGlobalComponent))<0 then
- FindGlobalComponentList.Add(CodePointer(AFindGlobalComponent));
- end;
- procedure UnregisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
- begin
- if assigned(FindGlobalComponentList) then
- FindGlobalComponentList.Remove(CodePointer(AFindGlobalComponent));
- end;
- function FindGlobalComponent(const Name: string): TComponent;
- var
- i : sizeint;
- begin
- FindGlobalComponent:=nil;
- if assigned(FindGlobalComponentList) then
- begin
- for i:=FindGlobalComponentList.Count-1 downto 0 do
- begin
- FindGlobalComponent:=TFindGlobalComponent(FindGlobalComponentList[i])(name);
- if assigned(FindGlobalComponent) then
- break;
- end;
- end;
- end;
- procedure RegisterInitComponentHandler(ComponentClass: TComponentClass; Handler: TInitComponentHandler);
- Var
- I : Integer;
- H: TInitHandler;
- begin
- If (InitHandlerList=Nil) then
- InitHandlerList:=TList.Create;
- H:=TInitHandler.Create;
- H.Aclass:=ComponentClass;
- H.AHandler:=Handler;
- try
- With InitHandlerList do
- begin
- I:=0;
- While (I<Count) and not H.AClass.InheritsFrom(TInitHandler(Items[I]).AClass) do
- Inc(I);
- { override? }
- if (I<Count) and (TInitHandler(Items[I]).AClass=H.AClass) then
- begin
- TInitHandler(Items[I]).AHandler:=Handler;
- H.Free;
- end
- else
- InitHandlerList.Insert(I,H);
- end;
- except
- H.Free;
- raise;
- end;
- end;
- { all targets should at least include the sysres.inc dummy in the system unit to compile this }
- function CreateComponentfromRes(const res : string;Inst : THandle;var Component : TComponent) : Boolean;
- var
- ResStream : TResourceStream;
- begin
- result:=true;
- if Inst=0 then
- Inst:=HInstance;
- try
- ResStream:=TResourceStream.Create(Inst,res,RT_RCDATA);
- try
- Component:=ResStream.ReadComponent(Component);
- finally
- ResStream.Free;
- end;
- except
- on EResNotFound do
- result:=false;
- end;
- end;
- function DefaultInitHandler(Instance: TComponent; RootAncestor: TClass): Boolean;
- function doinit(_class : TClass) : boolean;
- begin
- result:=false;
- if (_class.ClassType=TComponent) or (_class.ClassType=RootAncestor) then
- exit;
- result:=doinit(_class.ClassParent);
- result:=CreateComponentfromRes(_class.ClassName,0,Instance) or result;
- end;
- begin
- GlobalNameSpace.BeginWrite;
- try
- result:=doinit(Instance.ClassType);
- finally
- GlobalNameSpace.EndWrite;
- end;
- end;
- function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
- Var
- I : Integer;
- begin
- I:=0;
- if not Assigned(InitHandlerList) then begin
- Result := True;
- Exit;
- end;
- Result:=False;
- With InitHandlerList do
- begin
- I:=0;
- // Instance is the normally the lowest one, so that one should be used when searching.
- While Not result and (I<Count) do
- begin
- If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
- Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
- Inc(I);
- end;
- end;
- end;
- function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
- begin
- Result:=ReadComponentRes(ResName,Instance)=Instance;
- end;
- function SysReadComponentRes(HInstance : THandle; const ResName: String; Instance: TComponent): TComponent;
- Var
- H : TFPResourceHandle;
- begin
- { Windows unit also has a FindResource function, use the one from
- system unit here. }
- H:=system.FindResource(HInstance,ResName,RT_RCDATA);
- if (PtrInt(H)=0) then
- Result:=Nil
- else
- With TResourceStream.Create(HInstance,ResName,RT_RCDATA) do
- try
- Result:=ReadComponent(Instance);
- Finally
- Free;
- end;
- end;
- function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
- begin
- Result:=SysReadComponentRes(Hinstance,Resname,Instance);
- end;
- function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
- begin
- Result:=SysReadComponentRes(Hinstance,ResName,Nil);
- end;
- function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
- var
- FileStream: TStream;
- begin
- FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
- try
- Result := FileStream.ReadComponentRes(Instance);
- finally
- FileStream.Free;
- end;
- end;
- procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
- var
- FileStream: TStream;
- begin
- FileStream := TFileStream.Create(FileName, fmCreate);
- try
- FileStream.WriteComponentRes(Instance.ClassName, Instance);
- finally
- FileStream.Free;
- end;
- end;
- Function FindNestedComponent(Root : TComponent; APath : String; CStyle : Boolean = True) : TComponent;
- Function GetNextName : String; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
- Var
- P : Integer;
- CM : Boolean;
- begin
- P:=Pos('.',APath);
- CM:=False;
- If (P=0) then
- begin
- If CStyle then
- begin
- P:=Pos('->',APath);
- CM:=P<>0;
- end;
- If (P=0) Then
- P:=Length(APath)+1;
- end;
- Result:=Copy(APath,1,P-1);
- Delete(APath,1,P+Ord(CM));
- end;
- Var
- C : TComponent;
- S : String;
- begin
- If (APath='') then
- Result:=Nil
- else
- begin
- Result:=Root;
- While (APath<>'') And (Result<>Nil) do
- begin
- C:=Result;
- S:=Uppercase(GetNextName);
- Result:=C.FindComponent(S);
- If (Result=Nil) And (S='OWNER') then
- Result:=C;
- end;
- end;
- end;
- threadvar
- GlobalLoaded, GlobalLists: TFpList;
- procedure BeginGlobalLoading;
- begin
- if not Assigned(GlobalLists) then
- GlobalLists := TFpList.Create;
- GlobalLists.Add(GlobalLoaded);
- GlobalLoaded := TFpList.Create;
- end;
- { Notify all global components that they have been loaded completely }
- procedure NotifyGlobalLoading;
- var
- i: Integer;
- begin
- for i := 0 to GlobalLoaded.Count - 1 do
- TComponent(GlobalLoaded[i]).Loaded;
- end;
- procedure EndGlobalLoading;
- begin
- { Free the memory occupied by BeginGlobalLoading }
- GlobalLoaded.Free;
- GlobalLoaded := TFpList(GlobalLists.Last);
- GlobalLists.Delete(GlobalLists.Count - 1);
- if GlobalLists.Count = 0 then
- begin
- GlobalLists.Free;
- GlobalLists := nil;
- end;
- end;
- function CollectionsEqual(C1, C2: TCollection): Boolean;
- begin
- // !!!: Implement this
- CollectionsEqual:=false;
- end;
- function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;
- procedure stream_collection(s : tstream;c : tcollection;o : tcomponent);
- var
- w : twriter;
- begin
- w:=twriter.create(s,4096);
- try
- w.root:=o;
- w.flookuproot:=o;
- w.writecollection(c);
- finally
- w.free;
- end;
- end;
- var
- s1,s2 : tmemorystream;
- begin
- result:=false;
- if (c1.classtype<>c2.classtype) or
- (c1.count<>c2.count) then
- exit;
- if c1.count = 0 then
- begin
- result:= true;
- exit;
- end;
- s1:=tmemorystream.create;
- try
- s2:=tmemorystream.create;
- try
- stream_collection(s1,c1,owner1);
- stream_collection(s2,c2,owner2);
- result:=(s1.size=s2.size) and (CompareChar(s1.memory^,s2.memory^,s1.size)=0);
- finally
- s2.free;
- end;
- finally
- s1.free;
- end;
- end;
- { Object conversion routines }
- type
- CharToOrdFuncty = Function(var charpo: Pointer): Cardinal;
- function CharToOrd(var P: Pointer): Cardinal;
- begin
- result:= ord(pchar(P)^);
- inc(pchar(P));
- end;
- function WideCharToOrd(var P: Pointer): Cardinal;
- begin
- result:= ord(pwidechar(P)^);
- inc(pwidechar(P));
- end;
- function Utf8ToOrd(var P:Pointer): Cardinal;
- begin
- // Should also check for illegal utf8 combinations
- Result := Ord(PChar(P)^);
- Inc(P);
- if (Result and $80) <> 0 then
- if (Ord(Result) and %11100000) = %11000000 then begin
- Result := ((Result and %00011111) shl 6)
- or (ord(PChar(P)^) and %00111111);
- Inc(P);
- end else if (Ord(Result) and %11110000) = %11100000 then begin
- Result := ((Result and %00011111) shl 12)
- or ((ord(PChar(P)^) and %00111111) shl 6)
- or (ord((PChar(P)+1)^) and %00111111);
- Inc(P,2);
- end else begin
- Result := ((ord(Result) and %00011111) shl 18)
- or ((ord(PChar(P)^) and %00111111) shl 12)
- or ((ord((PChar(P)+1)^) and %00111111) shl 6)
- or (ord((PChar(P)+2)^) and %00111111);
- Inc(P,3);
- end;
- end;
- procedure ObjectBinaryToText(Input, Output: TStream; Encoding: TObjectTextEncoding);
- procedure OutStr(s: String);
- begin
- if Length(s) > 0 then
- Output.Write(s[1], Length(s));
- end;
- procedure OutLn(s: String);
- begin
- OutStr(s + LineEnding);
- end;
- procedure Outchars(P, LastP : Pointer; CharToOrdFunc: CharToOrdFuncty;
- UseBytes: boolean = false);
- var
- res, NewStr: String;
- w: Cardinal;
- InString, NewInString: Boolean;
- begin
- if p = nil then begin
- res:= '''''';
- end
- else
- begin
- res := '';
- InString := False;
- while P < LastP do
- begin
- NewInString := InString;
- w := CharToOrdfunc(P);
- if w = ord('''') then
- begin //quote char
- if not InString then
- NewInString := True;
- NewStr := '''''';
- end
- else if (Ord(w) >= 32) and ((Ord(w) < 127) or (UseBytes and (Ord(w)<256))) then
- begin //printable ascii or bytes
- if not InString then
- NewInString := True;
- NewStr := char(w);
- end
- else
- begin //ascii control chars, non ascii
- if InString then
- NewInString := False;
- NewStr := '#' + IntToStr(w);
- end;
- if NewInString <> InString then
- begin
- NewStr := '''' + NewStr;
- InString := NewInString;
- end;
- res := res + NewStr;
- end;
- if InString then
- res := res + '''';
- end;
- OutStr(res);
- end;
- procedure OutString(s: String);
- begin
- OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd,Encoding=oteLFM);
- end;
- procedure OutWString(W: WideString);
- begin
- OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
- end;
- procedure OutUString(W: UnicodeString);
- begin
- OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
- end;
- procedure OutUtf8Str(s: String);
- begin
- if Encoding=oteLFM then
- OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd)
- else
- OutChars(Pointer(S),PChar(S)+Length(S),@Utf8ToOrd);
- end;
- function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- Result:=Input.ReadWord;
- Result:=LEtoN(Result);
- end;
- function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- Result:=Input.ReadDWord;
- Result:=LEtoN(Result);
- end;
- function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- Input.ReadBuffer(Result,sizeof(Result));
- Result:=LEtoN(Result);
- end;
- {$ifndef FPUNONE}
- {$IFNDEF FPC_HAS_TYPE_EXTENDED}
- function ExtendedToDouble(e : pointer) : double;
- var mant : qword;
- exp : smallint;
- sign : boolean;
- d : qword;
- begin
- move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
- move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
- mant:=LEtoN(mant);
- exp:=LetoN(word(exp));
- sign:=(exp and $8000)<>0;
- if sign then exp:=exp and $7FFF;
- case exp of
- 0 : mant:=0; //if denormalized, value is too small for double,
- //so it's always zero
- $7FFF : exp:=2047 //either infinity or NaN
- else
- begin
- dec(exp,16383-1023);
- if (exp>=-51) and (exp<=0) then //can be denormalized
- begin
- mant:=mant shr (-exp);
- exp:=0;
- end
- else
- if (exp<-51) or (exp>2046) then //exponent too large.
- begin
- Result:=0;
- exit;
- end
- else //normalized value
- mant:=mant shl 1; //hide most significant bit
- end;
- end;
- d:=word(exp);
- d:=d shl 52;
- mant:=mant shr 12;
- d:=d or mant;
- if sign then d:=d or $8000000000000000;
- Result:=pdouble(@d)^;
- end;
- {$ENDIF}
- {$endif}
- function ReadInt(ValueType: TValueType): Int64;
- begin
- case ValueType of
- vaInt8: Result := ShortInt(Input.ReadByte);
- vaInt16: Result := SmallInt(ReadWord);
- vaInt32: Result := LongInt(ReadDWord);
- vaInt64: Result := Int64(ReadQWord);
- end;
- end;
- function ReadInt: Int64;
- begin
- Result := ReadInt(TValueType(Input.ReadByte));
- end;
- {$ifndef FPUNONE}
- function ReadExtended : extended;
- {$IFNDEF FPC_HAS_TYPE_EXTENDED}
- var ext : array[0..9] of byte;
- {$ENDIF}
- begin
- {$IFNDEF FPC_HAS_TYPE_EXTENDED}
- Input.ReadBuffer(ext[0],10);
- Result:=ExtendedToDouble(@(ext[0]));
- {$ELSE}
- Input.ReadBuffer(Result,sizeof(Result));
- {$ENDIF}
- end;
- {$endif}
- function ReadSStr: String;
- var
- len: Byte;
- begin
- len := Input.ReadByte;
- SetLength(Result, len);
- if (len > 0) then
- Input.ReadBuffer(Result[1], len);
- end;
- function ReadLStr: String;
- var
- len: DWord;
- begin
- len := ReadDWord;
- SetLength(Result, len);
- if (len > 0) then
- Input.ReadBuffer(Result[1], len);
- end;
- function ReadWStr: WideString;
- var
- len: DWord;
- {$IFDEF ENDIAN_BIG}
- i : integer;
- {$ENDIF}
- begin
- len := ReadDWord;
- SetLength(Result, len);
- if (len > 0) then
- begin
- Input.ReadBuffer(Pointer(@Result[1])^, len*2);
- {$IFDEF ENDIAN_BIG}
- for i:=1 to len do
- Result[i]:=widechar(SwapEndian(word(Result[i])));
- {$ENDIF}
- end;
- end;
- function ReadUStr: UnicodeString;
- var
- len: DWord;
- {$IFDEF ENDIAN_BIG}
- i : integer;
- {$ENDIF}
- begin
- len := ReadDWord;
- SetLength(Result, len);
- if (len > 0) then
- begin
- Input.ReadBuffer(Pointer(@Result[1])^, len*2);
- {$IFDEF ENDIAN_BIG}
- for i:=1 to len do
- Result[i]:=widechar(SwapEndian(word(Result[i])));
- {$ENDIF}
- end;
- end;
- procedure ReadPropList(indent: String);
- procedure ProcessValue(ValueType: TValueType; Indent: String);
- procedure ProcessBinary;
- var
- ToDo, DoNow, i: LongInt;
- lbuf: array[0..31] of Byte;
- s: String;
- begin
- ToDo := ReadDWord;
- OutLn('{');
- while ToDo > 0 do begin
- DoNow := ToDo;
- if DoNow > 32 then DoNow := 32;
- Dec(ToDo, DoNow);
- s := Indent + ' ';
- Input.ReadBuffer(lbuf, DoNow);
- for i := 0 to DoNow - 1 do
- s := s + IntToHex(lbuf[i], 2);
- OutLn(s);
- end;
- OutLn(indent + '}');
- end;
- var
- s: String;
- { len: LongInt; }
- IsFirst: Boolean;
- {$ifndef FPUNONE}
- ext: Extended;
- {$endif}
- begin
- case ValueType of
- vaList: begin
- OutStr('(');
- IsFirst := True;
- while True do begin
- ValueType := TValueType(Input.ReadByte);
- if ValueType = vaNull then break;
- if IsFirst then begin
- OutLn('');
- IsFirst := False;
- end;
- OutStr(Indent + ' ');
- ProcessValue(ValueType, Indent + ' ');
- end;
- OutLn(Indent + ')');
- end;
- vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
- vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
- vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
- vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
- {$ifndef FPUNONE}
- vaExtended: begin
- ext:=ReadExtended;
- Str(ext,S);// Do not use localized strings.
- OutLn(S);
- end;
- {$endif}
- vaString: begin
- OutString(ReadSStr);
- OutLn('');
- end;
- vaIdent: OutLn(ReadSStr);
- vaFalse: OutLn('False');
- vaTrue: OutLn('True');
- vaBinary: ProcessBinary;
- vaSet: begin
- OutStr('[');
- IsFirst := True;
- while True do begin
- s := ReadSStr;
- if Length(s) = 0 then break;
- if not IsFirst then OutStr(', ');
- IsFirst := False;
- OutStr(s);
- end;
- OutLn(']');
- end;
- vaLString:
- begin
- OutString(ReadLStr);
- OutLn('');
- end;
- vaWString:
- begin
- OutWString(ReadWStr);
- OutLn('');
- end;
- vaUString:
- begin
- OutWString(ReadWStr);
- OutLn('');
- end;
- vaNil:
- OutLn('nil');
- vaCollection: begin
- OutStr('<');
- while Input.ReadByte <> 0 do begin
- OutLn(Indent);
- Input.Seek(-1, soFromCurrent);
- OutStr(indent + ' item');
- ValueType := TValueType(Input.ReadByte);
- if ValueType <> vaList then
- OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
- OutLn('');
- ReadPropList(indent + ' ');
- OutStr(indent + ' end');
- end;
- OutLn('>');
- end;
- {vaSingle: begin OutLn('!!Single!!'); exit end;
- vaCurrency: begin OutLn('!!Currency!!'); exit end;
- vaDate: begin OutLn('!!Date!!'); exit end;}
- vaUTF8String: begin
- OutUtf8Str(ReadLStr);
- OutLn('');
- end;
- else
- Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
- end;
- end;
- begin
- while Input.ReadByte <> 0 do begin
- Input.Seek(-1, soFromCurrent);
- OutStr(indent + ReadSStr + ' = ');
- ProcessValue(TValueType(Input.ReadByte), Indent);
- end;
- end;
- procedure ReadObject(indent: String);
- var
- b: Byte;
- ObjClassName, ObjName: String;
- ChildPos: LongInt;
- begin
- // Check for FilerFlags
- b := Input.ReadByte;
- if (b and $f0) = $f0 then begin
- if (b and 2) <> 0 then ChildPos := ReadInt;
- end else begin
- b := 0;
- Input.Seek(-1, soFromCurrent);
- end;
- ObjClassName := ReadSStr;
- ObjName := ReadSStr;
- OutStr(Indent);
- if (b and 1) <> 0 then OutStr('inherited')
- else
- if (b and 4) <> 0 then OutStr('inline')
- else OutStr('object');
- OutStr(' ');
- if ObjName <> '' then
- OutStr(ObjName + ': ');
- OutStr(ObjClassName);
- if (b and 2) <> 0 then OutStr('[' + IntToStr(ChildPos) + ']');
- OutLn('');
- ReadPropList(indent + ' ');
- while Input.ReadByte <> 0 do begin
- Input.Seek(-1, soFromCurrent);
- ReadObject(indent + ' ');
- end;
- OutLn(indent + 'end');
- end;
- type
- PLongWord = ^LongWord;
- const
- signature: PChar = 'TPF0';
- begin
- if Input.ReadDWord <> PLongWord(Pointer(signature))^ then
- raise EReadError.Create('Illegal stream image' {###SInvalidImage});
- ReadObject('');
- end;
- procedure ObjectBinaryToText(Input, Output: TStream);
- begin
- ObjectBinaryToText(Input,Output,oteDFM);
- end;
- procedure ObjectTextToBinary(Input, Output: TStream);
- var
- parser: TParser;
- procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- w:=NtoLE(w);
- Output.WriteWord(w);
- end;
- procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- lw:=NtoLE(lw);
- Output.WriteDWord(lw);
- end;
- procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
- begin
- qw:=NtoLE(qw);
- Output.WriteBuffer(qw,sizeof(qword));
- end;
- {$ifndef FPUNONE}
- {$IFNDEF FPC_HAS_TYPE_EXTENDED}
- procedure DoubleToExtended(d : double; e : pointer);
- var mant : qword;
- exp : smallint;
- sign : boolean;
- begin
- mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
- exp :=(qword(d) shr 52) and $7FF;
- sign:=(qword(d) and $8000000000000000)<>0;
- case exp of
- 0 : begin
- if mant<>0 then //denormalized value: hidden bit is 0. normalize it
- begin
- exp:=16383-1022;
- while (mant and $8000000000000000)=0 do
- begin
- dec(exp);
- mant:=mant shl 1;
- end;
- dec(exp); //don't shift, most significant bit is not hidden in extended
- end;
- end;
- 2047 : exp:=$7FFF //either infinity or NaN
- else
- begin
- inc(exp,16383-1023);
- mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
- end;
- end;
- if sign then exp:=exp or $8000;
- mant:=NtoLE(mant);
- exp:=NtoLE(word(exp));
- move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
- move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
- end;
- {$ENDIF}
- procedure WriteExtended(e : extended);
- {$IFNDEF FPC_HAS_TYPE_EXTENDED}
- var ext : array[0..9] of byte;
- {$ENDIF}
- begin
- {$IFNDEF FPC_HAS_TYPE_EXTENDED}
- DoubleToExtended(e,@(ext[0]));
- Output.WriteBuffer(ext[0],10);
- {$ELSE}
- Output.WriteBuffer(e,sizeof(e));
- {$ENDIF}
- end;
- {$endif}
- procedure WriteString(s: String);
- var size : byte;
- begin
- if length(s)>255 then size:=255
- else size:=length(s);
- Output.WriteByte(size);
- if Length(s) > 0 then
- Output.WriteBuffer(s[1], size);
- end;
- procedure WriteLString(Const s: String);
- begin
- WriteDWord(Length(s));
- if Length(s) > 0 then
- Output.WriteBuffer(s[1], Length(s));
- end;
- procedure WriteWString(Const s: WideString);
- var len : longword;
- {$IFDEF ENDIAN_BIG}
- i : integer;
- ws : widestring;
- {$ENDIF}
- begin
- len:=Length(s);
- WriteDWord(len);
- if len > 0 then
- begin
- {$IFDEF ENDIAN_BIG}
- setlength(ws,len);
- for i:=1 to len do
- ws[i]:=widechar(SwapEndian(word(s[i])));
- Output.WriteBuffer(ws[1], len*sizeof(widechar));
- {$ELSE}
- Output.WriteBuffer(s[1], len*sizeof(widechar));
- {$ENDIF}
- end;
- end;
- procedure WriteInteger(value: Int64);
- begin
- if (value >= -128) and (value <= 127) then begin
- Output.WriteByte(Ord(vaInt8));
- Output.WriteByte(byte(value));
- end else if (value >= -32768) and (value <= 32767) then begin
- Output.WriteByte(Ord(vaInt16));
- WriteWord(word(value));
- end else if (value >= -2147483648) and (value <= 2147483647) then begin
- Output.WriteByte(Ord(vaInt32));
- WriteDWord(longword(value));
- end else begin
- Output.WriteByte(ord(vaInt64));
- WriteQWord(qword(value));
- end;
- end;
- procedure ProcessWideString(const left : widestring);
- var ws : widestring;
- begin
- ws:=left+parser.TokenWideString;
- while parser.NextToken = '+' do
- begin
- parser.NextToken; // Get next string fragment
- if not (parser.Token in [toString,toWString]) then
- parser.CheckToken(toWString);
- ws:=ws+parser.TokenWideString;
- end;
- Output.WriteByte(Ord(vaWstring));
- WriteWString(ws);
- end;
- procedure ProcessProperty; forward;
- procedure ProcessValue;
- var
- {$ifndef FPUNONE}
- flt: Extended;
- {$endif}
- s: String;
- stream: TMemoryStream;
- begin
- case parser.Token of
- toInteger:
- begin
- WriteInteger(parser.TokenInt);
- parser.NextToken;
- end;
- {$ifndef FPUNONE}
- toFloat:
- begin
- Output.WriteByte(Ord(vaExtended));
- flt := Parser.TokenFloat;
- WriteExtended(flt);
- parser.NextToken;
- end;
- {$endif}
- toString:
- begin
- s := parser.TokenString;
- while parser.NextToken = '+' do
- begin
- parser.NextToken; // Get next string fragment
- case parser.Token of
- toString : s:=s+parser.TokenString;
- toWString : begin
- ProcessWideString(WideString(s));
- exit;
- end
- else parser.CheckToken(toString);
- end;
- end;
- if (length(S)>255) then
- begin
- Output.WriteByte(Ord(vaLString));
- WriteLString(S);
- end
- else
- begin
- Output.WriteByte(Ord(vaString));
- WriteString(s);
- end;
- end;
- toWString:
- ProcessWideString('');
- toSymbol:
- begin
- if CompareText(parser.TokenString, 'True') = 0 then
- Output.WriteByte(Ord(vaTrue))
- else if CompareText(parser.TokenString, 'False') = 0 then
- Output.WriteByte(Ord(vaFalse))
- else if CompareText(parser.TokenString, 'nil') = 0 then
- Output.WriteByte(Ord(vaNil))
- else
- begin
- Output.WriteByte(Ord(vaIdent));
- WriteString(parser.TokenComponentIdent);
- end;
- Parser.NextToken;
- end;
- // Set
- '[':
- begin
- parser.NextToken;
- Output.WriteByte(Ord(vaSet));
- if parser.Token <> ']' then
- while True do
- begin
- parser.CheckToken(toSymbol);
- WriteString(parser.TokenString);
- parser.NextToken;
- if parser.Token = ']' then
- break;
- parser.CheckToken(',');
- parser.NextToken;
- end;
- Output.WriteByte(0);
- parser.NextToken;
- end;
- // List
- '(':
- begin
- parser.NextToken;
- Output.WriteByte(Ord(vaList));
- while parser.Token <> ')' do
- ProcessValue;
- Output.WriteByte(0);
- parser.NextToken;
- end;
- // Collection
- '<':
- begin
- parser.NextToken;
- Output.WriteByte(Ord(vaCollection));
- while parser.Token <> '>' do
- begin
- parser.CheckTokenSymbol('item');
- parser.NextToken;
- // ConvertOrder
- Output.WriteByte(Ord(vaList));
- while not parser.TokenSymbolIs('end') do
- ProcessProperty;
- parser.NextToken; // Skip 'end'
- Output.WriteByte(0);
- end;
- Output.WriteByte(0);
- parser.NextToken;
- end;
- // Binary data
- '{':
- begin
- Output.WriteByte(Ord(vaBinary));
- stream := TMemoryStream.Create;
- try
- parser.HexToBinary(stream);
- WriteDWord(stream.Size);
- Output.WriteBuffer(Stream.Memory^, stream.Size);
- finally
- stream.Free;
- end;
- parser.NextToken;
- end;
- else
- parser.Error(SInvalidProperty);
- end;
- end;
- procedure ProcessProperty;
- var
- name: String;
- begin
- // Get name of property
- parser.CheckToken(toSymbol);
- name := parser.TokenString;
- while True do begin
- parser.NextToken;
- if parser.Token <> '.' then break;
- parser.NextToken;
- parser.CheckToken(toSymbol);
- name := name + '.' + parser.TokenString;
- end;
- WriteString(name);
- parser.CheckToken('=');
- parser.NextToken;
- ProcessValue;
- end;
- procedure ProcessObject;
- var
- Flags: Byte;
- ObjectName, ObjectType: String;
- ChildPos: Integer;
- begin
- if parser.TokenSymbolIs('OBJECT') then
- Flags :=0 { IsInherited := False }
- else begin
- if parser.TokenSymbolIs('INHERITED') then
- Flags := 1 { IsInherited := True; }
- else begin
- parser.CheckTokenSymbol('INLINE');
- Flags := 4;
- end;
- end;
- parser.NextToken;
- parser.CheckToken(toSymbol);
- ObjectName := '';
- ObjectType := parser.TokenString;
- parser.NextToken;
- if parser.Token = ':' then begin
- parser.NextToken;
- parser.CheckToken(toSymbol);
- ObjectName := ObjectType;
- ObjectType := parser.TokenString;
- parser.NextToken;
- if parser.Token = '[' then begin
- parser.NextToken;
- ChildPos := parser.TokenInt;
- parser.NextToken;
- parser.CheckToken(']');
- parser.NextToken;
- Flags := Flags or 2;
- end;
- end;
- if Flags <> 0 then begin
- Output.WriteByte($f0 or Flags);
- if (Flags and 2) <> 0 then
- WriteInteger(ChildPos);
- end;
- WriteString(ObjectType);
- WriteString(ObjectName);
- // Convert property list
- while not (parser.TokenSymbolIs('END') or
- parser.TokenSymbolIs('OBJECT') or
- parser.TokenSymbolIs('INHERITED') or
- parser.TokenSymbolIs('INLINE')) do
- ProcessProperty;
- Output.WriteByte(0); // Terminate property list
- // Convert child objects
- while not parser.TokenSymbolIs('END') do ProcessObject;
- parser.NextToken; // Skip end token
- Output.WriteByte(0); // Terminate property list
- end;
- const
- signature: PChar = 'TPF0';
- begin
- parser := TParser.Create(Input);
- try
- Output.WriteBuffer(signature[0], 4);
- ProcessObject;
- finally
- parser.Free;
- end;
- end;
- procedure ObjectResourceToText(Input, Output: TStream);
- begin
- Input.ReadResHeader;
- ObjectBinaryToText(Input, Output);
- end;
- procedure ObjectTextToResource(Input, Output: TStream);
- var
- StartPos, FixupInfo: LongInt;
- parser: TParser;
- name: String;
- begin
- // Get form type name
- StartPos := Input.Position;
- parser := TParser.Create(Input);
- try
- if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
- parser.NextToken;
- parser.CheckToken(toSymbol);
- parser.NextToken;
- parser.CheckToken(':');
- parser.NextToken;
- parser.CheckToken(toSymbol);
- name := parser.TokenString;
- finally
- parser.Free;
- Input.Position := StartPos;
- end;
- name := UpperCase(name);
- Output.WriteResourceHeader(name,FixupInfo); // Write resource header
- ObjectTextToBinary(Input, Output); // Convert the stuff!
- Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
- end;
- { Utility routines }
- function LineStart(Buffer, BufPos: PChar): PChar;
- begin
- Result := BufPos;
- while Result > Buffer do begin
- Dec(Result);
- if Result[0] = #10 then break;
- end;
- end;
- procedure CommonInit;
- begin
- SynchronizeTimeoutEvent:=RtlEventCreate;
- InitCriticalSection(ThreadQueueLock);
- MainThreadID:=GetCurrentThreadID;
- ExternalThreads := TThreadList.Create;
- TThread.FProcessorCount := CPUCount;
- InitCriticalsection(ResolveSection);
- InitHandlerList:=Nil;
- FindGlobalComponentList:=nil;
- IntConstList := TThreadList.Create;
- ClassList := TThreadList.Create;
- ClassAliasList := TStringList.Create;
- { on unix this maps to a simple rw synchornizer }
- GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
- RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
- end;
- procedure CommonCleanup;
- var
- i: Integer;
- tmpentry: TThread.PThreadQueueEntry;
- begin
- GlobalNameSpace.BeginWrite;
- with IntConstList.LockList do
- try
- for i := 0 to Count - 1 do
- TIntConst(Items[I]).Free;
- finally
- IntConstList.UnlockList;
- end;
- IntConstList.Free;
- ClassList.Free;
- ClassAliasList.Free;
- RemoveFixupReferences(nil, '');
- DoneCriticalsection(ResolveSection);
- GlobalLists.Free;
- ComponentPages.Free;
- FreeAndNil(NeedResolving);
- { GlobalNameSpace is an interface so this is enough }
- GlobalNameSpace:=nil;
- if (InitHandlerList<>Nil) then
- for i := 0 to InitHandlerList.Count - 1 do
- TInitHandler(InitHandlerList.Items[I]).Free;
- InitHandlerList.Free;
- InitHandlerList:=Nil;
- FindGlobalComponentList.Free;
- FindGlobalComponentList:=nil;
- ExternalThreadsCleanup:=True;
- with ExternalThreads.LockList do
- try
- for i := 0 to Count - 1 do
- TThread(Items[i]).Free;
- finally
- ExternalThreads.UnlockList;
- end;
- FreeAndNil(ExternalThreads);
- RtlEventDestroy(SynchronizeTimeoutEvent);
- { clean up the queue, but keep in mind that the entries used for Synchronize
- are owned by the corresponding TThread }
- while Assigned(ThreadQueueHead) do begin
- tmpentry := ThreadQueueHead;
- ThreadQueueHead := tmpentry^.Next;
- if not Assigned(tmpentry^.SyncEvent) then
- Dispose(tmpentry);
- end;
- DoneCriticalSection(ThreadQueueLock);
- end;
- { TFiler implementation }
- {$i filer.inc}
- { TReader implementation }
- {$i reader.inc}
- { TWriter implementations }
- {$i writer.inc}
- {$i twriter.inc}
|