Delphi and
the Registry
by
Christian Feichtner
--------------------------------------------------------------------------------
Contents:
0.
DISCLAIMER:
1. What is
the registry?
2. What
does the registry look like?
3. How to
read and write data to the registry
3.1 RegCreateKey()
3.2 RegOpenKey()
3.3 RegSetValue()
3.4 RegQueryValue()
3.5 RegDeleteKey()
3.6 RegEnumKey()
4. An
Example
5. Win95
features
6. REGDLL.DLL
The source
code corresponding to this article is available for download as registry.zip.
--------------------------------------------------------------------------------
0.
DISCLAIMER:
This
article reflects my personal experiences with the registry and Delphi. I had no
'real' documentation on this, except what shipped with Delphi. I will not take
any responsibility that occurs from the usage of the procedures described in
this article. The same applies to the usage of the accompanying REGDLL.DLL and
its interface. USE AT YOUR OWN RISK.
Suggestions
and Comments are welcome. Please send them to:
Christian.Feichtner@jk.uni-linz.ac.at.
This
article describes how to use the registry-database as an 'INI file'. Especially
with the advent of Windows 95 every 'good' windows application should use the
registry database to store its information.
Note that
the described API routines are from the 16bit API. They work well with the
registry of Windows 95, but are not capable of using the special new features
of Windows 95.
--------------------------------------------------------------------------------
1. What is
the registry?
The
registry is a heirarchical database, which is used to store information for the
whole system. OLE-apps made frequent use of the registry in Win31. In Windows
95 the registry has grown to more than that. It not only stores system
information but has become a total replacement for the old-style INI files. The
INI files are only supported to maintain compatibility for 'old' 16bit Apps.
--------------------------------------------------------------------------------
2. What
does the registry look like?
As
mentioned above, the registry is a heirarchical database. It is organized as a
tree. The most interesting key (and the only one accessable from Delphi with
the 16bit version) is the HKEY_CLASSES_ROOT.
This key
can be used to store application settings. (Thus, I think there is another key
for Windows 95 apps. Since Delphi can only access this key, you can use it
until Delphi-32 becomes avaliable).
Example:
+ HKEY_CLASSES_ROOT This is what a key could look like. Assume an
| application named Information Manager
(which I'm
+--+-.IFM currently developing) which saves its files with
the
| extension .IFM. Under Win95 the shell, open, command
+--+-shell and ShellNew keys are of special interest. (Yes they
| can be used with Delphi as well.)
+--+-open
|
|
|
+---command
|
+-ShellNew
.IFM\shell\open\command
defines the command to be executed when the user double clicks on the file (or
under Win95 hits the right mouse button and selects open).
The keys
alone won't do the job. Normally there are values assigned to the keys. Under
Win31 these can only be strings. Win95 defines a kind of binary and a DWORD as
well.
The
shell\open\command normally has a value like:
Name Value
+ HKEY_CLASSES_ROOT
|
+--+-.IFM
|
+--+-shell
|
+--+-open
|
|
|
+---command (default) "H:\PROJECT\INFOMAN\IFM.EXE %1"
|
+-ShellNew
The
selected filename will be substituted for '%1' and passed along as a
command-line parameter to the application. Your Delphi app can use PARAMSTR(x)
to get the x-th command line parameter. x=0 returns the full path and name of
the application itself.
If you are
using the preview of Win95 and want your application to have an entry in the
'New' popup menu (something like 'Information Manager 1.0 file'), you have to
do the following:
Add a new
(text) value for the ShellNew key, named NullFile, with a value of
"". Also name the extension (.IFM) equal to the entry of your app in
the registry. If the application has an entry named 'InfoMan', then name .IFM
as InfoMan.
Example:
Name
Value
+ HKEY_CLASSES_ROOT
|
+--+-.IFM (default)
"InfoMan"
|
+--+-shell
|
+--+-open
|
|
|
+---command (default) "H:\PROJECT\INFOMAN\IFM.EXE %1"
|
+-ShellNew
NullFile ""
Now for the
key for the application itself. (I assume the application is still Information
Manager (short: InfoMan)).
The whole
tree looks like this:
Name Value
+ HKEY_CLASSES_ROOT
|
+--+-InfoMan (default)
"Information Manager 1.0 File"
|
+--+-Misc
|
+--+-Options
|
|
|
+---Saving
|
|
|
+---Directories
|
+--+-shell
|
+--+-open
|
+---command (default) "H:\PROJECT\INFOMAN\IFM.EXE %1"
The Options
key contains several other subkeys, which store the application- specific
settings like the window position, delete confirmations, and others.
--------------------------------------------------------------------------------
3. How to
read and write data to the registry
Delphi
offers the following API-routines for accessing the registry:
RegCreateKey()
RegOpenKey()
RegDeleteKey()
RegCloseKey()
RegEnumKey()
RegQueryValue()
RegSetValue()
NOTE: These
functions are from the Win31 API. These functions can only read and write
string (PChar) values and can not set the name of a key.
Before a
key can be accessed, it must be opened. The open functions return a handle
(HKEY), which is used to access the subkeys.
3.1
RegCreateKey()
Opens a key
and if the key does not exist, it will be created.
function
RegCreateKey(Key: HKey; SubKey: PChar; var Result: HKey): Longint;
Key:
The handle
of the key which should be accessed. To write directly under the root, you can
use HKEY_CLASSES_ROOT.
SubKey:
The subkey
to be accessed.
Result:
The
resulting key-handle.
Returns:
ERROR_SUCCESS,
if the function was successful, otherwise it will be an error value.
3.2
RegOpenKey()
Opens an
existing key. Unlike RegCreateKey, a non existing key returns an error and will
not be created.
function
RegOpenKey(Key: HKey; SubKey: PChar; var Result: HKey): Longint;
Key:
The handle
of the key which should be accessed. To write directly under the root, you can
use HKEY_CLASSES_ROOT.
SubKey:
The subkey
to be accessed.
Result:
The
resulting key-handle.
Returns:
ERROR_SUCCESS,
if the function was successful, otherwise it will be an error value.
3.3
RegSetValue()
Writes a
given value to the registry. Currently only a PChar-type can be written. To
store boolean or integer values, they must be converted.
function RegSetValue(Key:
HKey; SubKey: PChar; ValType: Longint; Value: PChar; cb: Longint): Longint;
Key:
The Handle
of the parent key (can be HKEY_CLASSES_ROOT).
SubKey:
The subkey
for which the value should be stored.
ValType:
must be
REG_SZ for Win31.
Value:
The value
to be stored.
cb:
Size in
bytes for the Value parameter. Windows 3.1 ignores this paramater.
Returns:
ERROR_SUCCESS
if function was successful; otherwise an error is returned.
3.4
RegQueryValue()
Reads a
value from a given key (only PChar). If you want to read a boolean or integer
value, it must be converted since the Win31 registry only stores strings.
function
RegQueryValue(Key: HKey; SubKey: PChar; Value: PChar; var cb: Longint):
Longint;
Key:
The Handle
of the parent key (can be HKEY_CLASSES_ROOT).
SubKey:
The subkey
from which the value should be read.
Value:
Pointer to
a buffer, which stores the read information. Must be a PChar.
cb:
Size of the
buffer. Contains the number of chars in the buffer, after completion of the
function.
Returns:
ERROR_SUCCESS
if function was successful; otherwise an error is returned.
NOTE: The
docs say, that the cb parameter is ignored for RegSetValue() and
RegQueryValue(). My experience (Using Delphi and Win95 preview) is the
contrary. Be sure alsways to set the cb parameter to the appropriate buffer
size.
3.5
RegDeleteKey()
Delets a
key from the registry.
function
RegDeleteKey(Key: HKey; SubKey: PChar): Longint;
Key:
The Handle
of the parent key (can be HKEY_CLASSES_ROOT).
SubKey:
The subkey
which should be deleted.
Returns:
ERROR_SUCCESS
if the key was deleted, or ERROR_ACCESS_DENIED if the key is in use by another
application.
3.6
RegEnumKey()
Enumerates
the keys for an open key.
function
RegEnumKey(Key: HKey; index: Longint; Buffer: PChar; cb: Longint): Longint;
Key:
The handle
of an open key (can be HKEY_CLASSES_ROOT).
index:
The index
of the subkey to retrieve. Should be zero on the first call.
Buffer:
A buffer
which will contain the name of the subkey when the function returns.
cb:
The size of
the buffer. Holds the number of chars copied to the buffer after completion of
the function.
Returns:
ERROR_SUCCESS
if the function was successful. Otherwise an error is returned.
NOTE:
Normally an application starts the enumeration with an index value of zero and
increments it step by step.
GENERAL
NOTES: HKEY_CLASSES_ROOT does not need to be opened. It is always open and
avaliable. However, using RegOpenKey() and RegCloseKey() on the
HKEY_CLASSES_ROOT will speed up performance on subsequent read/write calls.
--------------------------------------------------------------------------------
4. An
Example
So much for
the theory. Here is an example. It is assumed that an application wants to read
and write the paths used for storing its data.
procedure
Options.SaveSettings(Sender: TObject);
var
hndKey: HKey;
ValBuf: PChar;
cb: Longint;
begin
...
ValBuf:=StrAlloc(1024);
RegCreateKey('HKEY_CLASSES_ROOT\InfoMan\Options\Directories',hndKey);
cb:=1024;
RegSetValue(hndKey,'Working',StrPCopy(ValBuf,WorkingDir));
cb:=1024;
RegSetValue(hndKey,'Templates',StrPCopy(ValBuf,TemplateDir));
RegCloseKey(hndKey);
StrDispose(ValBuf);
end;
function
GetWorkingDir: String;
var
hndKey: HKey;
ValBuf: PChar;
cb:
Longint;
begin
...
ValBuf:=StrAlloc(1024);
cb:=1024;
if
RegOpenKey('HKEY_CLASSES_ROOT','InfoMan\Options\Directories',hndKey) =
ERROR_SUCCESS then begin
RegQueryValue(hndKey,'Working',ValBuf,cb);
GetWorkingDir:=StrPas(ValBuf);
end
else
GetWorkingDir:='C:\WINDOWS';
end;
--------------------------------------------------------------------------------
5. Win95
features
Since you
can't create a tree (or a key) for the Win95 specific features, you might want
to create a .REG file which then can be merged into the registry using the
following command:
regedit.exe
/i filename.reg
The syntax
of a .REG file is quite simple:
[KeyPath]
Name=Value
Name can be
'@' if you want to specify it as default. Here is an example of a .REG file:
REGEDIT4
[HKEY_CLASSES_ROOT\InfoMan]
@="Information
Manager 1.0 File"
[HKEY_CLASSES_ROOT\InfoMan\Misc]
[HKEY_CLASSES_ROOT\InfoMan\Misc\RecentFiles]
[HKEY_CLASSES_ROOT\InfoMan\Misc\RecentFiles\File1]
@="H:\\PROJEKTE\\INFOMAN\\EXAMPLES\\COMPUTER.IFM"
[HKEY_CLASSES_ROOT\InfoMan\Misc\RecentFiles\File2]
@=""
[HKEY_CLASSES_ROOT\InfoMan\Misc\RecentFiles\File3]
@=""
[HKEY_CLASSES_ROOT\InfoMan\Misc\RecentFiles\File4]
@=""
[HKEY_CLASSES_ROOT\InfoMan\Misc\WindowPos]
[HKEY_CLASSES_ROOT\InfoMan\Misc\WindowPos\Top]
@="97"
[HKEY_CLASSES_ROOT\InfoMan\Misc\WindowPos\Left]
@="169"
[HKEY_CLASSES_ROOT\InfoMan\Misc\WindowPos\Height]
@="590"
[HKEY_CLASSES_ROOT\InfoMan\Misc\WindowPos\Width]
@="728"
[HKEY_CLASSES_ROOT\InfoMan\Options]
[HKEY_CLASSES_ROOT\InfoMan\Options\Confirmations]
[HKEY_CLASSES_ROOT\InfoMan\Options\Confirmations\ItemRemove]
@="1"
[HKEY_CLASSES_ROOT\InfoMan\Options\Confirmations\ParentRemove]
@="1"
[HKEY_CLASSES_ROOT\InfoMan\Options\Directories]
[HKEY_CLASSES_ROOT\InfoMan\Options\Directories\Working]
@="H:\\PROJEKTE\\INFOMAN\\"
[HKEY_CLASSES_ROOT\InfoMan\Options\Directories\Templates]
@="H:\\PROJEKTE\\INFOMAN\\"
[HKEY_CLASSES_ROOT\InfoMan\Options\Directories\AutoSave]
@="H:\\PROJEKTE\\INFOMAN\\"
[HKEY_CLASSES_ROOT\InfoMan\Options\Saving]
[HKEY_CLASSES_ROOT\InfoMan\Options\Saving\AutoSave]
@="0"
[HKEY_CLASSES_ROOT\InfoMan\Options\Saving\CreateBackup]
@="1"
[HKEY_CLASSES_ROOT\InfoMan\Options\Saving\EnterFileInfo]
@="1"
[HKEY_CLASSES_ROOT\InfoMan\Options\Saving\TopicAsTitle]
@="1"
[HKEY_CLASSES_ROOT\InfoMan\shell]
[HKEY_CLASSES_ROOT\InfoMan\shell\open]
[HKEY_CLASSES_ROOT\InfoMan\shell\open\command]
@="H:\\PROJEKTE\\INFOMAN\\infoman.exe
%1"
--------------------------------------------------------------------------------
6. REGDLL.DLL
As you
might have noticed by now, there is a lot of redunant programming while
accessing the registry. Therefore I've written a .DLL, that does all the work. Along
with the .DLL there is an interface unit, which exports a TRegistry Object. With
this .DLL you can read and write from the registry, just like it would be an
INI-File. This .DLL is provided as freeware as long as the copyright notices
remain intact.
See
RegInt.pas for how to use the .DLL.
Christian.Feichtner@jk.uni-linz.ac.at
Copyright ©
1995 Christian Feichtner. This is a CITY ZOO production.
Last
revised January 8, 1996.
Enhanced version