Storing an Array of Properties in the Windows Registry

Environment: Windows, System Programming, Registry

MFC and Win API don't have functions that store arrays in the Windows Registry. This article describes the class based on the MFC CArray class that solves this task. I used this class in the PC Atomic Sync project for storing the NTP (Network Time Protocol) servers list.

1. MFC Registry Functions

We use the Registry to store program parameters.

If you use MFC you must set the Registry key for your program. The MFC SDI and MDI wizards generate correspondent strings in the App::InitInstance() function. In the dialog base project, you can insert it manually.

Example:

SetRegistryKey(_T("RegistryArray"));

After calling this function, all your parameters will be stored in the following Registry path: HKEY_CURRENT_USER/Software/RegistryArray.

As a result, in such multi-user systems as Win NT/XP/2K, every user will have his/her own set of parameters.

There are four MFC functions for writing/reading Registry parameters: GetProfileInt, GetProfileString, WriteProfileInt, and WriteProfileString. They are members of the CWinApp class. The "Get" functions have a nice parameter for setting the default property. If the Registry has not been yet initialized by your program, this parameter is used instead of the Registry value.

Example:

// Writing integer value nSomeValue to the section SomeSection
// under name SomeValue.
  AfxGetApp()->WriteProfileInt(_T("SomeSection"), _T("SomeValue"),
                                  nSomeValue );

// Reading nSomeValue from the key SomeValue of the section
// SomeSection.
// If the key is absent the variable will be assigned by 10.
  int nSomeValue = AfxGetApp()->GetProfileInt(_T("SomeSection"),
  _T("SomeValue"), 10);

2. Storing Arrays in the Registry

Usually, we store data in files and program parameters in the Registry. But, it is possible that some parameters can look like arrays. For example, our application has some windows and we want to store their placements. Every user would like a private placement. One solution is to create some file with parameters; the other is to store an array in the Registry. There is no such standard function, but the solution is simple. We can store the array size as an integer value and the array elements by using special key names that include numbers of elements. For example, array_0, array_1, array_2 . . .

3. CRegArray Template Class

It is good to have a common solution for any array that we want store in the Registry. So, our class must be a template that receives any type. Mostly, we work with classes and need to store records with data of different types. I created the CRegArray class template that is based on the CArray class template. There is only one demand to the class that is used as an array element. It must include two functions: CString GetAsString() const and void Parse(CString& sStr). In other words, the data converts to a string before storing and restores from the string after reading from the Registry.

Class source:

#include <afxtempl.h>

template <class T, class F>
  class CRegArray: public CArray<T, F>
  {
  public:
    CRegArray(const CString sSection, const CString sArrayName);
    void FetchRegistry();
    void PersistRegistry();
  private:
    const CString m_sSection;
    const CString m_sArrayName;
    const CString m_sCounterName;
  };

template <class T, class F>
  inline CRegArray<T,T&>::CRegArray(const
                                    CString sSection,
                                    const CString sArrayName):
                                    CArray<T,F>(),
  m_sSection(sSection),
  m_sArrayName(sArrayName),
  m_sCounterName(sArrayName+"_Counter")
  {
  }

template <class T, class F>
  inline void CRegArray<T,T&>::FetchRegistry()
  {
    int nCounter = AfxGetApp()->GetProfileInt(m_sSection,
                                              m_sCounterName, 0);
    for(int i = 0; i < nCounter; i++){
      CString sElmName;
      sElmName.Format("%s %d",m_sArrayName, i);
      CString sTmp = AfxGetApp()->GetProfileString(m_sSection,
                                                   sElmName, "");
      CSomeClass clTmp;
      clTmp.Parse(sTmp);
      Add(clTmp);
    }
  }

template <class T, class F>
  inline void CRegArray<T,T&>::PersistRegistry()
  {
    AfxGetApp()->WriteProfileInt(m_sSection, m_sCounterName,
                                 GetSize() );
    for(int i=0;i<GetSize();i++){
      CString sElmName;
      sElmName.Format("%s %d",m_sArrayName, i);
      AfxGetApp()->WriteProfileString(m_sSection, sElmName,
                                      (*this)[i].GetAsString() );
    }
  }

The class is simple. I added only two functions to the CArray class: FetchRegistry() and PersistRegistry(). The constructor has two parameters: the Section Name and the Array Name. So, it is possible to store some arrays in one section.

4. Demo Project

The DemoProject is the dialog base project. To demonstrate the use of CRegArray, I created CSomeClass. It includes string, double, and integer fields. The object is entered in the dialog form and is added to the array by pressing the "Add Object" button. All objects are shown in the list control. The "Delete Object" button removes the last object from the list. The "Store into the Registry" button writes the array into the Registry. This array is loaded in the OnInitDialog() function.

String converting of CSomeClass fields is realized in the following way:

const int nBuffSize(1024);

CString CSomeClass::GetAsString() const
  {
    sStr(' ', nBuffSize);

    sStr.Format("%s\n%d\n%e", m_sStrValue,
                 m_nIntValue,m_nDoubleValue);
    return sStr;
  }

void CSomeClass::Parse(CString& sStr)
  {
    strstream sStream((char*)(LPCTSTR)sStr, nBuffSize);

    char buff[nBuffSize];
    sStream.getline(buff,nBuffSize);
    m_sStrValue = buff;
    sStream >> m_nIntValue;
    sStream >> m_nDoubleValue;
  }

Links

I used the technique described in this article in the project "PC Atomic Sync": http://www.brigsoft.com/bsatomic
Author's home site: http://www.brigsoft.com.

Link to author's other sources and articles: http://www.brigsoft.com/edu.

© Alex Rest, 2003

Downloads

Download demo project - 15 Kb


Comments

  • How can you enable the registry in a dialog based app?

    Posted by joape382 on 03/19/2005 11:54am

    When using SetRegistryKey(_T("RegistryArray")) in my dialog based application the compiler gives the following error (using VS.NET 2003) error C3861: 'SetRegistryKey': identifier not found, even with argument-dependent lookup How can you enable the registry in a dialog based app?

    Reply
  • Good,but how about other types of data in the registry?

    Posted by Legacy on 08/19/2003 12:00am

    Originally posted by: fjwkitty

    Is there an template function to access all kinds of type of data?

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

Top White Papers and Webcasts

  • When it comes to desktops – physical or virtual – it's all about the applications. Cloud-hosted virtual desktops are growing fast because you get local data center-class security and 24x7 access with the complete personalization and flexibility of your own desktop. Organizations make five common mistakes when it comes to planning and implementing their application management strategy. This eBook tells you what they are and how to avoid them, and offers real-life case studies on customers who didn't …

  • The operational costs of managing an x86 base are taxing IT budgets, making it difficult to fund and staff new initiatives. Today's IT organization must seek efficiencies in its operations and shift to a more agile infrastructure that's flexible enough to adapt to future changes in the business. Read this Q & A session with Jed Scaramella, research manager for IDC's Enterprise Platforms and Data Center Trends, to learn how the integrated nature of the blade platform delivers critically needed efficiencies …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds