The Microsoft Windows Registry

by Mario Giannini

The registry is a shared database amongst all applications to hold configuration and initialization information. The single registry database is provided in Win32 to replace the numerous individual INI files that existed in Win16, including WIN.INI and SYSTEM.INI. While the registry is designed for long-term storage of program configurations and settings, you should not attempt to store information in it better suited for a data file.

The registry can be examined, searched, and altered, with the use of the REGEDIT program, which is a part of both Windows 95 and NT. Normal program operation is to read the registry for information upon startup, and to save data back to it upon shutdown. Note: Using REGEDIT incorrectly, or changing values in it incorrectly, may cause your system, or certin programs, to stop working. Use caution with REGEDIT.

The Registry is a hierarchical database, divided into 4 primary divisions or 'keys' (you can see them using REGEDIT.EXE), though more may be present:

HKEY_CLASSES_ROOT
This category manages classes and relationships. For example, entries exist here for things like file-type associations. This is how Windows knows that when you double-click a filename that ends in .DOC, that it should run Microsoft Word.

HKEY_CURRENT_USER
This registry division identifies the current user's settings, such as their desktop layout, and MRU file lists in applications.

HKEY_LOCAL_MACHINE
Stores information specific to the machine, such as driver and service installations and information. It is shared by all users of the system.

HKEY_USERS
This section identifies default settings for new users, as well as configuration information for the current user.

When a user logs onto Windows, the HKEY_CURRENT_USER tree is initialized with the settings for that user. If you make changes to it in a program, those changes are saved to the persistent settings for that user.  This is the primary location where an application stores its configuration information, and we will therefore concentrate on it for the remained of this document.  Please keep in mind however, that the approaches for dealing with the registry are the same with other keys as well.

HKEY_CURRENT_USER

Within the HKEY_CURRENT_USER section are several sub-sections. Of the sections there, the most interesting are:

Control Panel
Configuration values for items that appear in the control panel, such as the screen saver.

Environment
The user's environment settings.

Software
This is the most important sub-section for most programmers. It includes the configuration data for applications that the current user is running.

HKEY_CURRENT_USER/Software

This key is where your programs store their settings. For organizational purposes, this sub-section is further divided into company names. Here you will notice names like Microsoft, Borland, and Adobe. If your company produces software, then programs that use the registry to store data should create a 'key', or sub-section with your company name here.

Within each company name key, you will see an application name. The application name is also a key or sub-section. Inside this section, you will see the settings used by that program. An application is also free to create sub-keys off of it's own key as desired.

Below is an example of the REGEDIT program, looking at the HKEY_CURRENT_USER/Software/Adobe/PageMill 3.0/RecentFileList key is pictured below. This is how the PageMill program remembers the files that you most recently worked with (they appear in the File menu choice of the PageMill program):

 

Format of RegistrySettings

In the original INI files, sections were formatted similar to the following:
[Section]
Entry=Value

An example might be:
[Paths]
OutputDirectory=C:\Program\Output
InputDirectory=C:\Program\Input

Here, Section identifies a group of setting names and their values. The registry turns the Section into a key, or sub-section. Within a key in the registry you may also have settings and values, or other sub-keys.

You are free to make up whatever Section and Entry names your application might need.

MFC Support for the Registry

MFC provides support for registry access in the CWinApp class. It does so with the following functions:

UINT GetProfileInt( LPCTSTR lpszSection, LPCTSTR lpszEntry,
int nDefault );
CString GetProfileString( LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault = NULL );
BOOL WriteProfileInt( LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue );
BOOL WriteProfileString( LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue );
void SetRegistryKey( LPCTSTR lpszRegistryKey );
void SetRegistryKey( UINT nIDRegistryKey );

The GetProfileXXXX functions permit you to get either a string or integer value from the registry, while the WriteProfileXXXX functions permit you to set them. Note the following:

You can access or create sub-keys by specifying the key sections separated with a \ character. Remember to use the C '\\' escape sequence when in a string. For example:

WriteProfileString( "WebSites\\www", "File1", "www.openroad.org"
);
WriteProfileString( "WebSites\\ftp", "File1", "ftp.openroad.org" );

In the scenario above, we can assume that the program keeps a WebSites key, and then within that key, two sub-keys called www and ftp. Each sub-key has a File1 setting. This approach might be used to keep track of two Most-Recently-Used website lists, one for www sites and one for ftp sites.

Using GetProfileString in the same manner will retrieve those values.

SetRegistryKey

As mentioned earlier, the registry stores application specific information in the HKEY_CURRENT_USER\Software\CompanyName\ApplicationName sub-key. The CWinApp::SetRegistryKey function is used to set this registry key once during program run, and the GetProfileXXXX and WriteProfileXXXX functions will work off that key.

This function is called for you automatically in the CWinApp::InitInstance function for SDI and MDI programs (you must add the call yourself for Dialog-based applications). The default call however, sets the registry key to: "Local AppWizard-Generated Applications". For every project you create, you will want to replace this string with your company's name. For example:

BOOL CWhateverApp::InitInstance()
{
...
SetRegistryKey( "Acme Software" ); // Line you change, or add
...
}

Note: If SetRegistryKey is not called by your application, then GetProfileXXXX and WriteProfileXXXX functions will use an INI file to store their data. Internally, the SetRegistryKey function will set the m_pszRegistryKey and m_pszProfileName member variables of your CWinApp, which is where the GetProfileXXXX and WriteProfileXXXX function get their key data. If you want these functions to look into another key you can set them manually, but you should allocate space for your strings, as the destructor for the CWinApp will delete these two pointes.


Accessing the Registry from your Document or View class

Since the functions above are members of the CWinApp class, they are not members of, and therefore not visible too, your document and view classes. In order to use these functions in that case, you will need to get a pointer to the CWinApp object for your program (each running program has only one) using the AfxGetApp() function.

CWinApp* AfxGetApp( );

With the CWinApp pointer this function returns, you can access the registry from any class. For example:

CWinApp* pMyApp = AfxGetApp();
pMyApp->WriteProfileString( "WebSites\\www", "File1", "www.openroad.org" );

SDK Support for the Registry

The SDK, or Windows API provides 25 functions for directly accessing the Registry. Perhaps the best source of example code for working with the Registry SDK functions is inside the APPUI3.CPP file, in the SRC directory of your Visual C++ installation (if you opted to install source code when you installed VC, which you should have). APPUI.CPP is the source code for CWinApp, and the source code for the SetRegistryKey, and GetProfileXXXX and WriteProfileXXXX functions is in this file.

Like any other resource in Windows, access to the Registry comes via a handle. This handle is of type HKEY. The HKEY handle is first gotten by calling either RegCreateKeyEX or RegOpenKeyEx. Both will open a key handle, but the Create version will create the key of it doesn't exist.

Once a key is opened, you can use the RegQueryValueEx function to retrieve values from it, or RegSetValueEx to set them. When you are finished with a key handle, you close it with RegCloseKey.

The following code demonstrates how to use the API functions to read a value from the registry:

	HKEY hNotePadKey;
char Fontname[128]="N/A";
DWORD DataType;
DWORD DataCount=sizeof(Fontname);
if( RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Microsoft\\NotePad",
0, KEY_READ, &hNotePadKey ) == ERROR_SUCCESS )
{
		if( RegQueryValueEx( hNotePadKey, "lfFaceName",
0, 
&DataType, (unsigned char*)Fontname, &DataCount ) == ERROR_SUCCESS )
{
// The fontname used by notepad is now in the Fontname variable
}
RegCloseKey( hNotePadKey );
}

Adding to MFC, using SDK functions

Support for storing binary information (such as a struct or class) into the registry is missing from MFC. The following functions are examples of how to add this ability to your CWinApp-derived application class:

BOOL CRegApp::WriteProfileBinary(LPCSTR lpszSection, LPCSTR
lpszEntry, void * Src, int Size)
{
HKEY hSectionKey = GetSectionKey(lpszSection);
long Err;
if( hSectionKey )
{
Err=RegSetValueEx( hSectionKey,lpszEntry,0,REG_BINARY,(unsigned char*)Src, Size );
RegCloseKey( hSectionKey );
return( Err==ERROR_SUCCESS );
}
return( FALSE );
}
BOOL CRegApp::GetProfileBinary(LPCSTR lpszSection, LPCSTR lpszEntry, void * Dest, DWORD Size, void * Default)
{
HKEY hSectionKey = GetSectionKey(lpszSection);
long Err;
DWORD Type = REG_BINARY;
if( hSectionKey )
	   {
Err=RegQueryValueEx( hSectionKey,lpszSection,0,&Type,(unsigned char*)Dest,&Size );
RegCloseKey( hSectionKey );
if( (Err!=ERROR_SUCCESS || Type!= REG_BINARY) && Default)
{
memmove( Dest, Default, Size );
return( TRUE );
}
return( Err==ERROR_SUCCESS && Type==REG_BINARY );
}
return( FALSE );
}

Note: the GetSectionKey function is not a documented function, but you will find it in the APPGUI3.CPP file. Also, since these new functions are not part of the CWinApp class, you must now type-cast the return value from AfxGetApp() to the type of CWinApp class object used by your project, in order to use them:

((CMyApp*)AfxGetApp())->WriteProfileBinary( "Settings",
"LastPerson", &Person, sizeof(Person) );
 
    

Visual Basic support for the Registry

VB provides several functions to help you work with the registry. Unlike a Visual C++ program which lets you set your default registry key or folder, VB stores it's settings in the key of HKEY_USERS\ and in a sub folder of a subfolder, called Software\VB and VBA Program Settings. To determine exactly where it is stored, just use the REGEDIT program, and do a search for 'VB and VBA Program settings.

Within that key, you will find settings for individual programs or projects.

The functions that VB gives you to work with the registry, are:

GetAllSettings(appname, section)
GetSetting(appname, section, key[, default])
SaveSetting appname, section, key, setting
DeleteSetting appname, section[, key]

Here, appname refers to the name of your program, and the key or folder that will be off the VB and VBA Program settings key. Section is the value to get, and may also specify a path to a separate key, such as "Paths\ErrorLog" or "Startup\ScreenSize".

So, if you wanted to store the position of your main window, at program shutdown so that it would start up in the same place, you could do:

Private Sub Form_Activate()
Dim X As Integer
X = Val(GetSetting("MyApp", "Startup",
"Left", -1))
If X <> -1 Then Form1.Left = X
X = Val(GetSetting("MyApp", "Startup", "Width", -1))
If X <> -1 Then Form1.Width = X
X = Val(GetSetting("MyApp", "Startup", "Top", -1))
If X <> -1 Then Form1.Top = X
X = Val(GetSetting("MyApp", "Startup", "Height", -1))
If X <> -1 Then Form1.Height = X
End Sub
Private Sub Form_Unload(Cancel As Integer)
SaveSetting "MyApp", "Startup", "Left", Form1.Left
SaveSetting "MyApp", "Startup", "Width", Form1.Width
SaveSetting "MyApp", "Startup", "Top", Form1.Top
SaveSetting "MyApp", "Startup", "Height", Form1.Height
End Sub

If using the VB and VBA Program settings key defined by VB isn't what you want to do, you will need to use the Windows API functions, as described in the SDK Suppoer for the Registry section above.