A Class For Handling The Registry

Changes in Revision 2
Changes in Revision 3
Changes in Revision 4
Changes in Revision 5
Usage
Download

Often one can read in the newsgroups, that someone is looking for an MFC class that encapsulates the registry. In fact, MFC does not provide such a class. As long as one has no need to work with the registry in another location than HKEY_CURRENT_USER\Software\[<company>\]<product>, one can use CWinApp::GetProfile*() and CWinApp::WriteProfile*().

If one wants to use the registry more flexible, then one has to use the API-functions with their dozens of parameters. I don't know why MS doesn't provide a registry class in MFC - that would be quite easy ...

The CRegistry class I've developed allows one to use the registry in a simple way. In addition to the basic operations (loading and storing data), the class provides some more features. For instance one can walk the registry tree and perform some operations on any key/value-hit. Furthermore the class encapsulates differences between NT and Win95 (Aeh - you guessed that the Win32 API should be identical on both systems? Yes - the API is identical, but the performed action is not! Take a closer look at the description of the RegDeleteKey() function for instance.)

To handle all the different data types one can put into the registry, the CRegistry class uses an information holder class CRegVal. If you have to load a string from
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\WinLogon\DefaultUserName
you can do it as follows:

CString strKey = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon");
CRegistry reg(HKEY_LOCAL_MACHINE);  // otherwise it defaults to HKEY_CURRENT_USER
CString strDefaultUserName;
CRegVal regval;
if( reg.LoadKey(strKey, TEXT("DefaultUserName"), regval) )
        if( regval.GetValue(strDefaultUserName) )
                // yep - got the name
Simple datatypes (numbers and strings) will be supported directly by the CRegistry class, so you can write the sample above as follows:
CString strKey = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon");
CRegistry reg(HKEY_LOCAL_MACHINE);  // otherwise it defaults to HKEY_CURRENT_USER
CString strDefaultUserName;
if( reg.LoadKey(strKey, TEXT("DefaultUserName"), strDefaultUserName) )
        // yep - got the name
... but, if CRegistry::LoadKey() returns FALSE, this makes it harder to check whether the type of the registry key is wrong or the entry does not exist.

CRegistry doesn't support security (but that was no handicap for me so far :-)
 

Changes in Revision 2

You can use Registry.cpp if you want to use the registry classes in a non-MFC application and RegMFC.cpp in an MFC-based application. RegMFC.cpp will support some more methods for use with MFC.
For a build with MFC, you have to insert both files (Registry.cpp and RegMFC.cpp) into your project, but to exclude Registry.cpp from build.
In a non-MFC build you have to include Registry.cpp into your project only. In this case you don't need RegMFC.cpp.
Normally Registry.h detects whether you build an MFC version or not. If you want to build a non-MFC version in all circumstances, you can #define _REG_NO_MFC_BUILD.
Furthermore you can #define _REG_NO_TREEWALK to shrink the size of the resulting object files. This #define hides the CRegistry::RegistryTreeWalk() function and its associates. Use the _REG_NO_TREEWALK if you sure know, that you don't need the RegistryTreeWalk() method and want to reduce the code of your application/dll.
If you plan to use the CRegistry class in a non-MFC project you really should #define STRICT to make sure the class behaves correct in all circumstances. This is absolutly necessary, if you insert the class in a non-MFC dll that might be used in a MFC application.
CRegistry now is ready for use with UNICODE.

Changes in Revision 3

  • The RegistryTreeWalk() method no longer reports a wrong  "depth" to the methods OnValueHit() and OnKeyHit().
  • The member USHORT m_usDepth was deleted
  • eliminated a memory leak in DeleteKey()  (thanks to Tobias Krueger)
  • several bugfixes in DeleteKey() (sent in by Tobias Krueger)

 Changes in Revision 4

  • Some of the CRegVal::SetValue() methods changed. Most changes are for UNICODE applications (allocated too less memory). CRegVal::SetValue(const CStringArray &) is the only method that changes even for non-UNICODE applications. If you write CStringArrays to the registry, you really should upgrade to this revision!

Changes in Revision 5

  • Bug fixed in the RegTreeWalk-function (thanks to Pieter E. Roos and Daniel G. Hyams): The RegEnumValue()  function returns the number of bytes read in the last parameter. Since that value is stored in the CRegVal helper class, the next time RegVal was used to receive information from RegEnumValue(), RegEnumValue() thought that the buffer that it can put data in is smaller than it really is.
  • The sample is now a VC 6 project (sorry to all of you, who have only older versions of VC - but I have to be up to date ...)

Usage

If you want to use the class in a MFC environment, you have to include all three files to your project, but to exclude Registry.cpp from build. To do so, right-click the file in the FileView of the workspace window and select Settings ... . Make sure you select All Configurations. Now select the General page and check the field Exclude file from build.
In a pure Win32 project you will need Registry.[h|cpp] only.

CRegistry consists of three files:
Registry.h
Registry.cpp
RegMFC.cpp
Download Source 12 KB
Download Sample Project 28 KB

Date Last Updated: February 3, 1999



Comments

  • This class is not thread safe. Wait for Revision 6.

    Posted by mmoore on 04/29/2009 02:15pm

    In http://msdn.microsoft.com/en-us/library/ms724836(VS.85).aspx we find this: "The predefined handles are not thread safe. Closing a predefined handle in one thread affects any other threads that are using the handle." This means that it is not legitimate to call RegCloseKey on a predefined handle such as HKEY_LOCAL_MACHINE, but this class will do that if you create a class object with a predefined key. This causes intermittent failures of registry access in other threads of the same application. We are trying to notify the author of this problem and we are confident he will shortly provide revised code.

    • Work-around until Revision 6.

      Posted by KevinSorensen on 04/29/2009 02:26pm

      In the meantime we do the following before every RegCloseKey( hKey_p ) call:
      
      if (!IsPredefined( hKey_p ))
         RegCloseKey( hKey_p );
      
      Where IsPredefined is the following:
      BOOL CRegistry::IsPredefined( HKEY hKey )
      {
         return ((hKey == HKEY_CLASSES_ROOT) ||
                 (hKey == HKEY_CURRENT_CONFIG) ||
                 (hKey == HKEY_CURRENT_USER) ||
                 (hKey == HKEY_LOCAL_MACHINE) ||
                 (hKey == HKEY_PERFORMANCE_DATA) ||
                 (hKey == HKEY_PERFORMANCE_NLSTEXT) ||
                 (hKey == HKEY_PERFORMANCE_TEXT) ||
                 (hKey == HKEY_USERS));
      }

      Reply
    Reply
  • Question marks at end of retrieved strings

    Posted by Bob H on 11/06/2006 12:02pm

    I am getting question marks at the end of retrieved strings. I believe it is only occurring when the build is unicode. Example: // value is set sValue = m_sPrevFontName; // value is "Arial" User.SaveKey(sKey, TEXT("PrevFontName"), sValue); // value is retrieved if (User.LoadKey(sKey, TEXT("PrevFontName"), sValue)) m_sPrevFontName = sValue; now sValue is "Arial???????"

    Reply
  • Why can't i get REG_DWORD (Numbers) data from the registry?

    Posted by Legacy on 07/15/2002 12:00am

    Originally posted by: Thorin

    I can get strings from the registry but not numbers... any clues as to why?? Or is there any way i can convert CRegVal to an int?

    Reply
  • Great Job

    Posted by Legacy on 05/24/2002 12:00am

    Originally posted by: Douglas Brook

    I just wanted to get one key out of the HKEY_LOCAL_MACHINE key and I was banging my head against my desk trying!
    
    

    Then I searched the web, found this class, installed it and literally one minute later I had my key.

    Reply
  • Unable to do RegTreeWalk Walkin

    Posted by Legacy on 12/13/2001 12:00am

    Originally posted by: Will'o the Wisp

    Well im not able to get a Tree...
    i.e.: Im Checking HKEY_CURRENT_USER

    Software\\ANY

    this key has 2 subkeys (any1 and any2)... i want to read
    them out so that i can save them in a temp string to
    call them later please help!

    thanx!

    Reply
  • Can I use CRegistry class in Windows CE?

    Posted by Legacy on 12/28/2000 12:00am

    Originally posted by: Rex Valderama


    How can i port this class in Windows CE environment? I was trying to include the files in a project and some Functions are not supported by WinCE.
    Any help would be appreciated.

    Reply
  • Resource not being freed.

    Posted by Legacy on 09/29/2000 12:00am

    Originally posted by: Sanjeev Kapoor

    There is a memory leak in CRegistry ::RegTreeWalk, you need to insert the following line
    
    

    RegCloseKey( hKey_p ) ; // SK 290900

    at about line 337, if OnKeyHit() breaks the tree walk.

    Otherwise, I am glad to download these classes for my work.

    Gute Arbeit!

    Sanjeev Kapoor

    Reply
  • sample has some errors.

    Posted by Legacy on 05/26/2000 12:00am

    Originally posted by: kwon-myongjin

    one error and two warnning.

    in the registry.cpp

    comfiler says.

    i am a beginner.

    Reply
  • UNICODE bug - buffer not properly terminated

    Posted by Legacy on 03/24/2000 12:00am

    Originally posted by: Armin Balke

    Hi,

    there is a problem with writing UNICODE strings.
    If I use

    CRegVal :: SetValue( LPCTSTR pszValue_p, BOOL bExpanded_p )

    this line:
    m_pbyteData[ dwSize ] = TEXT('\0') ;

    does only set the byte one bevor the last byte. The last byte will stay undefined. As those kind of line occure multiple times in the code, it should be better to modify

    BYTE * CRegVal :: AllocateDataBuffer( DWORD dwSize_p )

    so that all byte in the buffer will be initially set to zero. Look at the code below:

    BYTE * CRegVal :: AllocateDataBuffer( DWORD dwSize_p ) {
    if( m_pbyteData )
    HeapFree( m_hHeap, 0, m_pbyteData ) ;
    m_pbyteData = (BYTE *) HeapAlloc( m_hHeap, HEAP_ZERO_MEMORY, dwSize_p ) ;
    if( ! m_pbyteData ) {
    TRACE0( "CRegVal::AllocateDataBuffer(): HeapAlloc() system call failed.\n" );
    }
    m_dwDataSize = dwSize_p ;
    return m_pbyteData ;
    }


    Reply
  • I�m also interested in connections to a remote registry...

    Posted by Legacy on 12/15/1999 12:00am

    Originally posted by: Jaime

    I can't get the way for connecting a remote registry, nor using the RegConnectRegistry() API function, neither using a wrapper class that i'm trying to implement. What is wrong in a call to the API functions that looks

    RegConnectRegistry( _T( "\\\\MyMachine\\"), hParentKey, &hKey )
    ???

    I would like somebody to help me, thank you

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date