IdThreadComponent.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.13 9/30/2004 2:26:04 PM BGooijen
  18. wrong property was referenced
  19. Rev 1.12 2004.02.03 4:17:12 PM czhower
  20. For unit name changes.
  21. Rev 1.11 2004.01.20 10:03:38 PM czhower
  22. InitComponent
  23. Rev 1.10 09.11.2003 14:05:52 ARybin
  24. AV
  25. Rev 1.9 08.11.2003 20:03:20 ARybin
  26. run-time active bug
  27. Rev 1.8 10/15/2003 8:48:58 PM DSiders
  28. Added resource strings for exceptions raised when setting thread component
  29. properties.
  30. Rev 1.7 2003.10.11 9:58:04 PM czhower
  31. Several bug fixes
  32. Rev 1.6 2003.10.11 5:51:54 PM czhower
  33. -VCL fixes for servers
  34. -Chain suport for servers (Super core)
  35. -Scheduler upgrades
  36. -Full yarn support
  37. Rev 1.5 2003.09.30 7:48:02 PM czhower
  38. Fixed Loop and ThreadName
  39. Rev 1.4 9/18/2003 07:40:52 PM JPMugaas
  40. Removed IdGlobal.
  41. Rev 1.3 9/16/2003 04:47:22 PM JPMugaas
  42. Made some code follow the Indy conventions so it's easier to debug.
  43. Rev 1.2 2003.07.01 4:14:38 PM czhower
  44. ThreadName and Loop added. Other bugs fixed.
  45. Rev 1.1 06.03.2003 12:16:52 ARybin
  46. adapted for new IdThread
  47. Rev 1.0 11/13/2002 08:03:06 AM JPMugaas
  48. 2002-05-03 -Andrew P.Rybin
  49. -Stéphane Grobéty (Fulgan) suggestion: component is Data owner, don't FreeAndNIL Data property
  50. -special TThread.OnTerminate support (it is sync-event)
  51. 2002-05-23 -APR
  52. -right support for Thread terminate
  53. }
  54. unit IdThreadComponent;
  55. {
  56. UnitName: IdThreadComponent
  57. Author: Andrew P.Rybin [[email protected]]
  58. Creation: 12.03.2002
  59. Version: 0.1.0
  60. Purpose:
  61. History: Based on my TmcThread
  62. }
  63. interface
  64. {$I IdCompilerDefines.inc}
  65. //Put FPC into Delphi mode
  66. uses
  67. Classes,
  68. IdBaseComponent, IdException, IdGlobal, IdThread, SysUtils;
  69. const
  70. IdThreadComponentDefaultPriority = tpNormal;
  71. IdThreadComponentDefaultStopMode = smTerminate;
  72. type
  73. TIdThreadComponent = class;
  74. TIdExceptionThreadComponentEvent = procedure(Sender: TIdThreadComponent; AException: Exception) of object;
  75. TIdExceptionThreadComponentEventEx = procedure(Sender: TIdThreadComponent; AException: Exception; var VHandled: Boolean) of object;
  76. TIdNotifyThreadComponentEvent = procedure(Sender: TIdThreadComponent) of object;
  77. //TIdSynchronizeThreadComponentEvent = procedure(Sender: TIdThreadComponent; AData: Pointer) of object;
  78. TIdThreadComponent = class(TIdBaseComponent)
  79. protected
  80. FActive: Boolean;
  81. FLoop: Boolean;
  82. FPriority : TIdThreadPriority;
  83. FStopMode : TIdThreadStopMode;
  84. FThread: TIdThread;
  85. FThreadName: string;
  86. //
  87. FOnAfterExecute: TIdNotifyThreadComponentEvent;
  88. FOnAfterRun: TIdNotifyThreadComponentEvent;
  89. FOnBeforeExecute: TIdNotifyThreadComponentEvent;
  90. FOnBeforeRun: TIdNotifyThreadComponentEvent;
  91. FOnCleanup: TIdNotifyThreadComponentEvent;
  92. FOnException: TIdExceptionThreadComponentEvent;
  93. FOnRun: TIdNotifyThreadComponentEvent;
  94. FOnStopped: TIdNotifyThreadComponentEvent;
  95. FOnTerminate: TIdNotifyThreadComponentEvent;
  96. FOnHandleRunException: TIdExceptionThreadComponentEventEx;
  97. //
  98. {$IFDEF INT_THREAD_PRIORITY}
  99. procedure DefineProperties(Filer: TFiler); override;
  100. procedure ReadPriority(Reader: TReader);
  101. procedure WritePriority(Writer: TWriter);
  102. {$ENDIF}
  103. procedure DoAfterExecute; virtual;
  104. procedure DoAfterRun; virtual;
  105. procedure DoBeforeExecute; virtual;
  106. procedure DoBeforeRun; virtual;
  107. procedure DoCleanup; virtual;
  108. procedure DoException(AThread: TIdThread; AException: Exception); virtual; //thev
  109. function DoHandleRunException(AException: Exception): Boolean; virtual;
  110. procedure DoRun; virtual;
  111. procedure DoStopped(AThread: TIdThread); virtual; //thev
  112. procedure DoTerminate(Sender: TObject); virtual; //thev
  113. function GetActive: Boolean;
  114. // When ARC is enabled, object references MUST be valid objects.
  115. // It is common for users to store non-object values, though, so
  116. // we will provide separate properties for those purposes
  117. function GetDataObject: TObject;
  118. function GetDataValue: PtrInt;
  119. //
  120. function GetHandle: TIdThreadHandle;
  121. function GetPriority: TIdThreadPriority;
  122. function GetReturnValue: Integer;
  123. function GetStopMode: TIdThreadStopMode;
  124. function GetStopped: Boolean;
  125. function GetSuspended: Boolean;
  126. function GetTerminatingException: string;
  127. function GetTerminatingExceptionClass: TClass;
  128. function GetTerminated: Boolean;
  129. function IsRunning: Boolean;
  130. procedure Loaded; override;
  131. procedure SetActive(const AValue: Boolean); virtual;
  132. procedure SetDataObject(const AValue: TObject);
  133. procedure SetDataValue(const AValue: PtrInt);
  134. procedure SetLoop(const AValue: Boolean);
  135. procedure SetThreadName(const AValue: string);
  136. procedure SetOnTerminate(const AValue: TIdNotifyThreadComponentEvent);
  137. procedure SetPriority(const AValue: TIdThreadPriority);
  138. procedure SetReturnValue(const AValue: Integer);
  139. procedure SetStopMode(const AValue: TIdThreadStopMode);
  140. public
  141. constructor Create(AOwner: TComponent); override;
  142. destructor Destroy; override;
  143. procedure Start; virtual;
  144. procedure Stop; virtual;
  145. procedure Synchronize(AMethod: TThreadMethod);
  146. procedure Terminate; virtual;
  147. procedure TerminateAndWaitFor; virtual;
  148. function WaitFor: UInt32;
  149. // Properties
  150. property DataObject: TObject read GetDataObject write SetDataObject;
  151. property DataValue: PtrInt read GetDataValue write SetDataValue;
  152. {$IFNDEF USE_OBJECT_ARC}
  153. property Data: TObject read GetDataObject write SetDataObject; // deprecated 'Use DataObject or DataValue property.';
  154. {$ENDIF}
  155. property Handle: TIdThreadHandle read GetHandle;
  156. property ReturnValue: Integer read GetReturnValue write SetReturnValue;
  157. property Stopped: Boolean read GetStopped;
  158. property Suspended: Boolean read GetSuspended;
  159. property TerminatingException: string read GetTerminatingException;
  160. property TerminatingExceptionClass: TClass read GetTerminatingExceptionClass;
  161. property Terminated: Boolean read GetTerminated;
  162. {$IFDEF INT_THREAD_PRIORITY}
  163. property Priority: TIdThreadPriority read GetPriority write SetPriority;
  164. {$ENDIF}
  165. published
  166. property Active: Boolean read GetActive write SetActive;
  167. property Loop: Boolean read FLoop write SetLoop;
  168. {$IFNDEF INT_THREAD_PRIORITY}
  169. property Priority: TIdThreadPriority read GetPriority write SetPriority;
  170. {$ENDIF}
  171. property StopMode: TIdThreadStopMode read GetStopMode write SetStopMode;
  172. property ThreadName: string read FThreadName write SetThreadName;
  173. // Events
  174. property OnAfterExecute: TIdNotifyThreadComponentEvent read FOnAfterExecute write FOnAfterExecute;
  175. property OnAfterRun: TIdNotifyThreadComponentEvent read FOnAfterRun write FOnAfterRun;
  176. property OnBeforeExecute: TIdNotifyThreadComponentEvent read FOnBeforeExecute write FOnBeforeExecute;
  177. property OnBeforeRun: TIdNotifyThreadComponentEvent read FOnBeforeRun write FOnBeforeRun;
  178. property OnCleanup: TIdNotifyThreadComponentEvent read FOnCleanup write FOnCleanup;
  179. property OnException: TIdExceptionThreadComponentEvent read FOnException write FOnException;
  180. property OnHandleRunException: TIdExceptionThreadComponentEventEx
  181. read FOnHandleRunException write FOnHandleRunException;
  182. property OnRun: TIdNotifyThreadComponentEvent read FOnRun write FOnRun;
  183. property OnStopped: TIdNotifyThreadComponentEvent read FOnStopped
  184. write FOnStopped;
  185. property OnTerminate: TIdNotifyThreadComponentEvent read FOnTerminate
  186. write SetOnTerminate;
  187. end;
  188. //For Component-writers ONLY!
  189. TIdThreadEx = class(TIdThread)
  190. protected
  191. FThreadComponent: TIdThreadComponent;
  192. //
  193. procedure AfterRun; override;
  194. procedure AfterExecute; override;
  195. procedure BeforeExecute; override;
  196. procedure BeforeRun; override;
  197. procedure Cleanup; override;
  198. function HandleRunException(AException: Exception): Boolean; override;
  199. procedure Run; override;
  200. public
  201. constructor Create(AThreadComponent: TIdThreadComponent); reintroduce;
  202. end;
  203. implementation
  204. uses
  205. IdResourceStringsCore;
  206. { TIdThreadEx }
  207. procedure TIdThreadEx.AfterExecute;
  208. begin
  209. try
  210. FThreadComponent.DoAfterExecute;
  211. finally
  212. FThreadComponent.FActive := FALSE;
  213. end;
  214. end;
  215. procedure TIdThreadEx.AfterRun;
  216. begin
  217. FThreadComponent.DoAfterRun;
  218. end;
  219. procedure TIdThreadEx.BeforeExecute;
  220. begin
  221. FThreadComponent.DoBeforeExecute;
  222. end;
  223. procedure TIdThreadEx.BeforeRun;
  224. begin
  225. FThreadComponent.DoBeforeRun;
  226. end;
  227. procedure TIdThreadEx.Cleanup;
  228. begin
  229. inherited Cleanup;
  230. FThreadComponent.DoCleanup;
  231. end;
  232. constructor TIdThreadEx.Create(AThreadComponent: TIdThreadComponent);
  233. begin
  234. inherited Create(True, AThreadComponent.Loop, iif(AThreadComponent.ThreadName = ''
  235. , AThreadComponent.Name, AThreadComponent.ThreadName));
  236. Exclude(FOptions, itoDataOwner); //TIdThreadComponent is data owner
  237. FThreadComponent := AThreadComponent;
  238. FOnException := FThreadComponent.DoException;
  239. FOnStopped := FThreadComponent.DoStopped;
  240. end;
  241. function TIdThreadEx.HandleRunException(AException: Exception): Boolean;
  242. begin
  243. Result := FThreadComponent.DoHandleRunException(AException);
  244. end;
  245. procedure TIdThreadEx.Run;
  246. begin
  247. FThreadComponent.DoRun;
  248. end;
  249. { TIdThreadComponent }
  250. constructor TIdThreadComponent.Create(AOwner: TComponent);
  251. begin
  252. inherited Create(AOwner);
  253. StopMode := IdThreadComponentDefaultStopMode;
  254. Priority := IdThreadComponentDefaultPriority;
  255. end;
  256. destructor TIdThreadComponent.Destroy;
  257. begin
  258. {FThread.TerminateAndWaitFor;}
  259. //make sure thread is not active before we attempt to destroy it
  260. if Assigned(FThread) then begin
  261. FThread.Terminate;
  262. FThread.Start;//resume for terminate
  263. end;
  264. IdDisposeAndNil(FThread);
  265. inherited Destroy;
  266. end;
  267. {$IFDEF INT_THREAD_PRIORITY}
  268. procedure TIdThreadComponent.DefineProperties(Filer: TFiler);
  269. begin
  270. inherited;
  271. Filer.DefineProperty('Priority', ReadPriority, WritePriority, FPriority <> tpNormal); {do not localize}
  272. end;
  273. procedure TIdThreadComponent.ReadPriority(Reader: TReader);
  274. const
  275. PriorityStrings: array[0..6] of string = ('tpIdle', 'tpLowest', 'tpLower', 'tpNormal', 'tpHigher', 'tpHighest', 'tpTimeCritical'); {do not localize}
  276. var
  277. Value: Integer;
  278. begin
  279. if Reader.NextValue = vaIdent then
  280. begin
  281. // an older DFM that stored TThreadPriority as enum value names is being read, so convert to integer ...
  282. case PosInStrArray(Reader.ReadIdent, PriorityStrings, False) of
  283. 0: Value := tpIdle;
  284. 1: Value := tpLowest;
  285. 2: Value := tpLower;
  286. 3: Value := tpNormal;
  287. 4: Value := tpHigher;
  288. 5: Value := tpHighest;
  289. 6: Value := tpTimeCritical;
  290. else
  291. Value := tpNormal;
  292. end;
  293. end else
  294. begin
  295. Value := Reader.ReadInteger;
  296. if Value < -20 then begin
  297. Value := -20;
  298. end
  299. else if Value > 19 then begin
  300. Value := 19;
  301. end;
  302. end;
  303. FPriority := Value;
  304. end;
  305. procedure TIdThreadComponent.WritePriority(Writer: TWriter);
  306. begin
  307. Writer.WriteInteger(FPriority);
  308. end;
  309. {$ENDIF}
  310. procedure TIdThreadComponent.DoAfterExecute;
  311. begin
  312. if Assigned(FOnAfterExecute) then
  313. begin
  314. FOnAfterExecute(Self);
  315. end;
  316. end;
  317. procedure TIdThreadComponent.DoAfterRun;
  318. begin
  319. if Assigned(FOnAfterRun) then
  320. begin
  321. FOnAfterRun(Self);
  322. end;
  323. end;
  324. procedure TIdThreadComponent.DoBeforeExecute;
  325. begin
  326. if Assigned(FOnBeforeExecute) then
  327. begin
  328. FOnBeforeExecute(Self);
  329. end;
  330. end;
  331. procedure TIdThreadComponent.DoBeforeRun;
  332. begin
  333. if Assigned(FOnBeforeRun) then
  334. begin
  335. FOnBeforeRun(Self);
  336. end;
  337. end;
  338. procedure TIdThreadComponent.DoCleanup;
  339. begin
  340. if Assigned(FOnCleanup) then
  341. begin
  342. FOnCleanup(Self);
  343. end;
  344. end;
  345. procedure TIdThreadComponent.DoException(AThread: TIdThread; AException: Exception);
  346. begin
  347. if Assigned(FOnException) then begin
  348. FOnException(Self, AException);
  349. end;
  350. end;
  351. function TIdThreadComponent.DoHandleRunException(AException: Exception): Boolean;
  352. begin
  353. Result := False;//not handled
  354. if Assigned(FOnHandleRunException) then begin
  355. FOnHandleRunException(Self, AException, Result);
  356. end;
  357. end;
  358. procedure TIdThreadComponent.DoStopped(AThread: TIdThread);
  359. begin
  360. if Assigned(FOnStopped) then begin
  361. FOnStopped(Self);
  362. end;
  363. end;
  364. procedure TIdThreadComponent.DoTerminate;
  365. begin
  366. if Assigned(FOnTerminate) then begin
  367. FOnTerminate(Self);
  368. end;
  369. end;
  370. function TIdThreadComponent.GetDataObject: TObject;
  371. begin
  372. Result := FThread.DataObject;
  373. end;
  374. function TIdThreadComponent.GetDataValue: PtrInt;
  375. begin
  376. Result := FThread.DataValue;
  377. end;
  378. function TIdThreadComponent.GetHandle: TIdThreadHandle;
  379. begin
  380. Result := GetThreadHandle(FThread);
  381. end;
  382. function TIdThreadComponent.GetReturnValue: Integer;
  383. begin
  384. Result := FThread.ReturnValue;
  385. end;
  386. function TIdThreadComponent.GetStopMode: TIdThreadStopMode;
  387. begin
  388. if Assigned(FThread) then begin
  389. Result := FThread.StopMode;
  390. end else begin
  391. Result := FStopMode;
  392. end;
  393. end;
  394. function TIdThreadComponent.GetStopped: Boolean;
  395. begin
  396. if Assigned(FThread) then begin
  397. Result := FThread.Stopped;
  398. end else begin
  399. Result := True;
  400. end;
  401. end;
  402. function TIdThreadComponent.GetSuspended: Boolean;
  403. begin
  404. Result := FThread.Suspended;
  405. end;
  406. function TIdThreadComponent.GetTerminated: Boolean;
  407. begin
  408. if Assigned(FThread) then begin
  409. Result := FThread.Terminated;
  410. end else begin
  411. Result := True;
  412. end;
  413. end;
  414. function TIdThreadComponent.GetTerminatingException: string;
  415. begin
  416. Result := FThread.TerminatingException;
  417. end;
  418. function TIdThreadComponent.GetTerminatingExceptionClass: TClass;
  419. begin
  420. Result := FThread.TerminatingExceptionClass;
  421. end;
  422. procedure TIdThreadComponent.Loaded;
  423. begin
  424. inherited Loaded;
  425. // Active = True must not be performed before all other props are loaded
  426. if Assigned(FThread) and Assigned(OnTerminate) then begin
  427. FThread.OnTerminate := DoTerminate;
  428. end;
  429. if FActive then begin
  430. // Retoggle for load since we ignore during loading until all properties
  431. // are ready
  432. FActive := False;
  433. Active := True;
  434. end;
  435. end;
  436. procedure TIdThreadComponent.DoRun;
  437. begin
  438. if Assigned(FOnRun) then begin
  439. FOnRun(Self);
  440. end;
  441. end;
  442. procedure TIdThreadComponent.SetActive(const AValue: Boolean);
  443. begin
  444. if IsDesignTime or IsLoading then begin
  445. FActive := AValue;
  446. end
  447. else if Active <> AValue then begin
  448. if AValue then begin
  449. Start;
  450. end else begin
  451. Stop;
  452. end;
  453. FActive := AValue;
  454. end;
  455. end;
  456. procedure TIdThreadComponent.SetDataObject(const AValue: TObject);
  457. begin
  458. // this should not be accessed at design-time.
  459. FThread.DataObject := AValue;
  460. end;
  461. procedure TIdThreadComponent.SetDataValue(const AValue: PtrInt);
  462. begin
  463. // this should not be accessed at design-time.
  464. FThread.DataValue := AValue;
  465. end;
  466. procedure TIdThreadComponent.SetReturnValue(const AValue: Integer);
  467. begin
  468. // this should not be accessed at design-time.
  469. FThread.ReturnValue := AValue;
  470. end;
  471. procedure TIdThreadComponent.SetStopMode(const AValue: TIdThreadStopMode);
  472. begin
  473. if Assigned(FThread) and not FThread.Terminated then begin
  474. FThread.StopMode := AValue;
  475. end;
  476. FStopMode := AValue;
  477. end;
  478. procedure TIdThreadComponent.Start;
  479. begin
  480. if not IsDesignTime then begin
  481. if Assigned(FThread) and FThread.Terminated then begin
  482. IdDisposeAndNil(FThread);
  483. end;
  484. if not Assigned(FThread) then begin
  485. FThread := TIdThreadEx.Create(Self);
  486. end;
  487. // MUST read from F variants as thread is now created
  488. if Assigned(FOnTerminate) then begin
  489. FThread.OnTerminate := DoTerminate;
  490. end else begin
  491. FThread.OnTerminate := nil;
  492. end;
  493. FThread.Name := FThreadName;
  494. FThread.Loop := FLoop;
  495. FThread.Priority := FPriority;
  496. FThread.StopMode := FStopMode;
  497. FThread.Start;
  498. end;
  499. end;
  500. procedure TIdThreadComponent.Stop;
  501. begin
  502. if Assigned(FThread) then begin
  503. FThread.Stop;
  504. end;
  505. end;
  506. procedure TIdThreadComponent.Synchronize(AMethod: TThreadMethod);
  507. begin
  508. FThread.Synchronize(AMethod);
  509. end;
  510. procedure TIdThreadComponent.Terminate;
  511. begin
  512. FThread.Terminate;
  513. end;
  514. procedure TIdThreadComponent.TerminateAndWaitFor;
  515. begin
  516. FThread.TerminateAndWaitFor;
  517. end;
  518. function TIdThreadComponent.WaitFor: UInt32;
  519. begin
  520. Result := FThread.WaitFor;
  521. end;
  522. function TIdThreadComponent.GetPriority: TIdThreadPriority;
  523. begin
  524. if Assigned(FThread) then begin
  525. Result := FThread.Priority;
  526. end else begin
  527. Result := FPriority;
  528. end;
  529. end;
  530. procedure TIdThreadComponent.SetPriority(const AValue: TIdThreadPriority);
  531. begin
  532. if Assigned(FThread) then begin
  533. if not FThread.Terminated then begin
  534. FThread.Priority := AValue;
  535. end;
  536. end;
  537. FPriority := AValue;
  538. end;
  539. function TIdThreadComponent.GetActive: Boolean;
  540. begin
  541. if IsDesignTime then begin
  542. Result := FActive;
  543. end else begin
  544. Result := IsRunning;
  545. end;
  546. end;
  547. procedure TIdThreadComponent.SetOnTerminate(const AValue: TIdNotifyThreadComponentEvent);
  548. begin
  549. FOnTerminate := AValue;
  550. if Assigned(FThread) then begin
  551. if Assigned(AValue) then begin
  552. FThread.OnTerminate := DoTerminate;
  553. end else begin
  554. FThread.OnTerminate := nil;
  555. end;
  556. end;
  557. end;
  558. procedure TIdThreadComponent.SetLoop(const AValue: Boolean);
  559. begin
  560. if IsRunning then begin
  561. raise EIdException.Create(RSThreadComponentLoopAlreadyRunning); // TODO: create a new Exception class for this
  562. end;
  563. FLoop := AValue;
  564. end;
  565. procedure TIdThreadComponent.SetThreadName(const AValue: string);
  566. begin
  567. if IsRunning then begin
  568. raise EIdException.Create(RSThreadComponentThreadNameAlreadyRunning); // TODO: create a new Exception class for this
  569. end;
  570. FThreadName := AValue;
  571. end;
  572. function TIdThreadComponent.IsRunning: Boolean;
  573. begin
  574. if Assigned(FThread) then begin
  575. Result := not FThread.Stopped;
  576. end else begin
  577. Result := False;
  578. end;
  579. end;
  580. end.