Create a thread-safe wrapper class for TCustomIniFile descendents (Views: 32)
Problem/Question/Abstract: 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} unit ThreadSafeWrapperU; interface uses SyncObjs; type {This is a class from which classes wrapping some data object in a thread-safe manner can be derived. The derived class should add a public Function Lock: Sometype; that calls InternalLock and then returns a reference for the protected object (kept in a private field ). Access to the protected object will typically take the form with wrapper.lock do try stuff finally wrapper.Unlock; end;} TThreadSafeWrapper = class private FGuardian: TCriticalSection; protected {Enter the critical section} procedure InternalLock; public {Create the critical section} constructor Create; virtual; {Destroy the critical section} destructor Destroy; override; {Leave the critical section} procedure Unlock; end; implementation constructor TThreadSafeWrapper.Create; begin FGuardian := TCriticalSection.Create; inherited; end; destructor TThreadSafeWrapper.Destroy; begin FGuardian.Free; inherited; end; procedure TThreadSafeWrapper.InternalLock; begin FGuardian.Acquire; end; procedure TThreadSafeWrapper.Unlock; begin FGuardian.Release; end; end. {ThreadSafeInifileU: Implements a thread-safe wrapper class for TCustomInifile descendents. Author Dr. Peter Below Version 1.0 created 24.12.2000 Version 1.01 created 25.04.2001, added most of the public inifile methods to wrap access to the internal inifile Current revision: 1.01 Last modified: 24.12.2000 Last review: 25.04.2001} unit ThreadSafeInifileU; interface uses Windows, Classes, ThreadSafeWrapperU, Inifiles; type {Enumerated type for TCustomInifile descendents to use} TIniType = (itRegistryInifile, itInifile, itMemInifile); {A thread-safe inifile class. The default inifile class used if none is specified in the constructor is TRegistryInifile} TThreadsafeInifile = class(TThreadSafeWrapper) private FIni: TCustomInifile; public constructor Create(aFilename: string; aClass: TIniType = itRegistryInifile; aAccess: LongWord = KEY_READ or KEY_WRITE); reintroduce; destructor Destroy; override; function Lock: TCustomInifile; function SectionExists(const Section: string): Boolean; function ReadString(const Section, Ident, Default: string): string; procedure WriteString(const Section, Ident, Value: string); function ReadInteger(const Section, Ident: string; Default: Longint): Longint; procedure WriteInteger(const Section, Ident: string; Value: Longint); function ReadBool(const Section, Ident: string; Default: Boolean): Boolean; procedure WriteBool(const Section, Ident: string; Value: Boolean); function ReadDate(const Section, Ident: string; Default: TDateTime): TDateTime; function ReadDateTime(const Section, Ident: string; Default: TDateTime): TDateTime; function ReadFloat(const Section, Ident: string; Default: Double): Double; function ReadTime(const Section, Ident: string; Default: TDateTime): TDateTime; procedure WriteDate(const Section, Ident: string; Value: TDateTime); procedure WriteDateTime(const Section, Ident: string; Value: TDateTime); procedure WriteFloat(const Section, Ident: string; Value: Double); procedure WriteTime(const Section, Ident: string; Value: TDateTime); procedure ReadSection(const Section: string; Strings: TStrings); procedure ReadSections(Strings: TStrings); procedure ReadSectionValues(const Section: string; Strings: TStrings); procedure EraseSection(const Section: string); procedure DeleteKey(const Section, Ident: string); function ValueExists(const Section, Ident: string): Boolean; end; implementation uses Registry; {TThreadsafeInifile.Create: Create the custom ini file descendent. Parameters: aFilename: The name to use. aClass: Defines the class to use. aAccess: The desired access if aclass is itRegistryInifile. We have a slight problem here since TCustomInifile.Create is not a virtual constructor. So we need a somewhat cumbersome Case construct to create the correct class of TCustomInifile descendent. Created 24.12.2000 by P. Below} constructor TThreadsafeInifile.Create(aFilename: string; aClass: TIniType = itRegistryInifile; aAccess: DWord = KEY_READ or KEY_WRITE); begin inherited Create; case aClass of itRegistryInifile: FIni := TRegistryInifile.Create(aFilename, aAccess); itInifile: FIni := TInifile.Create(aFilename); itMemInifile: FIni := TMemInifile.Create(aFilename); end; end; {TThreadsafeInifile.Destroy: Destroy the internal inifile object. Created 24.12.2000 by P. Below} destructor TThreadsafeInifile.Destroy; begin FIni.Free; inherited; end; {TThreadsafeInifile.Lock: Aquire access to the ini file and return its reference. Must be paired with an Unlock call! Created 24.12.2000 by P. Below} function TThreadsafeInifile.Lock: TCustomInifile; begin InternalLock; Result := FIni; end; function TThreadsafeInifile.SectionExists(const Section: string): Boolean; begin InternalLock; try Result := FIni.SectionExists(Section); finally Unlock; end; end; function TThreadsafeInifile.ReadString(const Section, Ident, Default: string): string; begin InternalLock; try Result := FIni.ReadString(Section, Ident, Default); finally Unlock; end; end; procedure TThreadsafeInifile.WriteString(const Section, Ident, Value: string); begin InternalLock; try FIni.WriteString(Section, Ident, Value); finally Unlock; end; end; function TThreadsafeInifile.ReadInteger(const Section, Ident: string; Default: Longint): Longint; begin InternalLock; try Result := FIni.ReadInteger(Section, Ident, Default); finally Unlock; end; end; procedure TThreadsafeInifile.WriteInteger(const Section, Ident: string; Value: Longint); begin InternalLock; try FIni.WriteInteger(Section, Ident, Value); finally Unlock; end; end; function TThreadsafeInifile.ReadBool(const Section, Ident: string; Default: Boolean): Boolean; begin InternalLock; try Result := FIni.ReadBool(Section, Ident, Default); finally Unlock; end; end; procedure TThreadsafeInifile.WriteBool(const Section, Ident: string; Value: Boolean); begin InternalLock; try FIni.WriteBool(Section, Ident, Value); finally Unlock; end; end; function TThreadsafeInifile.ReadDate(const Section, Ident: string; Default: TDateTime): TDateTime; begin InternalLock; try Result := FIni.ReadDate(Section, Ident, Default); finally Unlock; end; end; function TThreadsafeInifile.ReadDateTime(const Section, Ident: string; Default: TDateTime): TDateTime; begin InternalLock; try Result := FIni.ReadDatetime(Section, Ident, Default); finally Unlock; end; end; function TThreadsafeInifile.ReadFloat(const Section, Ident: string; Default: Double): Double; begin InternalLock; try Result := FIni.ReadFloat(Section, Ident, Default); finally Unlock; end; end; function TThreadsafeInifile.ReadTime(const Section, Ident: string; Default: TDateTime): TDateTime; begin InternalLock; try Result := FIni.ReadTime(Section, Ident, Default); finally Unlock; end; end; procedure TThreadsafeInifile.WriteDate(const Section, Ident: string; Value: TDateTime); begin InternalLock; try FIni.WriteDate(Section, Ident, Value); finally Unlock; end; end; procedure TThreadsafeInifile.WriteDateTime(const Section, Ident: string; Value: TDateTime); begin InternalLock; try FIni.WriteDatetime(Section, Ident, Value); finally Unlock; end; end; procedure TThreadsafeInifile.WriteFloat(const Section, Ident: string; Value: Double); begin InternalLock; try FIni.WriteFloat(Section, Ident, Value); finally Unlock; end; end; procedure TThreadsafeInifile.WriteTime(const Section, Ident: string; Value: TDateTime); begin InternalLock; try FIni.WriteTime(Section, Ident, Value); finally Unlock; end; end; procedure TThreadsafeInifile.ReadSection(const Section: string; Strings: TStrings); begin InternalLock; try FIni.ReadSection(Section, Strings); finally Unlock; end; end; procedure TThreadsafeInifile.ReadSections(Strings: TStrings); begin InternalLock; try FIni.ReadSections(Strings); finally Unlock; end; end; procedure TThreadsafeInifile.ReadSectionValues(const Section: string; Strings: TStrings); begin InternalLock; try FIni.ReadSectionValues(Section, Strings); finally Unlock; end; end; procedure TThreadsafeInifile.EraseSection(const Section: string); begin InternalLock; try FIni.EraseSection(Section); finally Unlock; end; end; procedure TThreadsafeInifile.DeleteKey(const Section, Ident: string); begin InternalLock; try FIni.DeleteKey(Section, Ident); finally Unlock; end; end; function TThreadsafeInifile.ValueExists(const Section, Ident: string): Boolean; begin InternalLock; try Result := FIni.ValueExists(Section, Ident); finally Unlock; end; end; end. |