In all versions of Windows since Windows 95, the registry has been the central repository for all configuration information relating to Windows setup, user preferences, and installed software and devices, Almost all commercial software these days uses the registry to store information about itself, and COM components must place information about themselves in the registry in order to be called by clients.
The .NET Framework and its accompanying concept of zero-impact installation has slightly reduced the significance of the registry for applications in the sense that assemblies are entirely selfcontained; no information about particular assemblies needs to be placed in the registry, even for shared assemblies.
In addition, the .NET Framework has brought the concept of isolated storage, by which applications can store information that is particular to each user in files; the .NET Framework ensures that data is stored separately for each user registered on a machine.
The fact that applications can now be installed using the Windows Installer also frees developers from some of the direct manipulation of the registry that used to be involved in installing applications.
However, despite this, the possibility exists that if you distribute any complete application, your application will use the registry to store information about its configuration. For instance, if you want your application to show up’in the Add/Remove Programs dialog box in the Control Panel; this will involve appropriate registry entries, You may also need to use the registry for backward compatibility with legacy code.
As you would expect from a library as comprehensive as the .NET library, it includes classes that give you access to the registry, Two classes are concerned with the registry, and both are in the Microsoft, Win32 namespace.
The classes are Registry and RegistryKey, Before you examine these classes, the following section briefly reviews the structure of the registry itself.
The registry has a hierarchical structure much like that of the file system, The usual way to view or modify the contents of the registry is with one of two utilities: regedit or regedt32 of these, regedit comes standard with all versions of Windows since Windows 95 regedt32 comes with Windows NT and Windows 2000; it is less user-friendly than regedit, but allows access to security information that regedit is unable to view Windows Server 2003 has merged regedit and regedt32 into a single new editor simply called regedit For the discussion here, you will use regedit from Windows XP Professional, which you can launch by typing in regedit in the Run dialog or at the command prompt.
what you get when you launch regedit for the first time.
regedit has a tree view /list view-style user interface similar to Windows Explorer, which matches then hierarchical structure of the registry itself However, you will see some key differences shortly.
In a file system, the topmost-level nodes can be thought of as being the partitions on your disks, C: \, D: \, and so on. In the registry, the equivalent to a partition is the registry hive, It is not possible to change the existing hives – they are fixed, and there are seven of them, although only five are actually visible through regedit:
¤HKEY_CLASSES_ROOT (HKCR) contains details of types of files on the system (: txt, . doc, and so on) and which applications are able to open files of each type, It also contains registration information for all COM components (this latter area is usually the largest single area of the registry because Windows, these days, comes with a huge number of COM components).
¤HKEY_CURRENT_USER(HKCU) contains details of user preferences for the user currently logged on to the machine locally, These settings include desktop settings, environment variables, network and printer connections, and other settings that define the user operating environment of the user.
¤HKEY_LOCAL_MACHINE(HKLM) is a huge hive that contains details of all software and hardware installed on the machine, These settings are not user-specific but are for all users that log on to the machine, This hive also includes the HKCR hive; HKCR is actually not really an independent hive in its own right but is simply a convenient mapping onto the registry key HKLM/SOFTWARE/Classes.
¤HKEY_USERS (HKUSR)contains details of user preferences for all users, As you might guess, it also contains the HKCU hive, which is simply a mapping onto one of the keys in HKEY_USERS.
¤HKEY_CURRENT_CONFIG(HKCF) contains details of hardware on the machine.
The remaining two keys contain information that is temporary and that changes frequently.
¤HKEY_DYN_DATA is a general container for any volatile data that needs to be stored somewhere in the registry.
¤HKEY_PERFORMANCE_DATA contains information concerning the performance of running applications.
Within the hives is a tree structure of registry key, Each key is in many ways analogous to a folder or file on the file system, However, there is one very important difference, The file system distinguishes between files (which are there-to contain data) and folders (which are primarily there to contain other files or folders), but in the registry there are only keys, A key may contain both data and other keys.
If a key contains data, it will be presented as a series of values. Each value will have an associated name, data type, and data. In addition, a key can have a default value, which is unnamed.
If a key contains data, it will be presented as a series of values, Each value will have an associated name, data type, and data In addition, a key can have a default value, which is unnamed.
You can see this structure by using regedi t to examine registry keys, the contents of the key HKCU\Control Panel \Appearance, which contains the details of the chosen color scheme of the currently logged-in user, regedit shows which key is being examined by displaying it with an open folder icon in the tree view.
The HKCU\Control Panel \Appearance key has three named values set, although the default value does not contain any data, The column in the screenshot marked Type details the data type of each value, Registry entries can be formatted as one of three data types:
¤ REG_SZ (which roughly corresponds to a .NET string instance; the matching is not exact because the registry data types are not .NET data types)
¤ REG_DWORD (corresponds roughly to unit)
¤ REG_BINARY(array of bytes)
An application that stores data in the registry will do so by creating a number of registry keys, usually under the key HKLM\Software\<CompanyName>.
Note that it is not necessary for these keys to contain any data Sometimes the very fact that a key exists provides the data that an application needs.
The .NET Registry Classes
Access to the registry is available through two classes in the Microsoft. Win32 namespace: Registry and RegistryKey.
A RegistryKey instance represents a registry key. This class implements methods to browse child keys, to create new keys, or to read or modify the values in the key – in other words, to do everything you would normally want to do with a registry key, including setting the security levels for the key, RegistryKey will be the class you use for much of your work with the registry.
Registry, by contrast, is a class that allows for singular access to registry keys for simple operations, Another role of he Registry class is simply to provide you with RegistryKey instances that represent the top-level keys, the different hives, in order to enable you to navigate the registry, Registry provides these instances through static properties, and there are seven of them called, respectively, ClassesRoot, CurrentConfig, CurrentUser, DynData, LocalMachine, PerforrnanceData, and Users It should be obvious which property corresponds to which hive.
So, for example, to obtain a RegistryKey instance that represents the HKLMkey, you would write:
RegistryKey hklm = Registry. LocalMachine;
The process of obtaining a reference to a RegistryKey object is known as opening the key.
Although you might expect that the methods exposed by RegistryKey would be similar to those implemented by Directorylnfo, given that the registry has a similar hierarchical structure to the file system, this actually isn’t the case.,Often the way that you access the registry is different from the way that you would use files and folders, and RegistryKey implements methods that reflect this.
The most obvious difference is 10 how you open a registry key at a given location in the registry, The Registry class does not have any public constructor that you can use, nor does it have any methods that let you go directly to a key, given its name Instead, you are expected to browse down to that key from the top of the relevant hive If you want to instantiate a RegistryKey object, the only way is to start off with the appropriate static property of Registry, and work down from there.
So, for example, if you want to read some data in the HKLM/Software/Microsoft key, you would get a reference to it like this:
RegistryKey hklm = Registry. LocalMachine;
RegistryKey hkSoftware = hklm.OpenSubKey(“Software”);
RegistryKey hkMicrosoft = hkSoftware.OpenSubKey(“Microsoft”);
A registry key accessed in this way will give you read-only access, If you want to be able to write to the key (that includes writing to its values or creating or deleting direct children of it), you-need to use another override to OpenSubKey, which takes a second parameter, of type bool, that indicates whether you want read-write access to the key.
For example, if you want to be able to modify the Microsoft key (and assuming that you are a system administrator with permission to do this), you would write this:
RegistryKey hklm = Registry.LocalMachine;
RegistryKey hkSoftware = hklm.OpensubKeY(“Software”);
RegistryKey hkMicrosoft = hkSoftware.OpenSubKey(“Microsoft”, true);
Incidentally, because this key contains information used by Microsoft’s applications, in most cases you probably shouldn’t be modifying this particular key.
The OpenSubKey() method is the one you will call if you are expecting the key to be present, If the key isn’t there, it will return a null reference, If you want to create a key, you should use the CreateSubKey () method (which automatically gives you read-write access to the key through the reference returned):
RegistryKey hklm = Registry.LocalMachine;
RegistryKey hkSoftware = hklm.OpenSubKey(“Software’);
RegistryKey hkMine = hkSoftware.CreateSubKey(“MyOwnSoftware”);
The way that CreateSubKey () works is quite interesting. It will create the key if it does not already exist, but if it does already exist, it will quietly return a RegistryKey instance that represents the existing key, The reason for the method behaving in this manner has to do with how you will normally use the registry, The registry, overall, contains long-term data such as configuration information for Windows and for various applications, It is not very common, therefore, that you find yourself in a situation where you need to explicitly create a key.
What is much more common is that your application needs to make sure that ‘some data is present in the registry – in other words, create the relevant keys if they do not already exist, but do nothing if they do.
CreateSubKey () fills that need perfectly. Unlike the situation with Filelnfo. Open (), for example, there is no chance with CreateSubKey () of accidentally removing any data. U deleting registry keys is your intention, you will need to call the RegistryKey. DeleteSubKey () method.
This makes sense given the importance of the registry to Windows, The last thing you want is to completely break Windows accidentally by deleting a couple of important keys while you are debugging your
C# registry calls!
Once you have located the registry key you want to read or modify, you can use the SetValue () or GetValue () methods to set or get at the data in it. Both of these methods take a string giving the name of the value as a parameter, and SetValue () requires an additional object reference containing details of the value, Because the parameter is defined as an object reference, it can actually be a reference to any class you want SetValue () will decide from the type of class actually supplied whether to set the value as a REG_SZ,REG_DWORoDr ,REG_BINARvYalue. For example:
RegistryKey hkMine = HkSoftware.CreateSubKey(“MyOwnSoftware”);
hkMine.SetValue(“MyStringValue”, “Hello World”);
This code will set the key to have two values: MyStringValue will be of type REG_SZ,and MylntValue will be of type REG_DWORTD These are the only two types you will consider here, and use in the example presented later.
RegistryKey GetValue () works in much the same way It is defined to return an object reference, which means that it is free to actually return a string reference if it detects the value is of type REG_SZ, and an int if that value is of type REG_DWORD:
string stringValue = (string)hkMine. GetValue (“MyStringValue”);
int inavalue.= (int)hkMine.GetValue(“MyIntValue”);
Finally, after you have finished reading or modifying the data, close the key:
RegistryKey implements a large number of methods and properties, The following table lists the most useful properties.
Property Name Description
Name: Name of the key (read-only)
SubKeyCount: The number of children of this key
ValueCount: How many values the key contains
The following table lists the most useful methods.
Method Name Purpose
Close( ): Closes the key.
CreateSubKey (): Creates a subkey of a given name (or opens it if it already exists).
DeleteSubKey ( ): Deletes a given sub key.
DeleteSubKeyTree: Recursively deletes a sub key and all its children.
DeleteValue(): Removes a named value from a key.
GetAccessControl(): Returns the access control list (ACL) for a specified registry key, This method is new to the .NET Framework 2.0.
GetSubKeyNames(): Returns an array of strings containing the names of the subkeys.
GetValue(): Returns a named value.
GetValueKind (): Returns a named value whose registry data type is to be retrieved, This method is new to the .NET Framework 2.0.
GetValueNames (): Returns an array of strings containing the names of all the values of the key.
OpenSubKey ( ): Returns a reference to a RegistryKey instance that represents a given sub key.
SetAccessControl( ): Allows you to apply an access control list (ACL) to a specified registry key.
SetValue ( ): Sets a named value.
The use of the registry classes is illustrated with an application called SelfPlacingWindow, This example is a simple C# Windows application that has almost no features, The only thing you can do with it is click a button, which brings up a standard Windows color dialog box (represented by the System Windows Forms CoLorDialoq class) to let you choose a color, which will become the background color of the form.
Despite its lack of features, the self-placing window scores higher than just about every other application that you have developed in this book in one important and very user-friendly way If you drag the window around the screen, change its size, or maximize or minimize it before you exit the application, it will remember the new position, as well as the background color, so that the next time it is launched it automatically reappears the way you chose last time. It remembers this information because it writes it to the registry whenever it shuts down, In this way, it demonstrates not only the .NET registry classes themselves but also a very typical use for them, which you will almost certainly want to replicate in any serious commercial Windows Forms application that you write, The location in which SelfPlacingWindow stores its information in the registry is the key HKLM\Software \csharp\Self PlacingWindow, HKLM is the usual place for application configuration information, but note that it is not user-specific, If you wanted to be more sophisticated in a real application, you would probably want to replicate the information inside the HK_Users hive as well, so that each user can have his or her own profile.
It is also worth noting that, if you are implementing this in a real .NET application, you may want to consider using isolated storage instead of the registry to store this information, However, because isolated storage is available only in .NET, you will need to use the registry if you need any interoperability with non-.NET apps.
The very first time that you run the example, it will look for this key and not find it (obviously), Therefore, it is forced to use a default size, color, and position that you set in the developer environment, The example also features a list box in which it displays any information read in from the registry, On its first run, it will look similar to Figure 25-18 .
If you now modify the background color and resize SelfPlacingWindow or move it around on the screen a bit before exiting, it will create the HKLM\Software\csharp\SelfPlacingWindow key and write its new configuration information into it, You can examine the information using regedit.
The details are shown.
As this figure shows, SelfPlacingWindow has placed a number of values in the registry key.
The values Red, Green, and Blue give the color components that make up the selected background color, For now, just know that any color display on the system can be completely described by these three components, which are each represented by a number between o and 255 (or OxOO and Oxff hexadecimal).
The values given here make up a bright green color, There are also four more REG_DWORD values, which represent the position and size of the window: X and Y are the coordinates of the top left of the window on the desktop – that is to say the numbers of pixels across from the top left of the screen and the numbers of pixels down. And, Width and Height give the size of the window. WindowsState is the only value for which you have used a string data type (REG_SZ), and it can contain one of the strings Normal, Maximized, or Minimized, depending on the final state of the
window when you exited the application.
When you launch SelfPlacingWindow again, it will read this registry key and automatically position itself accordingly.
This time when.you exit selfPlacingWindow, it will overwrite the previous registry settings with whatever new values are relevant at the time that you exit it.
To code the example, you create the usual Windows Forms project in VISual Studio .NET and add the list box and button, using the developer environment’s toolbox. You will change the names of these controls, respectively, to listBoxMessages and buttonChooseColor, You also need to ensure that you use the Microsoft Win32 namespace:
using System. Drawing;
You need to add one field (chooseColorDialog) to the main Forml class, which will represent the color dialog box:
public partial class forml : Form
private readonly ColorDialog chooseColorDialog new ColorDialog();
Quite a lot of action takes place in the Forml constructor:
public Forml ( )
buttonChooseColor.Click += OnClickChooseColor;
listBoxMessages.lterns.Add(·NO information in registry·);
if (ReadSettings() == false)
listBoxMessages.ltems.Add(·Information read in from registry·);
StartPosition = FormstartPosition.Manual;
catch (Exception e)
listBoxMessagel.ltems.Add(·A problem occurred reading in data
In this constructor, you begin by setting up the event handler for when the user clicks the button, The handler is a method called OnClicltChooseColor ( ), which is covered shortly, Reading in the configuration information is done using another method that you have to write, called ReadSettings (). ReadSettings () returns true if it finds the information in the registry, and false if it does not (which it should be because this is the first time you have run the application).
You place this part lI the constructor in a try block, just in case any exceptions are generated while reading in the registry values (this might happen if some user has come in and played around with the registry using regedit).
The StartPosition = FormStartPosition .Manual ; statement tells the form to take its initial starting position from the DesktopLocation property instead of using the Windows default location (the default behavior).
Possible values are taken from the FormStartPosition enumeration.
SelfPlacingWindow is also one of the few applications in this book in which you have a serious use for adding code to the Dispose () method. Remember that Dispose () is called whenever the application terminates normally, so this is the ideal place from which to save the configuration information to the registry, You will find the Dispose () method in the Forml. Designer. cs file. Within this method, you will place another method that you have to write, Savesettings ( ):
protected override void Dispose(bool disposing)
if (disposing && (components != null»
SaveSettings () ;
The Saveset tings () and ReadSettings () methods are the ones that contain the registry code you are interested in, but before you examine them, you have one more piece of housekeeping to do: handle the event of the user clicking that button This involves displaying the color dialog and setting the background color to whatever color the user chose:
void OnClickChooseColor(object Sender, EventArgs e)
if (chooseColorDialog.ShowDialog() == DialogResult.OK)
BackColor = chooseColorDialog.Color;
Now, look at how you save the settings:
There is a lot going on here. You start by navigating through the registry to get to the HKLM\Software\csharp\SelfelacingWindow registry key using the technique demonstrated earlier, starting with the Registry, localMachine static property that represents the HKLM hive.
Then you use the RegistryKey. OpenSubKey () method, rather than RegistryKey. CreateSubKey (), to get to the HKLM/ Software key, That is because you can be very confident that this key already exists If it does not, then there is something seriously wrong with your computer, because this key contains settings for a lot of system software! You also indicate that you need write access to this key. That is: ”
because if the csharp key does not already exist, you will need to create it, which involves writing to the parent key.
The next key to navigate to is HKLM\Software\csharp – and here you are not certain whether the key already exists, so you use CreateSubKey () to automatically create it if it does not.
Note that Crea teSubKey () automatically gives you write access to the key in question. Once you have reached HKLM\Software\csharp\SelfPlacingWindow, it is simply a matter of calling the RegistryKey. SetValue () method a number of times to either create or set the appropriate values, There are, however, a couple of complications.
First, you might notice that you are using a couple of classes that you have not encountered before, The DeskTopLocation property of the Form class indicates the position of the top-left corner of the screen and is of type Point, (The Point is discussed in Chapter 33, “Graphics with GDI+”.) What you need to know here is that it contains two int values, X and Y,which represent the horizontal and vertical position on the screen, You also look up three member properties of the Form. BackColor property, which is an instance of the Color class: R,G,and B:Color, which represents a color, These properties on it give the red, green, and blue components that make up the color, and they are all of type byte, you also use the Form, WindowState property, which contains an enumeration that gives the current state of the window: Minimized, MAximized, or Normal.
The other complication here is that you need to be a little careful about your casts. SetValue () takes two parameters: a string that gives the name of the key and a System, Object instance, which contains the value SetValue () has a choice of format for storing the value – it can store it as REG_SZ, REG_BINARY,or REG_DWORD- and it is actually pretty intelligent about making a sensible choice depending on the data type that has been given. Hence for the WindowState, you pass it a string, and SetValue () determines that this should be translated to REG_SZ Similarly, for the various positions and dimensions, you supply ints, which will be converted into REG_DWORD However, the color components are more complicated, as you want these to be stored as REG_DWORD too because they are numeric types.However, if SetValue () sees that the data is of type byte, it will store it as a string – as REG_SZ in the registry. To prevent this, you cast the color components to ints.
You have also explicitly cast all the values to the type object You don’t really need to do this because the cast from any other data type to object is implicit, but you are doing this to make it clear what is going on and to remind yourself that SetValue () is defined to take just an object reference as its second parameter.
The ReadSettings () method is a little longer because for each value read in, you also need to interpret it, display the value in the list box, and make the appropriate adjustments to the relevant property of the main form ReadSettings () looks like this:
In ReadSettings () you first have to navigate to the HKLM/Software/WroxPressl
SelfPlacingWindow registry key. In this case, however, you are hoping to find the key there so that you can read it. If it is not there, it is probably the first time you have run the example In this case, you just want to abort reading the keys, and you certainly don’t want to create any keys, Now you use the RegistryKey.
OpenSubKey () method all the way down. If at any stage OpenSubkey () returns a null reference, then you know that the registry key is not there, and you can simply return the value false to the calling code.
When it comes to actually reading the keys, you use the RegistryKey, GetValue () method, which is defined as returning an object reference (meaning that this method can actually return an instance of literally any class it chooses). Like SetValue (),it will return a class of object appropriate to the type of data it found in the key. Therefore, you can usually assume that the REG_SZ keys will give you a string, and the other keys will give you an int. You also cast the return reference from SetValue () accordingly.
If there is an exception, say someone has fiddled with the registry and mangled the value types, your cast will cause an exception to be thrown – which will be caught by the handler in the Forml constructor.
The rest of this code uses one more data type, the Size structure, This is similar to a Point structure but is used to represent sizes rather than coordinates, It has two member properties, Width and Height, and you use the Size structure here simply as a convenient way of packaging the size of the form for displaying in the list box.