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