Author: Peter Below
How to create a thread-safe wrapper class for TCustomIniFile descendents
Answer:
{Unit ThreadSafeWrapperU:
Declares and implements a simple thread-safe wrapper class as base class
for classes that need to serialize access to some internal object.
Author Dr. Peter Below
Version 1.0 created 18 Oktober 2000
Current revision: 1.0
Last modified: 18 Oktober 2000
Last review: 18.04.2001}
1 unit ThreadSafeWrapperU;
2
3 interface
4
5 uses SyncObjs;
6
7 type
8
9 {This is a class from which classes wrapping some data object in a thread-safe
10 manner can be derived. The derived class should add a public
11 Function Lock: Sometype;
12 that calls InternalLock and then returns a reference for the protected object (kept
13 in a private field ).
14 Access to the protected object will typically take the form
15
16 with wrapper.lock do
17 try
18 stuff
19 finally
20 wrapper.Unlock;
21 end;}
22
23 TThreadSafeWrapper = class
24 private
25 FGuardian: TCriticalSection;
26 protected
27 {Enter the critical section}
28 procedure InternalLock;
29 public
30 {Create the critical section}
31 constructor Create; virtual;
32 {Destroy the critical section}
33 destructor Destroy; override;
34 {Leave the critical section}
35 procedure Unlock;
36 end;
37
38 implementation
39
40 constructor TThreadSafeWrapper.Create;
41 begin
42 FGuardian := TCriticalSection.Create;
43 inherited;
44 end;
45
46 destructor TThreadSafeWrapper.Destroy;
47 begin
48 FGuardian.Free;
49 inherited;
50 end;
51
52 procedure TThreadSafeWrapper.InternalLock;
53 begin
54 FGuardian.Acquire;
55 end;
56
57 procedure TThreadSafeWrapper.Unlock;
58 begin
59 FGuardian.Release;
60 end;
61
62 end.
63
64 {ThreadSafeInifileU:
65 Implements a thread-safe wrapper class for TCustomInifile descendents.
66
67 Author Dr. Peter Below
68 Version 1.0 created 24.12.2000
69 Version 1.01 created 25.04.2001, added most of the public inifile methods to wrap
70 access to the internal inifile
71 Current revision: 1.01
72 Last modified: 24.12.2000
73 Last review: 25.04.2001}
74
75 unit ThreadSafeInifileU;
76
77 interface
78
79 uses
80 Windows, Classes, ThreadSafeWrapperU, Inifiles;
81
82 type
83 {Enumerated type for TCustomInifile descendents to use}
84 TIniType = (itRegistryInifile, itInifile, itMemInifile);
85
86 {A thread-safe inifile class. The default inifile class used if none is specified
87 in
88 the constructor is TRegistryInifile}
89 TThreadsafeInifile = class(TThreadSafeWrapper)
90 private
91 FIni: TCustomInifile;
92 public
93 constructor Create(aFilename: string; aClass: TIniType = itRegistryInifile;
94 aAccess: LongWord = KEY_READ or KEY_WRITE); reintroduce;
95 destructor Destroy; override;
96 function Lock: TCustomInifile;
97 function SectionExists(const Section: string): Boolean;
98 function ReadString(const Section, Ident, default: string): string;
99 procedure WriteString(const Section, Ident, Value: string);
100 function ReadInteger(const Section, Ident: string; default: Longint): Longint;
101 procedure WriteInteger(const Section, Ident: string; Value: Longint);
102 function ReadBool(const Section, Ident: string; default: Boolean): Boolean;
103 procedure WriteBool(const Section, Ident: string; Value: Boolean);
104 function ReadDate(const Section, Ident: string; default: TDateTime): TDateTime;
105 function ReadDateTime(const Section, Ident: string; default: TDateTime):
106 TDateTime;
107 function ReadFloat(const Section, Ident: string; default: Double): Double;
108 function ReadTime(const Section, Ident: string; default: TDateTime): TDateTime;
109 procedure WriteDate(const Section, Ident: string; Value: TDateTime);
110 procedure WriteDateTime(const Section, Ident: string; Value: TDateTime);
111 procedure WriteFloat(const Section, Ident: string; Value: Double);
112 procedure WriteTime(const Section, Ident: string; Value: TDateTime);
113 procedure ReadSection(const Section: string; Strings: TStrings);
114 procedure ReadSections(Strings: TStrings);
115 procedure ReadSectionValues(const Section: string; Strings: TStrings);
116 procedure EraseSection(const Section: string);
117 procedure DeleteKey(const Section, Ident: string);
118 function ValueExists(const Section, Ident: string): Boolean;
119 end;
120
121 implementation
122
123 uses
124 Registry;
125
126 {TThreadsafeInifile.Create:
127 Create the custom ini file descendent.
128
129 Parameters:
130 aFilename: The name to use.
131 aClass: Defines the class to use.
132 aAccess: The desired access if aclass is itRegistryInifile.
133
134 We have a slight problem here since TCustomInifile.Create is not a virtual
135 constructor.
136 So we need a somewhat cumbersome Case construct to create the correct class of
137 TCustomInifile descendent.
138
139 Created 24.12.2000 by P. Below}
140
141 constructor TThreadsafeInifile.Create(aFilename: string; aClass: TIniType =
142 itRegistryInifile;
143 aAccess: DWord = KEY_READ or KEY_WRITE);
144 begin
145 inherited Create;
146 case aClass of
147 itRegistryInifile:
148 FIni := TRegistryInifile.Create(aFilename, aAccess);
149 itInifile:
150 FIni := TInifile.Create(aFilename);
151 itMemInifile:
152 FIni := TMemInifile.Create(aFilename);
153 end;
154 end;
155
156 {TThreadsafeInifile.Destroy:
157 Destroy the internal inifile object.
158
159 Created 24.12.2000 by P. Below}
160
161 destructor TThreadsafeInifile.Destroy;
162 begin
163 FIni.Free;
164 inherited;
165 end;
166
167 {TThreadsafeInifile.Lock:
168 Aquire access to the ini file and return its reference. Must be paired with an
169 Unlock call!
170
171 Created 24.12.2000 by P. Below}
172
173 function TThreadsafeInifile.Lock: TCustomInifile;
174 begin
175 InternalLock;
176 Result := FIni;
177 end;
178
179 function TThreadsafeInifile.SectionExists(const Section: string): Boolean;
180 begin
181 InternalLock;
182 try
183 Result := FIni.SectionExists(Section);
184 finally
185 Unlock;
186 end;
187 end;
188
189 function TThreadsafeInifile.ReadString(const Section, Ident, default: string):
190 string;
191 begin
192 InternalLock;
193 try
194 Result := FIni.ReadString(Section, Ident, default);
195 finally
196 Unlock;
197 end;
198 end;
199
200 procedure TThreadsafeInifile.WriteString(const Section, Ident, Value: string);
201 begin
202 InternalLock;
203 try
204 FIni.WriteString(Section, Ident, Value);
205 finally
206 Unlock;
207 end;
208 end;
209
210 function TThreadsafeInifile.ReadInteger(const Section, Ident: string; default:
211 Longint): Longint;
212 begin
213 InternalLock;
214 try
215 Result := FIni.ReadInteger(Section, Ident, default);
216 finally
217 Unlock;
218 end;
219 end;
220
221 procedure TThreadsafeInifile.WriteInteger(const Section, Ident: string; Value:
222 Longint);
223 begin
224 InternalLock;
225 try
226 FIni.WriteInteger(Section, Ident, Value);
227 finally
228 Unlock;
229 end;
230 end;
231
232 function TThreadsafeInifile.ReadBool(const Section, Ident: string; default:
233 Boolean):
234 Boolean;
235 begin
236 InternalLock;
237 try
238 Result := FIni.ReadBool(Section, Ident, default);
239 finally
240 Unlock;
241 end;
242 end;
243
244 procedure TThreadsafeInifile.WriteBool(const Section, Ident: string; Value:
245 Boolean);
246 begin
247 InternalLock;
248 try
249 FIni.WriteBool(Section, Ident, Value);
250 finally
251 Unlock;
252 end;
253 end;
254
255 function TThreadsafeInifile.ReadDate(const Section, Ident: string; default:
256 TDateTime): TDateTime;
257 begin
258 InternalLock;
259 try
260 Result := FIni.ReadDate(Section, Ident, default);
261 finally
262 Unlock;
263 end;
264 end;
265
266 function TThreadsafeInifile.ReadDateTime(const Section, Ident: string;
267 default: TDateTime): TDateTime;
268 begin
269 InternalLock;
270 try
271 Result := FIni.ReadDatetime(Section, Ident, default);
272 finally
273 Unlock;
274 end;
275 end;
276
277 function TThreadsafeInifile.ReadFloat(const Section, Ident: string; default:
278 Double):
279 Double;
280 begin
281 InternalLock;
282 try
283 Result := FIni.ReadFloat(Section, Ident, default);
284 finally
285 Unlock;
286 end;
287 end;
288
289 function TThreadsafeInifile.ReadTime(const Section, Ident: string; default:
290 TDateTime): TDateTime;
291 begin
292 InternalLock;
293 try
294 Result := FIni.ReadTime(Section, Ident, default);
295 finally
296 Unlock;
297 end;
298 end;
299
300 procedure TThreadsafeInifile.WriteDate(const Section, Ident: string; Value:
301 TDateTime);
302 begin
303 InternalLock;
304 try
305 FIni.WriteDate(Section, Ident, Value);
306 finally
307 Unlock;
308 end;
309 end;
310
311 procedure TThreadsafeInifile.WriteDateTime(const Section, Ident: string; Value:
312 TDateTime);
313 begin
314 InternalLock;
315 try
316 FIni.WriteDatetime(Section, Ident, Value);
317 finally
318 Unlock;
319 end;
320 end;
321
322 procedure TThreadsafeInifile.WriteFloat(const Section, Ident: string; Value:
323 Double);
324 begin
325 InternalLock;
326 try
327 FIni.WriteFloat(Section, Ident, Value);
328 finally
329 Unlock;
330 end;
331 end;
332
333 procedure TThreadsafeInifile.WriteTime(const Section, Ident: string; Value:
334 TDateTime);
335 begin
336 InternalLock;
337 try
338 FIni.WriteTime(Section, Ident, Value);
339 finally
340 Unlock;
341 end;
342 end;
343
344 procedure TThreadsafeInifile.ReadSection(const Section: string; Strings: TStrings);
345 begin
346 InternalLock;
347 try
348 FIni.ReadSection(Section, Strings);
349 finally
350 Unlock;
351 end;
352 end;
353
354 procedure TThreadsafeInifile.ReadSections(Strings: TStrings);
355 begin
356 InternalLock;
357 try
358 FIni.ReadSections(Strings);
359 finally
360 Unlock;
361 end;
362 end;
363
364 procedure TThreadsafeInifile.ReadSectionValues(const Section: string; Strings:
365 TStrings);
366 begin
367 InternalLock;
368 try
369 FIni.ReadSectionValues(Section, Strings);
370 finally
371 Unlock;
372 end;
373 end;
374
375 procedure TThreadsafeInifile.EraseSection(const Section: string);
376 begin
377 InternalLock;
378 try
379 FIni.EraseSection(Section);
380 finally
381 Unlock;
382 end;
383 end;
384
385 procedure TThreadsafeInifile.DeleteKey(const Section, Ident: string);
386 begin
387 InternalLock;
388 try
389 FIni.DeleteKey(Section, Ident);
390 finally
391 Unlock;
392 end;
393 end;
394
395 function TThreadsafeInifile.ValueExists(const Section, Ident: string): Boolean;
396 begin
397 InternalLock;
398 try
399 Result := FIni.ValueExists(Section, Ident);
400 finally
401 Unlock;
402 end;
403 end;
404
405 end.
|