Registry Access with Visual C++


The System Registry - A Brief Description

The Windows Registry was added to Windows NT 3.51 and Windows 95 (and it has been incorporated in all subsequent MicroSoft operating systems), as a central repository for application settings. Prior to the advent of the registry, each application stored its settings in an initialization (or INI) file, often (but not always) located in the System folder.

The registry is organized in an hierarchical format comprised of keys, entries and their associated values. Each key may contain one or more sub-keys (also known as keys) which in turn may contain additional sub-keys, entries and values. If you are confused, then the next few paragraphs will either lose you forever, or make it all crystal clear...

If you take a look at Windows Explorer (or Windows NT Explorer), you'll see an hierarchical arrangement (tree) in the left-hand pane indicating the drives and folders on your computer. The right-hand pane will display a list of drives, folders and files. The registry has an application that is roughly the equivalent of Windows Explorer, known as Regedit (the registry editor). Assuming you have access to the system registry, you can launch regedit by Clicking the "Start" button, and clicking "Run..." in the start menu. When the dialog appears, type "regedit" (with or without the quotes) and click "OK"

PLEASE NOTE: You can do serious and possibly irrepairable damage to your computer by tampering with the registry. Unless you are absolutely certain that you know what you are doing, do not add, change or delete anything in the registry using regedit.

Chart 1: Comparison of Windows Explorer to the System Registry
Windows Explorer
Windows Registry
Item
Description
Item
Description
Drives Your computer may contain one or more disk drives Parent Key The registry contains exactly six parent keys (described below)
Folder Each drive on your computer may contain one or more folders. Each of these folders may themselves contain additional folders. Child Key (or sub-key) Each parent key may contain one or more child keys. Each of these may themselves contain additional sub-keys.
File Within each folder there may exist one or more files. Entry Each key may contain a number of entries, some contain no entries at all (makes me wonder why they are even there).
File Data Each file will contain some sort of data. It could be text data in a text or INI file, or it could be binary data representing image information, database data, spreadsheet data... Value Each entry will have one value associated with it. The value can be in one of three formats:
  • Binary data (an array of bytes)
  • Numeric data (an unsigned integer value)
  • Text data (a string of characters)

There is one additional similarity between Windows Explorer and Regedit; at the root of both is "My Computer," not actually a key, but I guess they had to start somewhere... Under "My Computer," are the Parent Keys (listed and described in the chart that follows).

Chart 2: Description of the Parent Keys in the System Registry
Key Name Description
HKEY_CLASSES_ROOT This key contains two categories of items
  1. Registered file extension mappings that indicate which application should be launched when someone double-clicks on a file. The O/S looks up the file extension in this key, determines which program needs to be executed and then launches that application passing the file as a parameter.
  2. Registered document type descriptions. In Windows Explorer (or Windows NT Explorer), when you browse a folder AND Explorer is displaying file information in Detail format, you get a textual description of every file. The O/S uses the descriptions contained in the registry to provide that output in Explorer.
HKEY_CURRENT_USER This key contains a number of sub-keys, too numerous and varied (depending upon O/S and the user's configuration) to list here. The one sub-key worth mentioning is Software
The Software sub-key contains numerous additional sub-keys (I'll give a detailed description of the software key(s) later in this document).
HKEY_LOCAL_MACHINE This key contains a number of sub-keys including Hardware, Software and System (there are others as well) each of which contains additional sub-keys, entries and values.
  • The hardware key has information regarding the current hardware configuration of your computer
  • The software key is similar to the key by the same name under HKEY_CURRENT_USER (it will also be described later).
  • The system key has information about the capabilities of the hardware and software - specifically configuration data.
HKEY_USERS This key contains a number of sub-keys, each of which describes a registered user of the computer.
HKEY_CURRENT_CONFIG Another key that contains a Software sub-key along with a System key. There may be additional keys here as well. Whenever a new user logs on to a computer, that user's configuration settings are swapped into this parent key.
HKEY_DYN_DATA As the name describes, this key contains application specific, dynamic data that can change while a program is running.

Each application may have a number of keys, entries and associated values stored in the registry. The exact location will depend upon a number of factors, you can use these to help you determine where to store your application data.

As I indicated above, here is a description of the Software sub-keys. Every application that stores information in the registry will have a sub-key under one of the Software keys. However, some applications' sub-keys aren't directly under Software, they may be nested within other sub-keys. For example, large software vendors - especially those who have developed numerous applications - will have a sub-key for their company. The companies sub-key will contain additional sub-keys, one for each application that is installed on the computer.

Other software vendors (usually the smaller ones) will have a specific sub-key under one of the software keys for each application they've released. Some will use the software key under HKEY_CURRENT_USER, others will use HKEY_LOCAL_MACHINE and still others will use both. The information that follows is a guide to help you decide which of the Software keys you should use.

If you are developing an application that has user-specific settings, or will be registered to a person (rather than a computer), then you probably want to store your registry information in HKEY_CURRENT_USER\Software. If each user of your application will require a license to operate your program - an ideal place to store the registration info would also be under HKEY_CURRENT_USER\Software (you'd probably want to encrypt the data in some form).

If your program has settings that are independent of the number of users then that information may be stored under HKEY_LOCAL_MACHINE\Software. For instance, for an internet-aware application, the ports that should be used to access the internet could be stored here. If your program uses specific dynamic link libraries, on installation of your program you can search for their location and store the paths in the registry.

Make a determination either while developing or before developing your program as to the best location for your registry information. If you plan on distributing numerous applications, you might want to consider creating a key for all apps developed by your company. Then, create a sub-key (under the company key) for each application.


Programming Registry Access in Visual C++

At the time of this writing (April, 2000), there is are no known classes in the MFC hierarchy for accessing the registry. That does not mean that there are no classes, just that they aren't MFC classes. In the Active Template Library (or ATL - another class hierarchy from Micro$oft) there lives a class called CRegKey. This class provides some basic access to the registry allowing you to create and/or access keys, sub-keys, entries and values. Although not one of the MFC classes, you can still use it within MFC projects as long as you include the appropriate header.
    #include <AtlBase.h>

Although there are numerous member functions of this class, I'm going to focus on only a few - the ones you'll most likely need to store your application settings. Those functions are:


Open

LONG CRegKey::Open( HKEY hKeyParent, LPCTSTR lpszKeyName, REGSAM samDesired = KEY_ALL_ACCESS )

The Open function gives access to a key within the registry if the key exists. This function (or the Create function) must be called prior to setting or querying any values contained in the registry.

The following code snippet will grant read access to a key called "MyProgram", assuming the key exists:
    // This is how you'd get access to the registry for reading information
    CRegKey key;
    long nError = key.Open(HKEY_CURRENT_USER, "Software\\MyProgram", KEY_READ);
    if(nError == ERROR_SUCCESS)
    {
        // Code here to read values from MyProgram key
    }

Create

LONG CRegKey::Create( HKEY hKeyParent, LPCTSTR lpszKeyName, 
    LPTSTR lpszClass = REG_NONE, DWORD dwOptions = REG_OPTION_NON_VOLATILE, 
    REGSAM samDesired = KEY_ALL_ACCESS, LPSECURITY_ATTRIBUTES lpSecAttr = NULL, 
    LPDWORD lpdwDisposition = NULL )
The Create function performs essentially the same task as the Open function except that if the key does not already exist, it will create it.

Rather than describe all the parameters here (you can find a full description at MSDN online), I'll only describe the ones most often used.

I would recommend using the Create function rather than the Open function when you need to store information in the registry. The first time your application runs, chances are that the registry keys used by your application do not yet exist. Since the Open function fails if the key doesn't exist, the Create function is better suited for writing data.
    // This is how you'd get access to the registry for writing information
    CRegKey key;
    long nError = key.Create(HKEY_CURRENT_USER, "Software\\MyProgram");
    if(nError == ERROR_SUCCESS)
    {
        // Code here to write values to MyProgram key
    }

SetValue

LONG CRegKey::SetValue( DWORD dwValue, LPCTSTR lpszValueName )
LONG CRegKey::SetValue( LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL )
This function has been overloaded to allow storage of two different types of data; DWORD (an unsigned integer) and LPCTSTR (null-terminated character strings). In Chart 1 above, I indicated that three types of values can be stored in the registry, however CRegKey only provides support for two of them (there is currently no class-based support for storing binary data in the registry). Once you have access to a key within the registry, use this function to create or store entries and their values.
    CString sDefaultPath = "C:\\Program Files\\MyProgram\\";
    CString sPathEntry = "Default Directory";
    key.SetValue(sDefaultPath, sPathEntry);
    int nWindowWidth = 640;
    CString sWidthEntry = "Window Width";
    key.SetValue(nWindowWidth, sWidthEntry);

QueryValue

LONG CRegKey::QueryValue( DWORD& dwValue, LPCTSTR lpszValueName )
LONG CRegKey::QueryValue( LPTSTR szValue, LPCTSTR lpszValueName, DWORD* pdwCount )
As with the SetValue function, this function is overloaded to allow the retrieval of two types of data: DWORD (unsigned integer) and LPTSTR (null-terminated character strings). Once you have read access to the registry, you can use this function to retrieve information contained in keys.
    CString sDefaultPath, sPathEntry = "Default Directory";
    DWORD dwBufferSize = MAX_PATH;
    key.QueryValue( sDefaultPath.GetBuffer( dwBufferSize ), sPathEntry, &dwBufferSize );
    sDefaultPath.ReleaseBuffer();
    int nWindowWidth;
    CString sWidthEntry = "Window Width";
    key.QueryValue( (DWORD&)nWindowWidth, sWidthEntry );

Close

LONG CRegKey::Close(void)

There are no parameters required for this function. After you've finished accessing the registry, you should call the Close function to release control of the registry.


There are additional functions that allow you to enumerate and delete keys and sub-keys. Ideally, your uninstall program would use these functions to remove any keys you created (on setup) so that the registry doesn't get too bloated.

For additional information on the CRegKey class, refer to the online documentation at http://msdn.microsoft.com/library/devprods/vs6/visualc/vcmfc/_atl_cregkey.htm