-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathThdtimer.pas
177 lines (148 loc) · 4.23 KB
/
Thdtimer.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
////////////////////////////////////////////////////
// //
// ThreadedTimer 1.2a //
// //
// Copyright (C) 1996, 2000 Carlos Barbosa //
// email: [email protected] //
// Home Page: http://www.carlosb.com //
// //
// Portions (C) 2000, Andrew N. Driazgov //
// email: [email protected] //
// //
// Last updated: November 24, 2000 //
// //
////////////////////////////////////////////////////
unit ThdTimer;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
const
DEFAULT_INTERVAL = 1000;
type
TThreadedTimer = class;
TTimerThread = class(TThread)
private
FOwner: TThreadedTimer;
FInterval: Cardinal;
FStop: THandle;
protected
procedure Execute; override;
end;
TThreadedTimer = class(TComponent)
private
FOnTimer: TNotifyEvent;
FTimerThread: TTimerThread;
FEnabled,
FAllowZero: Boolean;
procedure DoTimer;
procedure SetEnabled(Value: Boolean);
function GetInterval: Cardinal;
procedure SetInterval(Value: Cardinal);
function GetThreadPriority: TThreadPriority;
procedure SetThreadPriority(Value: TThreadPriority);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property AllowZero: Boolean read FAllowZero write FAllowZero default False;
property Enabled: Boolean read FEnabled write SetEnabled default False;
property Interval: Cardinal read GetInterval write SetInterval default DEFAULT_INTERVAL;
property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
property ThreadPriority: TThreadPriority read GetThreadPriority write SetThreadPriority default tpNormal;
end;
procedure Register;
implementation
{ TTimerThread }
procedure TTimerThread.Execute;
begin
repeat
if WaitForSingleObject(FStop, FInterval) = WAIT_TIMEOUT then
Synchronize(FOwner.DoTimer);
until Terminated;
end;
{ TThreadedTimer }
constructor TThreadedTimer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FTimerThread := TTimerThread.Create(True);
with FTimerThread do
begin
FOwner := Self;
FInterval := DEFAULT_INTERVAL;
Priority := tpNormal;
// Event is completely manipulated by TThreadedTimer object
FStop := CreateEvent(nil, False, False, nil);
end;
end;
destructor TThreadedTimer.Destroy;
begin
with FTimerThread do
begin
Terminate;
// When this method is called we must be confident that the event handle was not closed
SetEvent(FStop);
if Suspended then
Resume;
WaitFor;
CloseHandle(FStop); // Close event handle in the primary thread
Free;
end;
inherited Destroy;
end;
procedure TThreadedTimer.DoTimer;
begin
// We have to check FEnabled in the primary thread
// Otherwise we get AV when the program is closed
if FEnabled and Assigned(FOnTimer) then
try
FOnTimer(Self);
except
end;
end;
procedure TThreadedTimer.SetEnabled(Value: Boolean);
begin
if Value <> FEnabled then
begin
FEnabled := Value;
if FEnabled then
begin
if (FTimerThread.FInterval > 0) or
((FTimerThread.FInterval = 0) and FAllowZero) then
begin
SetEvent(FTimerThread.FStop);
FTimerThread.Resume;
end;
end
else
FTimerThread.Suspend;
end;
end;
function TThreadedTimer.GetInterval: Cardinal;
begin
Result := FTimerThread.FInterval;
end;
procedure TThreadedTimer.SetInterval(Value: Cardinal);
var
PrevEnabled: Boolean;
begin
if Value <> FTimerThread.FInterval then
begin
PrevEnabled := FEnabled;
Enabled := False;
FTimerThread.FInterval := Value;
Enabled := PrevEnabled;
end;
end;
function TThreadedTimer.GetThreadPriority: TThreadPriority;
begin
Result := FTimerThread.Priority;
end;
procedure TThreadedTimer.SetThreadPriority(Value: TThreadPriority);
begin
FTimerThread.Priority := Value;
end;
procedure Register;
begin
RegisterComponents('System', [TThreadedTimer]);
end;
end.