Accessing the Windows Registry Using Visual J++

By Al Saganich

The Windows Registry provides a hierarchical database of configuration information and persistent storage that's essential to the Windows operating system and to Windows users and developers, as well. It's actually been around since 3.1 days, although only with Windows 95/NT 3.5 has the Windows Registry became a full-featured tool that developers can use to their advantage.

Last month, when we looked at Java Services, we used the Services Control Panel application to manipulate our service. In fact, the information we were manipulating was actually stored in the Windows Registry! This month we'll take a look at how the registry works, and at how the Visual J++ WFC classes can be used to add to, delete from, update, and search the registry.

Registry hives

The top-most level of the Windows Registry hierarchy is made up of several individual sub-groupings of system or application data. These sub-groupings have historically been known as hives. The different hives are:

Two additional hives exist for performance data: HKEY_DYN_DATA and HKEY_PERFORMANCE_DATA, for Window 95/98 and Windows NT, respectively.

Note: Often, the registry hives are referred to by abbreviations, such as HKLM for HKEY_LOCAL_MACHINE or HKCU for HKEY_CURRENT_USER. We'll use these abbreviations in this article.

Registry Contents

On first glance, the registry is an incredibly complex structure with entries in which most developers aren't interested, and, in most cases, shouldn't be tampered with. However, there are areas specifically designed for application use. Don't let your first look at the registry's contents intimidate you, but do be careful:

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.  vjp98c2a.gif (30866 bytes)

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:

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.
vjp98c2b.gif (3881 bytes)

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.
vjp98c2c.gif (9749 bytes)

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

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.
vjp98c2d.gif (13893 bytes)

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.
vjp98c2e.gif (8956 bytes)

Figure F: This is the result of enumerating all of the subkey values in the Software subkey.
vjp98c2f.gif (7083 bytes)

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.

Tip: Make changes to the registry carefully
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!