Author: Teun Spaans
What is the structure of the registry?
What settings to store in the registry, how to do so?
This article is the third article in a series of four articles about personal
settings. This article deals with the usage of the registry for retaining personal
settings. It explains the working of the registry, how to read & write date in the
registry from Delphi, and contains an example: a form which reads its previous
position on the screen.
One thing every application i.m.h.o. should contain is a registration in the
registry -the registry should have a clue in which directory your application has
been stored. You may choose to have this handled by your installtion program, which
is a logical place to do so. But the program can also do it itself, so that the
user moving the directory with your application from the windows explorer can fix
its own settings by simply starting your program.
The registry - its structure
The registry was introduced by Microsoft with Windows 95. In Windows 95 and Windows
98, there are 2 files in your windows directory called user.dat and system.dat
which contain the data in your registry. However, in all cases Microsoft provides a
utility regedit to browse and change the registry.
When you use this tool to open your registry, you will see 5 base keys:
These five keys are identical in all window versions. Each one has many subkeys,
which in turn have subkeys again. The registry has a strict hierarchical structure.
For our purpose only 2 of them are interesting: HKEY_CURRENT_USER and
HKEY_LOCAL_MACHINE. The first is, as the name suggests, user dependant, the second
is applicable to all the machine. You might think this key contains just hardware
related data, but it has a subkey for software as well. The local machine root is a
good choice for items applicable to all users.
The reading of data from the registry is illustrated with an example. We will
cerate a new form which will remember its previous location on the screen. The
location is determined by the Top and Left properties of the form. In addition to
these, we will read and store the Height and Width properties of the form.
3 cKey = 'SOFTWARE\Test_Company\Test_Application';
4 // key where item values will be stored and read
6 procedure TRememberForm.FormCreate(Sender:
9 lReg: TRegistry;
10 getInt: integer;
13 // general purpose:
14 // read latest Left, Top, Width and Height
15 lReg := TRegistry.Create;
16 // create registry object
17 lReg.RootKey := HKEY_CURRENT_USER;
18 // set root to current user root,
19 // to ensure different users on this
20 // machine have their own setting
21 lReg.OpenKey(cKey, True);
22 // Open key where we will read items
23 if lReg.ValueExists(self.name +
24 '.Left') then // check if
25 value for item formname.left exists
27 getint := lReg.ReadInteger(self.name
28 + '.Left'); // Read left position of actual form
29 if getint > 0 then
30 self.Left := getint;
32 if lReg.ValueExists(self.name +
33 '.Top') then
35 getint := lReg.ReadInteger(self.name + '.Top');
36 if getint > 0 then
37 self.Top := getint;
39 if lReg.ValueExists(self.name + '.Width') then
41 getint := lReg.ReadInteger(self.name + '.Width');
42 if getint > 0 then
43 self.Width := getint;
45 if lReg.ValueExists(self.name + '.Height') then
47 getint := lReg.ReadInteger(self.name + '.Height');
48 if getint > 0 then
49 self.Height := getint;
51 // Close and free
56 //Let's have a short look at the main points:
58 lReg := TRegistry.Create;
59 // create registry object
61 //This line creates the Registry object.
63 lReg.RootKey := HKEY_CURRENT_USER;
64 // set root to current user root,
65 // to ensure different users on this
66 // machine have their own setting
We set the root to indicate in which of the 5 roots we want to work.
HKEY_CURRENT_USER is the default value. Alternately, we might have chosen
HKEY_LOCAL_MACHINE if we wanted to save settings for all users on this machine.
67 lReg.OpenKey(cKey, True);
68 // Open key where we will read items
The key where items will be stored and read is opened. If the key does not exist,
windows automatically creates it. Note that capitalization is important when the
registry key is created. Most entries in the registry have first letter uppercase
and the rest lowercase, and it is good practice to comply.
69 if lReg.ValueExists(self.name + '.Left') then
70 // check if value for item formname. left exists
This statement tests if the item FormName.left exists within the open key.
72 getint := lReg.ReadInteger(self.name
73 + '.Left'); // Read left position of actual form
As an alternative for ReadInteger, the TRegistry object also provides functions to
read strings, booleans, dates, datetimes, times, floats, and binary data.
74 if getint > 0 then
75 self.Left := getint;
By putting all these code in the FormCreate, the window is automatically positioned
at the right spot at creation. Of course the code above can not be really tested
when we don't have any data, so the next step is to write these items in the
The FormDestroy event is a good moment to write the data to the registry. The code
is a lot shorter:
78 procedure TRememberForm.FormDestroy(Sender: TObject);
80 lReg: TRegistry;
82 // open registry, set root and key
83 lReg := TRegistry.Create;
84 lReg.RootKey := HKEY_CURRENT_USER;
85 lReg.OpenKey(cKey, True);
86 // write last Left, Top, Width and Height
87 lReg.WriteInteger(self.name + '.Left', self.Left);
88 lReg.WriteInteger(self.name + '.Top', self.Top);
89 lReg.WriteInteger(self.name + '.Width', self.Width);
90 lReg.WriteInteger(self.name + '.Height', self.Height);
91 // close all
As with reading data, the same applies with writing data. You can easily write
booleans, currencies, dates, datetimes, floats, strings and times, and binary data.
In addition, there is a WriteExpandString, which is meant for unexpanded strings
with "%" in it, such as "Open file %s failed".
WriteInteger creates a name when the name does not yet exist. If a write operation
fails, an exception is raised.
There are 2 other objects, TRegIniFile and TRegistryInifile available.
TRegistryIniFile presents a simple interface to the system registry and hides the
need to know about the underlying structure of the registry. TRegistryIniFile
enables handling the Windows system registry as if it were a Windows 3.x INI file.
Instead of processing an INI file, however, TRegistryIniFile reads from and writes
to the system registry.
TRegIniFile presents a simple interface to the system registry, hiding the need to
know about the underlying structure of the registry. TRegIniFile acts as a helper
object to TRegistryIniFile.
Personally I avoid using these 2 classes. The programmer saves some time by not
having to understand the registry. But the structure of the registry is rather
straightforward hierarchical, and using the registry as if it was an ini-file
limits its usage.
Limitations and final words
There are a few limitations which we haven't discussed. First, The registry is not
meant a a database for storing vast quantities of data. It is meant for storing
initialization and configuration data. Anything over 2Kb had better be stored in a
separate file. If you wish, you can mention the corresponding file location in the
registry. Then WriteBinary is especially useful for storing recordtypes. Using a
record type saves you typing code, and it can be written to and read from the
registry with 1 statement, saving both time and storage. And a large registry might
slow down all applications.
There is a small bug in the MoveKey procedure under WNT. It should move a key
including Subkeys, but it does not, at least not in D2-4. In the help of Delphi 5
this problem has been documented. The problem does not seem to appear under W2K.
Third, it seems Windows NT & Windows 2000 administrators can limit Registry access.
Using the registry may conflict with IT-policies in some companies.
Should you like the form we created, right click on the form and choose 'add to
repository'. You can then create descendants by choosing File / New / forms.
Component Download: http://www.xs4all.nl/~spaanszt/Delphi/DemoRegistry.zip