The registry isn't something to be played with. All of the
configuration information about booting and maintaining your computer is in the registry.
Deleting or changing the wrong entry could render your computer unusable! |
Under normal circumstances, the registry can be read and updated directly with the
Windows regedit utility. Figure A shows an example of running regedit.
Figure A: Regedit, The Windows Registry Editor, can be used to read and edit the
registry.
While we won't go into any detail on how to use regedit, it's an important tool for
debugging. However, be careful to only edit and manipulate those entries you've added
yourself!
While the registry is very complex you needn't understand much of it in order to make
use of the capabilities it provides. As was previously mentioned, the registry is a
hierarchy of data. Below each of the hives is a series of keys and subkeys. Each key can
contain either additional subkeys or data or both. The regedit utility in Figure A is
displaying some of the entries of one of the most commonly used subkeys, the HKCU\Software
subkey.
The Software subkey entries are used for program persistent storage, specifically user
settings, with subkeys for each company and software product. Each of these subkeys
provides some number of data items, called values, which represent actual program
settings. Data values come in any of a number of types, such as strings, longs, binary, or
blobs, and the Visual J++ WFC provides several classes for accessing this information.
Visual J++ registry classes
An application typically can do only three things with the registry:
- Add keys and values
- Modify existing values
- Read values previously stored
The registry can be accessed via a number of Visual J++ classes and methods that
support adding keys, adding and updating values, removing keys, and otherwise accessing
registry data. In this article, we'll develop a simple user address book application using
Visual J++ that allows us to store, change, and list entries in the registry.
Two main WFC classes exist for accessing the registry:
com.ms.wfc.app.RegistryKey
and
com.ms.wfc.app.Registry
The Registry class is simply a public final class that contains a set of RegistryKey
objects. The RegistryKey objects represent the individual registry hives, where each
object name matches the hive name without the HKEY_ prefix. For example, the RegistryKey's
CURRENT_USER object represents the HKEY_CURRENT_USER hive. The RegistryKey class, on the
other hand, contains a set of methods for manipulating registry subkeys and data.
Figure B shows a form for a simple Java applet that adds an address record into the
registry.
Figure B: The form for adding a record to the registry was created in the Visual
J++ form editor.
The applet itself was developed quickly and easily with the Visual J++ form editor. The
Store Changes button was then hooked to the onClickStore method, shown as Listing A.
Note: All of the code for this article may be downloaded from our FTP site at
ftp://ftp.zdjournals.com/vjp/dec98.zip
Listing A: The onClickStore Method
private void onClickStore(Object
source, Event e) {
//
//Store in the information based on the
input user name.
//
String name[] = UserName.getLines();
String address[] = Address.getLines();
String phone[] = Phone.getLines();
String dob[] = DOB.getLines();
System.out.println("User clicked store");
System.out.println("Storing " +
name[0] + " at " + address[0] + " " + phone[0] +
" " + dob[0] + ".");
//
// Create a subkey or open it if it already exists.
//
RegistryKey key = Registry.CURRENT_USER.createSubKey
(registryRoot+name[0]);
key.setValue( "address", address[0] );
key.setValue( "phone", phone[0] );
key.setValue( "dob", dob[0] );
}
Saving Data
The onClickStore method creates a specific key and then adds values to it. As
previously noted, the HKEY_CURRENT_USER hive stores information specific to the currently
logged-on user. We use the Registry class's CURRENT_USER object to access the registry
hive in which we want to add the data. Since we want to store our information in the hive,
we start by creating a subkey in that hive with the statement:
RegistryKey key =
Registry.CURRENT_USER.createSubKey
(registryRoot+name[0]);
Note that the registryRoot variable is simply a string that represents the product we
want to add. As an example, I use ZDJournals\\VJ++Journal\\ under the Software subkey,
where ZDJournals is the company and VJ++Journal is the software product.
This company/product breakdown is the normal procedure for storing information and keeps
the products of different companies from clashing in the event that their names are
similar.
The createSubKey method adds a new entry whose entire path is HKCU\
Software\ZDJournals\VJ++Journal\ {SomeName}, based on whatever the user entered.
Note: CreateSubKey has side effect
The createSubKey method has a side effect in that it either opens an existing key or
creates that key if it's not present. If, for some reason, you only want to open an
existing key, use getSubKey instead.
Now that we've created our subkey, we can add one or more data items to it with
setValue, as shown below:
key.setValue( "address", address[0] );
Note that setValue takes a string that represents the name of the value as its first
argument and an object as its second argument. Any object may be written to the registry;
however, you may find it easier to stick with storing strings and converting in and out of
strings when adding and retrieving data from the registry. We'll talk more about this
later.
Retrieving Data
Retrieving data from the registry is almost as straightforward as writing it; that is,
almost! Just as there's a setValue method on any Java object, there's also a getValue
method. If we stored a value with the name foo for a given key, we can retrieve it
back with the same name. For example, we could store and retrieve an integer and a double
string using the code shown in Listing B. Note that it's assumed that the key object was
set up with a createSubKey or getSubKey method call.
Listing B: Code for storing and returning registry data
key.setValue("integertest",new Integer(127));
Integer testInteger = (Integer)
key.getValue("integertest");
key.setValue("doubletest", new Double(1.2445));
Double testDouble = new
Double((String)key.getValue("doubletest"));
Additional Operations
In addition to reading and writing to the registry, the RegistryKey class provides
methods for enumerating subkeys and values, as well as deleting values, subkeys, and
entire subkey hierarchies. Figure C shows the main form for our simple registry example
and Listings C and D show the code for populating the dropdown combo box, as well as
deleting an entry.
Figure C: Our simple registry program uses this as its main form.
Listing C: Populating the list box
RegistryKey key =
Registry.CURRENT_USER.getSubKey(registryRoot);
String[] subKeys = key.getSubKeyNames();
for ( int i = 0; i < key.getSubKeyCount(); i++) {
cbNames.addItem( subKeys[i] );
}
Listing D: Deleting a Subkey
int which = cbNames.getSelectedIndex();
if ( -1 == which ) return;
String selectedName = (String)cbNames.
getItem( which );
RegistryKey key =
Registry.CURRENT_USER.getSubKey
(registryRoot );
key.deleteSubKeyTree( selectedName );
Populating the list box is really quite simple and most of the code centers around the
list box itself. As we've seen before, we first open the subkey that represents our
registry, then we iterate over all the subkeys, first getting all the names with
getSubKeyNames, and then bounding our loop with getSubKeyCount.
Deleting an entry with deleteSubKeyTree is even easier then enumerating entries, as
Listing D shows. DeleteSubKeyTree takes as its argument the name of a subkey and
recursively deletes the entire subtree, values and all.
More Sophisticated Access
While the Registry and RegistryKey classes are easy to use, they are somewhat lacking
in some of the more sophisticated features to which C and C++ developers have grown
accustomed.
We've touched briefly on the fact that strings, integers, and other data types may be
stored in the Windows Registry. What we haven't yet addressed is the complete set of
supported data types. In fact, the Windows C++ API includes a call, RegSetValueEx, which
documents 10 explicit data types, not all of which are supported by regedit or its older
Windows NT cousin regedt32. Specifically, the data types supported by the Windows Registry
are
- REG_BINARY--Binary or blob data.
- REG_DWORD--32-bit values.
- REG_DWORD_LITTLE_ENDIAN --synonym for REG_DWORD.
- REG_DWORD_BIG_ENDIAN--32-bit value, most significant byte first.
- REG_EXPAND_SZE--nvironment variable such as %PATH%.
- REG_LINK--Unicode symbolic link.
- REG_SZ--Null terminated string.
- REG_MULTI_SZ--Multiple strings separated by single nul's and terminated by double null.
- REG_RESOURCE_LIST--Device Driver Resource List.
- REG_NONE--Not currently defined.
Although not all of these types are supported by Visual J++, many are, by the
com.ms.lang.RegKey class. The RegKey class provides a powerful interfacefor enumerating
keys and values, showing internal information about keys and values, and returning and
displaying any data value.
Figure D shows a simple applet that makes use of the RegKey class.
Figure D: This simple applet makes use of the RegKey class.
Specifically, Figure D shows the result of the RegKey's queryInfo method on the
registry key
HKLM\Software\CobbGroup\VJ++Journal.
We'll discuss what the queryInfo method returns in a moment, but before we do, it's
important to understand how we create RegKey objects in the first place.
The RegKey Constructor
The RegKey class contains a number of constructors that allow for the fine-tuning of
how we access the registry. The RegKey class differs from the RegistryKey class in that we
can create new RegKey objects and specify how we'll use them. For example, the RegKey
class itself contains a number of final static fields that represent access rights. That
is, RegKey.KEYOPEN_ALL allows for read, write, and delete access, whereas
RegKey.KEYOPEN_READ allows for opening a key-read only.
Access rights become important when you wish to open or manipulate registry keys in
protected areas. Consider that many users may log on to a single Windows NT workstation,
but only certain users have Administrator privileges. Without the ability to open the
registry, read-only users may not be able to run the applications that require information
from the HKEY_LOCAL_MACHINE hive. Also, applications regularly store global application
information within HKLM, causing a major headache for the developer if he can't read that
data.
The RegKey class constructor actually has three flavors, all completely documented in
the online help. Two of these create RegKey objects from scratch, and the third creates
one RegKey from another RegKey.
Digging Deeper
RegKey objects have finer control in other areas, as well. As we saw in Figure D, we
can query a subkey for a complete set of information about itself right down to its last
modification date. (Note that the last modification date is only available under Windows
NT). Listing E shows a snippet of code that uses the queryInfo method. The complete code,
in the file RegTest2, is available for download from our FTP site.
Listing E: RegKey queryInfo method
RegKey key = null;
try {
key = new RegKey(hive,editSubKey.getText(),
RegKey.KEYOPEN_READ);
} catch (RegKeyException unexpectedE) {
System.out.println("Unexpected RegKey
Exception CTor" + unexpectedE);
return;
}
try {
RegQueryInfo info = key.queryInfo();
String data = "key.queryInfo return \r\n\t";
data += "info.lastWriteTime: " +
info.lastWriteTime +
"\r\n\t";
data += "info.maxClassLen: "+
info.maxClassLen +
"\r\n\t";
data += "info.maxSubKeyLen: " +
info.maxSubKeyLen +
"\r\n\t";
data += "info.maxValueLen: " +
info.maxValueLen +
"\r\n\t";
data += "info.maxValueNameLen:" +
info.maxValueNameLen + "\r\n\t";
data += "info.securityDescriptor" +
info.securityDescriptor + "\r\n\t";
data += "info.subKeys: " + info.subKeys + "\r\n\t";
data += "info.theClass: " + info.theClass + "\r\n\t";
data += "info.values: " + info.values + "\r\n\t";
result.setText(data);
}
We can see from Listing E that since we're only reading the registry, we specify read
access only in the RegKey constructor. Like its RegistryKey cousin, we also specify the
hive of interest and the subkey to open. Since our code allows for reading information
from any of the RegKey supported hives, we don't want to assume that we can write.
Once we have the subkey object, we can then query for information about it. The
queryInfo method actually returns a RegQueryInfo object rather than raw data. We can then
delve further into the subkey to list its values and subkeys. Listing F shows how we might
enumerate all the values within a key, whereas Listing G shows the same code for subkeys
within a key. Figures E and F show the result of running Listing F and G, respectively, on
the Software subkey of HKEY_LOCAL_MACHINE.
Figure E: This is the result of enumerating all of the values in the
HKEY_LOCAL_MACHINE hive.
Figure F: This is the result of enumerating all of the subkey values in the
Software subkey.
Listing F: Enumerating values
try {
key = new RegKey(hive,editSubKey.
getText(),RegKey.
KEYOPEN_READ);
} catch (RegKeyException unexpectedE){
System.out.println("Unexpected RegKey
Exception CTor" + unexpectedE);
return;
}
String data = "key.enumValue returned \r\n\t";
int i;
for ( i = 0; ;i++){
RegKeyEnumValue value;
try { value = key.enumValue(i);
} catch (RegKeyException exceptionE) { break; }
if ( null == value ) break;
data += value.toString();
data += "\r\n\t";
}
Listing G: Enumerating subkeys
RegKey key = null;
try {
key = new RegKey(hive,editSubKey.getText(),
RegKey.KEYOPEN_READ);
} catch (RegKeyException unexpectedE) {
System.out.println("Unexpected
RegKeyException CTor" + unexpectedE);
return;
}
String data = "key.enumKey returned \r\n\t";
int i;
for ( i = 0; ;i++) {
String value;
try { value = key.enumKey(i);
} catch (RegKeyException unexpectedE) { break;
}
if ( null == value ) break;
data += value + "\r\n\t";
}
An important point to notice about the RegKey.EnumValue method is that it actually
returns RegKey.EnumValue objects. The enum value object can actually represent any of
three subclasses of this object, as well as any of the other registry data types (getting
and setting directly is only supported for byte arrays, integers, and strings).
Specifically, RegKeyEnumValueByteArray is used for binary data, RegKeyEnumValueInt is used
for integer data, and RegKeyEnumValueString is used for string data. Each of these objects
also contains methods for accessing the underlying data type, such as a getValue method,
which returns an appropriate Java data type. The RegKeyEnumValue parent class contains
additional information about an object, such as the object's type (It supports all 10 of
the registry data types.), as well as information about the data in general, such as its
name, etc.
Other Methods
There are many other methods within the RegKey object, but getIntValue, getBinaryValue,
and getStringValue bear a special mention. Each of these methods allows for getting and
setting the three primary data types supported by the RegKey class. In addition, as with
the RegistryKey class, deleting values and subkeys is also supported.
Conclusion
The Windows Registry is an incredibly useful structure. No longer are users and
developers limited by .INI files, but rather can use a centralized data store for user,
program and system management information. In this article, we examined two different
Visual J++ WFC class sets for accessing and manipulating the registry. One class set,
com.ms.wfc.app.Registry and com.ms.wfc.app.RegistryKey, is simple, straightforward, and
easy to use for your regular day-to-day needs, while the second, com.ms.lang.RegKey, is
for more sophisticated access.
The Windows Registry is only a tool to an end, but when used correctly it can help you
develop more robust and usable applications. While we couldn't possibly give an in-depth
discussion of the contents of the registry, we've hopefully given you some insight into
how the registry is accessed by Visual J++ and why.
Copyright © 1998, ZD
Inc. All rights reserved. ZD Journals and the ZD Journals logo are trademarks of ZD
Inc. Reproduction in whole or in part in any form or medium without
express written permission of ZD Inc. is prohibited. All other product
names and logos are trademarks or registered trademarks of their
respective owners.