Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / MFC
Article

Simple registry class Enhancement

Rate me:
Please Sign up or sign in to vote.
3.50/5 (10 votes)
15 May 2002CPOL5 min read 82.4K   2.5K   17   8
A simple class which simplifies working with registry values and history items lists.
Before Run After Run
Before Run After Run
Data stored in system registry
Stored data in Registry

Purposes of class

Cache

The purpose of this class is to simplify working with registry data. To make the class more useful I made two things: create internal cache and create default data store of registry values. The first feature is used to boost performance of registry access. The second feature used in the case when the application, which will use this class, starts the first time on the computer and doesn't find its own registry values. In such case the default values will be in the class cache and on access the application will have only default values. These simplify installation of applications on new computers and also give an easy way to configure the application. Default values will be rewritten by the class if variables of the same name are found in the registry.

Advantages

The class gives easy to use access to the system registry and simplifies most common tasks.
The class gives a great performance boost when accessing registry data often.
Class gives easy access to history data.
There is also simple error detection.

Disadvantage

All values are stored into the registry as string data.
Only one level of subkeys are scanned by the RefreshContents() function. (it can be redefined by inherited classes)

Implementation Notes

For the implementation of internal cache std::map<std::string, std::string> was used. In it the class stores values found by the registry path set on the class construction call. The Class scan the registry path for subkeys and store them into cache like DOS paths. Values on the upper level of registry can be easily accessed by its name, other values found in subkeys can be accessed by path.
Example:

/* Registry access example */
registry.GetValueByName( "value-Name", strValue ); // upper level variables
registry.GetValueByName( "stldbg_optdlg\\autoexpand", strValue ); // subkey value access
If you try to get a variable value, and the variable is not yet in cache, then the access functions will return NULL string or Zero Long value. The class doesn't create any notification by which can be detected if it tries to access a non existing variable. In most cases this is not needed at all.
All values are first stored only in the cache, and only after a call to RefreshRegistry() function will they be stored in the  system registry. As you understand RegistryEx class can be used to share data between many dialogs or classes. That is why its most useful to make RegistryEx class instance singleton in application.

In using the cache there are some exceptions: on calling the delete functions, values are deleted from the system registry and from the cache too. That is why the delete functions can work a little slower then access functions. Also on application crash the data will not be stored into the registry, but data will be deleted as well. To make the application safe when working with the registry it is recommended to call the RefreshRegistry() function after each significant change of registry values. Update of system registry is not well optimized, it's simply created values and subkeys according to cache content.

Default Values

Default Values in class are created by virtual function SetDefaults(). By default class CRegistryEx does not have any implementation of this function. Function is defined with protected access and can be only redefined by inherited classes. This function is called by RefreshContents() function before trying to read system registry. In example you can saw redefinition of SetDefaults() function. To simplify work with class cache any class which inherit CRegistryEx will have free access to it. Developer can choose which style of access he/she wants to use: direct access or throw Accessor functions.

How to use it

CRegistryEx - is a utility class which can be used in MFC or WTL(Win32) projects to store and set values into system registry. Most interested feastures of class are:

  • On Init CRegistryEx class read all values from registry and stores them into cache. Also in cache added all one level lower sub-folders. That feature limits memory usage and give easier way to use registry settings.
Example:
  We have such structure of registry:
  HKEY_LOCAL_MACHINE            ( folder )
    + Software                  ( folder )
      + MyApplication           ( folder )
        + Dialog1               ( folder )
        + Dialog2               ( folder )
        + Dialog3               ( folder )
          + Additional Settings ( folder )

Into code must be added:

CRegistryEx registry( HKEY_LOCAL_MACHINE, "software\\MyApplication" );
try
{
  registry.RefreshContents();
}
catch( string err )
{
  cout << err.c_str();
  exit(-1);
}

After such calls in CRegistryEx class cache will be stored values of such folders: MyApplication, Dialog1, Dialog2, Dialog3. "Additional Settings" folder values will not be read.

User can get access to values using functions:

  • Read:
    • GetValueByName
    • GetArrayByTemplate
    • GetArrayByArray
  • Write:
    • SetValueByName
    • SetValueByTemplate
    • SetArrayByArray
  • Delete:
    • DeleteByName
    • DeleteByTemplate
    • DeleteByArray

In the case when value is not in registry then when the READ functions is called it will return NULL length string or LONG value equal to 0. To add a value into the registry simple call WRITE functions and all values will be modified or added. To Refresh the cache from the registry use the function RefreshContents(). To Store all values into the registry use the function RefreshRegistry().

Array and Template Works

Templates are used to store a list(array) of values into the registry. Template can specify variables with only one diff - order number. Template have printf function format. Into Template can be added only one %d marker, otherwise will be stack corruption...

NOTE: Template is a very useful feature to store and restore history of dialogs settings.

All values on WRITE functions calls will be renumbered and stored with new name. That is why before calling WRITE functions call DELETE function to clean registry from old values.
Example:
void CStringClipBoard::SetInitSettings()
{
  CInitDialogImpl::SetInitSettings();
  /* ...  */
  m_pRegistry->DeleteByTemplate( "findhistory\\history%d" );
  m_pRegistry->SetValueByTemplate( "findhistory\\history%d", m_arrHistory );
};
After function call in registry will be added variables like:
history1
history2
history3
...
historyN
into subkey findhistory...

NOTE: in class for variables names can be used only symbols in lower case otherwise value will not be found in CRegistryEx class cache.

Values automatically will be added into registry on destructor call.

Example Description

Let's define our own class which will inherit from the CRegistryEx class and redefine the SetDefaults function of it. Then let's add a function which will list the internal cache.

class CRegistryDemo : public CRegistryEx
{
  public:
    explicit CRegistryDemo( HKEY key, const string &path ) : CRegistryEx( key, path ){};
    void PrintCacheContent( void )
    {
      const TRegMap &maps = GetRegistryMap();
      TRegMap::const_iterator iter;

      for( iter = maps.begin(); iter != maps.end(); iter++ )
      {
        printf( "Path == %s\nValue == %s\n", iter->first.c_str(), iter->second.c_str() );
      }
    };

  protected:
    virtual void SetDefaults( void )
    {
      // find dialog
      m_mapValues[ "\\limit" ] = "20";
      m_mapValues[ "\\matchcase" ] = "0";
      m_mapValues[ "\\regexp" ] = "0";
      m_mapValues[ "\\up" ] = "0";
      
      // search file extensions
      m_mapValues[ "keywords_optdlg\\extensions" ] = ".cpp;.hpp;.hxx;.cxx;.c;.h;";
      
      // keywords list
      m_mapValues[ "search\\search1" ] = "// NOTE: ";
      m_mapValues[ "search\\text1" ] = "Carefully read notes about code";
      m_mapValues[ "search\\search2" ] = "// TEST: ";
      m_mapValues[ "search\\text2" ] = "Carefully read test comments";
      
      // parse thread timeout
      m_mapValues[ "sorting_optdlg\\parsetime" ] = "10000";
      m_mapValues[ "sorting_optdlg\\showtime" ]  = "20000";
      
      // STL debug dialog
      m_mapValues[ "stldbgdlg\\autoexpand" ] = "400";
      m_mapValues[ "stldbgdlg\\limit" ] = "20";
      
      // stl debug options
      m_mapValues[ "stldbg_optdlg\\autoexpand" ] = "1";
      m_mapValues[ "stldbg_optdlg\\autotype" ] = "1";
      m_mapValues[ "stldbg_optdlg\\showsymbolchange" ] = "0";
      m_mapValues[ "stldbg_optdlg\\symbolchange" ] = "1";
    }
};

After creation of our own class our main() function will look like:

// set start point of registry class
CRegistryDemo registry( HKEY_CURRENT_USER, "Software\\RegistryEx Test" );

try
{
  // Refresh class cache from registry
  registry.RefreshContents();
}
catch( string error )
{
  printf( "Error: %s", error.c_str() );
  exit( -1 );
}

LONG lTest1;
string strTest1;

// simple access to registry values
registry.GetValueByName( "stldbgdlg\\autoexpand", lTest1 );
registry.GetValueByName( "search\\text1", strTest1 );

printf( "autoexpand value = %d\ntext = %s", lTest1, strTest1.c_str() );

registry.PrintCacheContent();

// NOTE: on CRegistryEx class destructor call, all values will be saved
// to registry according to specified paths...

return 0;

History

v1.0 First this class was implemented and used in Visual Studio Add-in: "ToDoList Add-on".
v1.1 Current version published now.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO ArtfulBits Inc.
Ukraine Ukraine
Name:Kucherenko Oleksandr

Born:September 20, 1979

Platforms: Win32, Linux; - well known and MS-DOS; Win16; OS/2 - old time not touched;

Hardware: IBM PC

Programming Languages: Assembler (for Intel 80386); Borland C/C++; Borland Pascal; Object Pascal; Borland C++Builder; Delphi; Perl; Java; Visual C++; Visual J++; UML; XML/XSL; C#; VB.NET; T-SQL; PL/SQL; and etc.

Development Environments: MS Visual Studio 2001-2008; MS Visual C++; Borland Delphi; Borland C++Builder; C/C++ any; Rational Rose; GDPro; Together and etc.

Libraries: STL, ATL, WTL, MFC, NuMega Driver Works, VCL; .NET 1.0, 1.1, 2.0, 3.5; and etc.

Technologies: Client/Server; COM; DirectX; DirectX Media; BDE; HTML/DHTML; ActiveX; Java Servlets; DCOM; COM+; ADO; CORBA; .NET; Windows Forms; GDI/GDI+; and etc.

Application Skills: Databases - design and maintain, support, programming; GUI Design; System Programming, Security; Business Software Development. Win/Web Services development and etc.

Comments and Discussions

 
Questionlicense? Pin
Corey W30-May-08 3:08
Corey W30-May-08 3:08 
GeneralCRegistryEx::RefreshContents Pin
bizulk14-Sep-05 6:08
bizulk14-Sep-05 6:08 
GeneralRe: CRegistryEx::RefreshContents [modified] Pin
alexn24-Jul-06 15:20
alexn24-Jul-06 15:20 
Kucherenko's class is good, but it'll go in an infinite loop even after your suggestions..

E.g.
HKEY_LOCAL_MACHINE
+Software
  +CodeProject
      +Unicode string array
      +Folder
          +Another string

This combination alone will take RefreshContents() for a good spin WTF | :WTF: , I'll try to fix though..


-- modified at 21:21 Monday 24th July, 2006
GeneralProblem openning and reading keys Pin
mel_sadek11-Mar-04 18:47
mel_sadek11-Mar-04 18:47 
GeneralRe: Problem openning and reading keys Pin
Oleksandr Kucherenko11-Mar-04 21:50
Oleksandr Kucherenko11-Mar-04 21:50 
QuestionHow to read Shell MRU Lists Pin
16-May-02 5:56
suss16-May-02 5:56 
AnswerRe: How to read Shell MRU Lists Pin
Oleksandr Kucherenko24-May-02 2:04
Oleksandr Kucherenko24-May-02 2:04 
AnswerRe: How to read Shell MRU Lists Pin
Oleksandr Kucherenko18-Jul-02 1:45
Oleksandr Kucherenko18-Jul-02 1:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.