IdThreadComponent.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 10377: IdThreadComponent.pas
  11. {
  12. { Rev 1.2 2003.06.15 6:20:38 PM czhower
  13. { Exposed real thread for TIdSync and other purposes.
  14. }
  15. {
  16. { Rev 1.1 2003.06.15 5:35:02 PM czhower
  17. { Fixed OnTerminate. If OnTerminate was set, it would AV when component was
  18. { created.
  19. }
  20. {
  21. { Rev 1.0 2002.11.12 10:56:00 PM czhower
  22. }
  23. {-----------------------------------------------------------------------------
  24. UnitName: IdThreadComponent
  25. Author: Andrew P.Rybin [[email protected]]
  26. Creation: 12.03.2002
  27. Version: 0.1.0
  28. Purpose:
  29. History: Based on my TmcThread
  30. 2002-05-03 -Andrew P.Rybin
  31. -Stéphane Grobéty (Fulgan) suggestion: component is Data owner, don't
  32. FreeAndNIL Data property
  33. -special TThread.OnTerminate support (it is sync-event)
  34. 2002-05-23 -APR
  35. -right support for Thread terminate
  36. 2002 - Kudzu
  37. -Original concept with implementation by J Peter
  38. -----------------------------------------------------------------------------}
  39. unit IdThreadComponent;
  40. interface
  41. uses
  42. Classes, IdBaseComponent,
  43. IdException, IdGlobal, IdThread,
  44. SysUtils;
  45. const
  46. IdThreadComponentDefaultPriority = tpNormal;
  47. IdThreadComponentDefaultStopMode = smTerminate;
  48. type
  49. TIdCustomThreadComponent = class;
  50. TIdExceptionThreadComponentEvent = procedure(Sender: TIdCustomThreadComponent; AException: Exception) of object;
  51. TIdNotifyThreadComponentEvent = procedure(Sender: TIdCustomThreadComponent) of object;
  52. //TIdSynchronizeThreadComponentEvent = procedure(Sender: TIdCustomThreadComponent; AData: Pointer) of object;
  53. TIdCustomThreadComponent = class(TIdBaseComponent)
  54. protected
  55. FActive: Boolean;
  56. FPriority : TIdThreadPriority;
  57. FStopMode : TIdThreadStopMode;
  58. FThread: TIdThread;
  59. //
  60. FOnAfterExecute: TIdNotifyThreadComponentEvent;
  61. FOnAfterRun: TIdNotifyThreadComponentEvent;
  62. FOnBeforeExecute: TIdNotifyThreadComponentEvent;
  63. FOnBeforeRun: TIdNotifyThreadComponentEvent;
  64. FOnCleanup: TIdNotifyThreadComponentEvent;
  65. FOnException: TIdExceptionThreadComponentEvent;
  66. FOnRun: TIdNotifyThreadComponentEvent;
  67. FOnStopped: TIdNotifyThreadComponentEvent;
  68. FOnTerminate: TIdNotifyThreadComponentEvent;
  69. //
  70. function GetActive: Boolean;
  71. function GetData: TObject;
  72. function GetHandle: THandle;
  73. function GetPriority: TIdThreadPriority;
  74. function GetReturnValue: Integer;
  75. function GetStopMode: TIdThreadStopMode;
  76. function GetStopped: Boolean;
  77. function GetSuspended: Boolean;
  78. function GetTerminatingException: string;
  79. function GetTerminatingExceptionClass: TClass;
  80. function GetTerminated: Boolean;
  81. procedure Loaded; override;
  82. procedure SetActive(const AValue: Boolean); virtual;
  83. procedure SetData(const AValue: TObject);
  84. procedure SetOnTerminate(const AValue: TIdNotifyThreadComponentEvent);
  85. procedure SetPriority(const AValue: TIdThreadPriority);
  86. procedure SetReturnValue(const AValue: Integer);
  87. procedure SetStopMode(const AValue: TIdThreadStopMode);
  88. // event triggers
  89. procedure DoAfterExecute; virtual;
  90. procedure DoAfterRun; virtual;
  91. procedure DoBeforeExecute; virtual;
  92. procedure DoBeforeRun; virtual;
  93. procedure DoCleanup; virtual;
  94. procedure DoException(AThread: TIdThread; AException: Exception); virtual;
  95. procedure DoRun; virtual;
  96. procedure DoStopped(AThread: TIdThread); virtual;
  97. procedure DoTerminate(Sender: TObject); virtual;
  98. //
  99. property Active: Boolean read GetActive write SetActive default FALSE;
  100. property Priority: TIdThreadPriority read GetPriority write SetPriority;
  101. property StopMode: TIdThreadStopMode read GetStopMode write SetStopMode;
  102. //
  103. property OnAfterExecute: TIdNotifyThreadComponentEvent read FOnAfterExecute write FOnAfterExecute;
  104. property OnAfterRun: TIdNotifyThreadComponentEvent read FOnAfterRun write FOnAfterRun;
  105. property OnBeforeExecute: TIdNotifyThreadComponentEvent read FOnBeforeExecute write FOnBeforeExecute;
  106. property OnBeforeRun: TIdNotifyThreadComponentEvent read FOnBeforeRun write FOnBeforeRun;
  107. property OnCleanup: TIdNotifyThreadComponentEvent read FOnCleanup write FOnCleanup;
  108. property OnException: TIdExceptionThreadComponentEvent read FOnException write FOnException;
  109. property OnRun: TIdNotifyThreadComponentEvent read FOnRun write FOnRun;
  110. property OnStopped: TIdNotifyThreadComponentEvent read FOnStopped write FOnStopped;
  111. property OnTerminate: TIdNotifyThreadComponentEvent read FOnTerminate write SetOnTerminate;
  112. public
  113. constructor Create(AOwner: TComponent); override;
  114. destructor Destroy; override;
  115. procedure Start; virtual;
  116. procedure Stop; virtual;
  117. procedure Synchronize(AMethod: TThreadMethod); overload;
  118. procedure Synchronize(AMethod: TMethod); overload;
  119. procedure Terminate; virtual;
  120. procedure TerminateAndWaitFor; virtual;
  121. function WaitFor: LongWord;
  122. //
  123. property Data: TObject read GetData write SetData;
  124. property Handle: THandle read GetHandle;
  125. property ReturnValue: Integer read GetReturnValue write SetReturnValue;
  126. property Stopped: Boolean read GetStopped;
  127. property Suspended: Boolean read GetSuspended;
  128. property Thread: TIdThread read FThread;
  129. property TerminatingException: string read GetTerminatingException;
  130. property TerminatingExceptionClass: TClass read GetTerminatingExceptionClass;
  131. property Terminated: Boolean read GetTerminated;
  132. end;
  133. TIdThreadComponent = class(TIdCustomThreadComponent)
  134. published
  135. property Active;
  136. property Priority default IdThreadComponentDefaultPriority;
  137. property StopMode default IdThreadComponentDefaultStopMode;
  138. //
  139. property OnAfterExecute;
  140. property OnAfterRun;
  141. property OnBeforeExecute;
  142. property OnBeforeRun;
  143. property OnCleanup;
  144. property OnException;
  145. property OnRun;
  146. property OnStopped;
  147. property OnTerminate;
  148. end;
  149. //For Component-writers ONLY!
  150. TIdThreadEx = class(TIdThread)
  151. protected
  152. FThreadComponent: TIdCustomThreadComponent;
  153. //
  154. procedure AfterRun; override;
  155. procedure AfterExecute; override;
  156. procedure BeforeExecute; override;
  157. procedure BeforeRun; override;
  158. procedure Cleanup; override;
  159. procedure Run; override;
  160. public
  161. constructor Create(AThreadComponent: TIdCustomThreadComponent); reintroduce;
  162. end;
  163. implementation
  164. { TIdThreadEx }
  165. procedure TIdThreadEx.AfterExecute;
  166. begin
  167. try
  168. FThreadComponent.DoAfterExecute;
  169. finally
  170. FThreadComponent.FActive := FALSE;
  171. end;
  172. end;
  173. procedure TIdThreadEx.AfterRun;
  174. begin
  175. FThreadComponent.DoAfterRun;
  176. end;
  177. procedure TIdThreadEx.BeforeExecute;
  178. begin
  179. FThreadComponent.DoBeforeExecute;
  180. end;
  181. procedure TIdThreadEx.BeforeRun;
  182. begin
  183. FThreadComponent.DoBeforeRun;
  184. end;
  185. procedure TIdThreadEx.Cleanup;
  186. begin
  187. //don't free FData. Now Component is Data owner! inherited Cleanup;
  188. FThreadComponent.DoCleanup;
  189. end;
  190. constructor TIdThreadEx.Create(AThreadComponent: TIdCustomThreadComponent);
  191. begin
  192. inherited Create(True);
  193. FThreadComponent := AThreadComponent;
  194. FOnException := FThreadComponent.DoException;
  195. FOnStopped := FThreadComponent.DoStopped;
  196. end;
  197. procedure TIdThreadEx.Run;
  198. begin
  199. FThreadComponent.DoRun;
  200. end;
  201. { TIdCustomThreadComponent }
  202. procedure TIdCustomThreadComponent.DoAfterExecute;
  203. begin
  204. if Assigned(FOnAfterExecute) then FOnAfterExecute(Self);
  205. end;
  206. procedure TIdCustomThreadComponent.DoAfterRun;
  207. begin
  208. if Assigned(FOnAfterRun) then FOnAfterRun(Self);
  209. end;
  210. procedure TIdCustomThreadComponent.DoBeforeExecute;
  211. begin
  212. if Assigned(FOnBeforeExecute) then FOnBeforeExecute(Self);
  213. end;
  214. procedure TIdCustomThreadComponent.DoBeforeRun;
  215. begin
  216. if Assigned(FOnBeforeRun) then FOnBeforeRun(Self);
  217. end;
  218. procedure TIdCustomThreadComponent.DoCleanup;
  219. begin
  220. if Assigned(FOnCleanup) then FOnCleanup(Self);
  221. end;
  222. constructor TIdCustomThreadComponent.Create(AOwner: TComponent);
  223. begin
  224. inherited Create(AOwner);
  225. StopMode := IdThreadComponentDefaultStopMode;
  226. Priority := IdThreadComponentDefaultPriority;
  227. end;//TIdCustomThreadComponent.Create
  228. destructor TIdCustomThreadComponent.Destroy;
  229. begin
  230. {FThread.TerminateAndWaitFor;}
  231. //make sure thread is not active before we attempt to destroy it
  232. if Assigned(FThread) then begin
  233. FThread.Terminate;
  234. FThread.Start;//resume for terminate
  235. end;
  236. FreeAndNIL(FThread);
  237. inherited;
  238. end;
  239. procedure TIdCustomThreadComponent.DoException(AThread: TIdThread; AException: Exception);
  240. begin
  241. if Assigned(FOnException) then begin
  242. FOnException(Self, AException);
  243. end;
  244. end;
  245. procedure TIdCustomThreadComponent.DoStopped(AThread: TIdThread);
  246. begin
  247. if Assigned(FOnStopped) then begin
  248. FOnStopped(Self);
  249. end;
  250. end;
  251. procedure TIdCustomThreadComponent.DoTerminate;
  252. begin
  253. if Assigned(FOnTerminate) then begin
  254. FOnTerminate(Self);
  255. end;
  256. end;
  257. function TIdCustomThreadComponent.GetData: TObject;
  258. begin
  259. Result := FThread.Data;
  260. end;
  261. function TIdCustomThreadComponent.GetHandle: THandle;
  262. begin
  263. Result := GetThreadHandle(FThread);
  264. end;
  265. function TIdCustomThreadComponent.GetReturnValue: Integer;
  266. begin
  267. Result := FThread.ReturnValue;
  268. end;
  269. function TIdCustomThreadComponent.GetStopMode: TIdThreadStopMode;
  270. begin
  271. if FThread = NIL then begin
  272. Result := FStopMode;
  273. end
  274. else begin
  275. Result := FThread.StopMode;
  276. end;
  277. end;
  278. function TIdCustomThreadComponent.GetStopped: Boolean;
  279. begin
  280. Result := FThread.Stopped;
  281. end;
  282. function TIdCustomThreadComponent.GetSuspended: Boolean;
  283. begin
  284. Result := FThread.Suspended;
  285. end;
  286. function TIdCustomThreadComponent.GetTerminated: Boolean;
  287. begin
  288. Result := FThread.Terminated;
  289. end;
  290. function TIdCustomThreadComponent.GetTerminatingException: string;
  291. begin
  292. Result := FThread.TerminatingException;
  293. end;
  294. function TIdCustomThreadComponent.GetTerminatingExceptionClass: TClass;
  295. begin
  296. Result := FThread.TerminatingExceptionClass;
  297. end;
  298. procedure TIdCustomThreadComponent.Loaded;
  299. begin
  300. inherited;
  301. if FActive then begin
  302. FActive := False;
  303. Active := True;
  304. end;
  305. end;
  306. procedure TIdCustomThreadComponent.DoRun;
  307. begin
  308. if Assigned(FOnRun) then begin
  309. FOnRun(Self);
  310. end;
  311. end;
  312. procedure TIdCustomThreadComponent.SetActive(const AValue: Boolean);
  313. begin
  314. if not (csDesigning in ComponentState) then begin
  315. if FActive<>AValue then begin
  316. if AValue then begin
  317. Start;
  318. end else begin
  319. Stop;
  320. end;
  321. end;//if
  322. end;
  323. FActive:= AValue; //component load
  324. end;//SetActive
  325. procedure TIdCustomThreadComponent.SetData(const AValue: TObject);
  326. begin
  327. // this should not be accessed at design-time.
  328. FThread.Data := AValue;
  329. end;
  330. procedure TIdCustomThreadComponent.SetReturnValue(const AValue: Integer);
  331. begin
  332. // this should not be accessed at design-time.
  333. FThread.ReturnValue := AValue;
  334. end;
  335. procedure TIdCustomThreadComponent.SetStopMode(const AValue: TIdThreadStopMode);
  336. begin
  337. if Assigned(FThread) and not FThread.Terminated then begin
  338. FThread.StopMode := AValue;
  339. end;
  340. FStopMode := AValue;
  341. end;
  342. procedure TIdCustomThreadComponent.Start;
  343. begin
  344. if not (csDesigning in ComponentState) then begin
  345. if Assigned(FThread) and FThread.Terminated then begin
  346. FreeAndNIL(FThread);
  347. end;//if Thread is dead
  348. if FThread = nil then begin
  349. FThread := TIdThreadEx.Create(Self);
  350. end;
  351. with FThread do begin
  352. OnTerminate := DoTerminate;
  353. StopMode := FStopMode;
  354. Priority := FPriority;
  355. // Start it last after necessary settings are made
  356. Start;
  357. end;
  358. end;
  359. end;
  360. procedure TIdCustomThreadComponent.Stop;
  361. begin
  362. if Assigned(FThread) then begin
  363. FThread.Stop;
  364. end;
  365. end;
  366. procedure TIdCustomThreadComponent.Synchronize(AMethod: TThreadMethod);
  367. begin
  368. FThread.Synchronize(AMethod);
  369. end;
  370. procedure TIdCustomThreadComponent.Synchronize(AMethod: TMethod);
  371. begin
  372. FThread.Synchronize(AMethod);
  373. end;
  374. procedure TIdCustomThreadComponent.Terminate;
  375. begin
  376. FThread.Terminate;
  377. end;
  378. procedure TIdCustomThreadComponent.TerminateAndWaitFor;
  379. begin
  380. FThread.TerminateAndWaitFor;
  381. end;
  382. function TIdCustomThreadComponent.WaitFor: LongWord;
  383. begin
  384. Result := FThread.WaitFor;
  385. end;
  386. function TIdCustomThreadComponent.GetPriority: TIdThreadPriority;
  387. begin
  388. if csDesigning in ComponentState then begin
  389. Result := FPriority;
  390. end else begin
  391. Result := FThread.Priority;
  392. end;
  393. end;
  394. procedure TIdCustomThreadComponent.SetPriority(const AValue: TIdThreadPriority);
  395. begin
  396. if (FThread <> nil) and (FThread.Terminated = False) then begin
  397. FThread.Priority := AValue;
  398. end;
  399. FPriority := AValue;
  400. end;
  401. function TIdCustomThreadComponent.GetActive: Boolean;
  402. begin
  403. if csDesigning in ComponentState then begin
  404. Result := FActive;
  405. end else begin
  406. Result := not FThread.Stopped;
  407. end;
  408. end;
  409. procedure TIdCustomThreadComponent.SetOnTerminate(const AValue: TIdNotifyThreadComponentEvent);
  410. begin
  411. FOnTerminate := AValue;
  412. if FThread <> nil then begin
  413. if Assigned(AValue) then begin
  414. FThread.OnTerminate := DoTerminate;
  415. end else begin
  416. FThread.OnTerminate := nil;
  417. end;
  418. end;
  419. end;
  420. end.