The Registry


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.

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.

As a programmer, your primary use of the registry, will be to store configuration information about your application. You will also at times be interested in working with the associations in HKEY_CLASSES_ROOT, particularly when dealing with writing COM programs. We will therefore concentrate on those two divisions.


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.


Format of Registry Settings
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.

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 \\ 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) );