Using the Registry in a C++ Application

 

In the old days of Microsoft Windows development, application settings were stored in profile files that typically ended in an .INI extension. There are still remnants of the old profiles, and desktop Windows installations contain a SYSTEM.INI file even now. However, modern applications use the system registry to store configuration information.

Applies to:
   Microsoft Windows Powered Pocket PC 2000
   Microsoft eMbedded Visual C++ version 3.0 or later
   Optionally, free VORegistry class files from Virtual Office Systems, Inc

Languages Supported

English.

Registry Basics

You can get a good idea of the layout of the registry using the Microsoft Windows CE Remote Registry Editor that ships with Microsoft eMbedded Visual Tools 3.0 (see Figure 1). Without spending hours going over every detail, the essential things you'll need to know about the registry are:

  1. The registry is organized as a tree, with any number of child nodes branching off from a few top-level nodes.
  2. One of the top-level nodes you will care about is called HKEY_LOCAL_MACHINE and all users of the physical device share it. Typically settings that will be the same for any user of an application (i.e., an IP address, etc.) are stored in HKEY_LOCAL_MACHINE.
  3. The other top-level node you will use is called HKEY_CURRENT_USER. Although the current version of Windows CE treats this identically to HKEY_LOCAL_MACHINE (because there is not currently a way to "log on" to a Pocket PC and have multiple users) you should still be familiar with the concept that HKEY_CURRENT_USER will be different for each user. This is a good place to store individual preferences such as colors and fonts.
  4. Within each key, there can be any number of values. These values can be strings, numbers, or binary information. Although you can store anything in a binary value, it is recommended that nothing over 2 KB in size be stored in the registry, as it is designed to track many small values instead of as a repository for bitmaps, etc.

Click here for larger image

Figure 1: Windows CE Remote Registry Editor.

Creating or Opening a Registry Key

Before you can read or write to a key, you must first obtain a handle to it. To do this, use either the RegOpenRegKeyEx or RegCreateKeyEx Microsoft Win32 functions. In practice, you will almost always use RegCreateKeyEx, which will open the key if it exists or create it if it does not. Here is a typical scenario:

  1. Declare an HKEY variable in your code.
  2. Call RegCreateKeyEx, passing HKEY_LOCAL_MACHINE as the parent key and Software/YourCompany/YourApplication as the subkey.
  3. For each setting you wish to read, call RegQueryValueEx, and if the setting is not found set a default value.
  4. Close the handle to the key with RegCloseKey.

Sample code:

void CMyFirstMFCApplicationApp::LoadPreferences()
{
 HKEY   hkey;
 DWORD  dwDisposition;
 
 DWORD dwType, dwSize;
 
 // Set the default values
 m_dwMaxFileSize = 16 * 1024;         // 16k
 _tcscpy(m_szLastFileName, TEXT("Datafile.TXT"));
 
 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\My Company\\My 
        Application"), 0, NULL, 0, 0, NULL, &hkey, &dwDisposition)== 
        ERROR_SUCCESS)
 {
  dwType = REG_DWORD;
  dwSize = sizeof(DWORD);
  RegQueryValueEx(hkey, TEXT("MaxFileSize"), NULL, &dwType, 
        (PBYTE)&m_dwMaxFileSize, &dwSize);
        
  dwType = REG_SZ;
  dwSize = sizeof(m_szLastFileName);
  RegQueryValueEx(hkey, TEXT("LastFileName"), NULL, &dwType, 
        (PBYTE)&m_szLastFileName, &dwSize);
 
  RegCloseKey(hkey);
 }
}void CMyFirstMFCApplicationApp::SavePreferences()
{
 HKEY   hkey;
 DWORD  dwDisposition;
 
 DWORD dwType, dwSize;
 
 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\My Company\\My 
        Application"), 0, NULL, 0, 0, NULL, &hkey, &dwDisposition)== 
        ERROR_SUCCESS)
 {
  dwType = REG_DWORD;
  dwSize = sizeof(DWORD);
  RegSetValueEx(hkey, TEXT("MaxFileSize"), 0, dwType, 
        (PBYTE)&m_dwMaxFileSize, dwSize);
 
  dwType = REG_SZ;
  dwSize = (_tcslen(m_szLastFileName) + 1) * sizeof(TCHAR);
  RegSetValueEx(hkey, TEXT("LastFileName"), 0, dwType, 
        (PBYTE)&m_szLastFileName, dwSize);
 
  RegCloseKey(hkey);
 }
}

Using VORegistry (Optional)

Virtual Office Systems has provided a free C++ class library to encapsulate basic registry functions. This class creates and closes the registry handles; reads and writes string and DWORD values to and from the registry; and enumerates the child keys (if any) of any key in the registry. MFC (Microsoft Foundation Classes) are required when using VORegistry, since the string values are returned as CString objects.

Typically, using VORegistry is much simpler than making the Win32 calls yourself. To use VORegistry in your application:

  1. Add a data member of type CVORegistry to your application's main C++ class.
  2. In the constructor of your application's main class, pass the parent and subkey names to the CVORegistry object
  3. Call the ReadString, ReadDWORD, WriteString, and WriteDWORD methods of the CVORegistry class whenever you need to load or save settings.
  4. Call the GetFirstSubkey method followed by a looping call to GetNextSubKey to enumerate any child keys from the current key.

Sample Code:

CMyFirstMFCApplicationApp::CMyFirstMFCApplicationApp() :
        m_reg(HKEY_LOCAL_MACHINE, TEXT("Software\\My Company\\My Application"))
{
}
 
void CMyFirstMFCApplicationApp::LoadPreferences()
{
        m_dwMaxFileSize = m_reg.ReadDWORD(TEXT("MaxFileSize"), 16 * 1024);
        m_strLastFileName = m_reg.ReadString(TEXT("LastFileName"), TEXT("Datafile.TXT"));
}
 
void CMyFirstMFCApplicationApp::SavePreferences()
{
        m_reg.WriteDWORD(TEXT("MaxFileSize"), m_dwMaxFileSize);
        m_reg.WriteString(TEXT("LastFileName"), m_strLastFileName);
}

As you can see, using VORecordset simplifies the code greatly, and eliminates the need to worry about closing the registry key when you are finished with it, because this is done automatically when the object is destroyed.

Conclusion

By using the system registry, either directly through the Win32 calls, or indirectly through VORegistry or a similar class library, your application can store all of its configuration and user preferences in a common, reliable location.