Many applications use ini files to store configuration information. BaseCLX includes two classes for working with ini files: TIniFile and TMemIniFile. Using ini files has the advantage that they can be used in cross-platform applications and they are easy to read and edit.
Many Windows applications replace the use of ini files with the system Registry. The Windows system Registry is a hierarchical database that acts as a centralized storage space for configuration information. The VCL includes classes for working with the system Registry.
While these are technically not part of BaseCLX (because they are only available on Windows), two of these classes, TRegistryIniFile and TRegistry, are discussed here because of their similarity to the classes for working with ini files.
TRegistryIniFile is useful for cross-platform applications, because it shares a common ancestor (TCustomIniFile) with the classes that work with ini files. If you confine yourself to the methods of the common ancestor (TCustomIniFile) your application can work on both applications with a minimum of conditional code.
For applications that are not cross-platform, you can use the TRegistry class. The properties and methods of TRegistry have names that correspond more directly to the way the system Registry is organized, because it does not need to be compatible with the classes for ini files.
Using TIniFile and TMemIniFile The ini file format is still popular, many configuration files (such as the DSK Desktop settings file) are in this format. This format is especially useful in cross-platform applications, where you can’t always count on a system Registry for storing configuration information.
BaseCLX provides two classes, TIniFile and TMemIniFile, to make reading and writing ini files very easy. TIniFile works directly with the ini file on disk while TMemIniFile buffers all changes in memory and does not write them to disk until you call the UpdateFile method.
When you instantiate the TIniFile or TMemIniFile object, you pass the name of the ini file as a parameter to the constructor. If the file does not exist, it is automatically created. You are then free to read values using the various read methods, such as ReadString, ReadDate, ReadInteger, or ReadBool.
Alternatively, if you want to read an entire section of the ini file, you can use the ReadSection method. Similarly, you can write values using methods such as WriteBool, WriteInteger, WriteDate, or WriteString.
Following is an example of reading configuration information from an ini file in a form's OnCreate event handler and writing values in the OnClose event handler.
procedure TForm1.FormCreate(Sender: TObject); var Ini: TIniFile; begin Ini := TIniFile.Create( ChangeFileExt( Application.ExeName, '.INI' ) ); try Top := Ini.ReadInteger( 'Form', 'Top', 100 ); Left := Ini.ReadInteger( 'Form', 'Left', 100 ); Caption := Ini.ReadString( 'Form', 'Caption', 'New Form' ); if Ini.ReadBool( 'Form', 'InitMax', false ) then WindowState = wsMaximized else WindowState = wsNormal; finally TIniFile.Free; end; end;
procedure TForm1.FormClose(Sender: TObject; var Action TCloseAction) var Ini: TIniFile; begin Ini := TIniFile.Create( ChangeFileExt( Application.ExeName, '.INI' ) ); try Ini.WriteInteger( 'Form', 'Top', Top); Ini.WriteInteger( 'Form', 'Left', Left); Ini.WriteString( 'Form', 'Caption', Caption ); Ini.WriteBool( 'Form', 'InitMax', WindowState = wsMaximized ); finally TIniFile.Free; end; end;
Each of the Read routines takes three parameters. The first parameter identifies the section of the ini file. The second parameter identifies the value you want to read, and the third is a default value in case the section or value doesn't exist in the ini file.
Just as the Read methods gracefully handle the case when a section or value does not exist, the Write routines create the section and/or value if they do not exist. The example code creates an ini file the first time it is run that looks like this:
[Form] Top=100 Left=100 Caption=Default Caption InitMax=0
On subsequent execution of this application, the ini values are read in when the form is created and written back out in the OnClose event.
Many 32-bit Windows applications store their information in the system Registry instead of ini files because the Registry is hierarchical and doesn't suffer from the size limitations of ini files. If you are accustomed to using ini files and want to move your configuration information to the Registry instead, you can use the TRegistryIniFile class.
You may also want to use TRegistryIniFile in cross-platform applications if you want to use the system Registry on Windows and an ini file on Linux. You can write most of your application so that it uses the TCustomIniFile type.
You need only conditionalize the code that creates an instance of TRegistryIniFile (on Windows) or TMemIniFile (on Linux) and assigns it to the TCustomIniFile your application uses. TRegistryIniFile makes Registry entries look like ini file entries. All the methods from TIniFile and TMemIniFile (read and write) exist in TRegistryIniFile.
When you construct a TRegistryIniFile object, the parameter you pass to the constructor (corresponding to the filename for an IniFile or TMemIniFile object) becomes a key value under the user key in the registry.
All sections and values branch from that root. TRegistryIniFile simplifies the Registry interface considerably, so you may want to use it instead of the TRegistry component even if you aren't porting existing code or writing a cross-platform application.
If you are writing a Windows-only application and are comfortable with the structure of the system Registry, you can use TRegistry. Unlike TRegistryIniFile, which uses the same properties and methods of other ini file components, the properties and methods of TRegistry correspond more directly to the structure of the system Registry.
For example, TRegistry lets you specify both the root key and subkey, while TRegistryIniFile assumes HKEY_CURRENT_USER as a root key. In addition to methods for opening, closing, saving, moving, copying, and deleting keys, TRegistry lets you specify the access level you want to use.