The Wayback Machine - https://web.archive.org/web/20080601051049/http://www.codeguru.com:80/Cpp/Cpp/cpp_mfc/files/article.php/c4035

CodeGuru
Earthweb Search
Forums Wireless Jars Gamelan Developer.com
CodeGuru Navigation
Member Sign In
User ID:
Password:
Remember Me:
Forgot Password?
Not a member?
Click here for more information and to register.

Search
The Business Internet

jobs.internet.com

internet.commerce
Partners & Affiliates
Condos For Sale
Promote Your Website
Holiday Gift Ideas
Free Business Cards
KVM over IP
Find Software
Web Design
Promotional Golf
Boat Donations
Desktop Computers
SMS Mobile Messaging
Cell Phones
Server Racks
GPS


RSS Feeds

RSSAll

RSSVC++/C++

RSS.NET/C#

RSSVB

See more EarthWeb Network feeds

Home >> Visual C++ / C++ >> C++ >> C++ & MFC >> File I/O

Download: Intel AMT Setup and Configuration Service (SCS). Intel AMT SCS automates the task of populating Intel AMT platforms with credentials & parameters that enable them to be administered remotely.

Non volatile variables and configuration settings for MFC applications
Rating: none

Ruben Jvnsson (view profile)
January 24, 2002


(continued)

Access FREE Verio BSD Tools:
Whitepaper:
Verio FreeBSD Managed Private Servers (MPS) v3

Whitepaper:
Verio FreeBSD Virtual Private Server (VPS) v3

Whitepaper:
Performance, Control, and Security--The Benefits of Verio Virtual Private Servers (VPS)

Whitepaper:
Complete Peace of Mind--The Benefits of Verio Managed Private Servers (MPS)



Download these IBM resources today!
e-Kit: IBM Rational Systems Development Solution
With systems teams under so much pressure to develop products faster, reduce production costs, and react to changing business needs quickly, communication and collaboration seem to get lost. Now, theres a way to improve product quality and communication.

Webcast: Asset Reuse Strategies for Success--Innovate Don't Duplicate!
Searching for, identifying, updating, using and deploying software assets can be a difficult challenge.

eKit: Rational Build Forge Express
Access valuable resources to help you increase staff productivity, compress development cycles and deliver better software, fast.

Download: IBM Data Studio v1.1
Effectively design, develop, deploy and manage your data, databases, and database applications throughout the data management life.

eKit: Rational Asset Manager
Learn how to do more with your reusable assets, learn how Rational Asset Manager tracks and audits your assets in order to utilize them for reuse.

Environment: VC6 sp5 tested on W95 and W98

This article describes two classes for storing and retrieving string, numeric and BOOL variables to/from files in ASCII text format - much like INI files. The first class - CTxtVar, is used to dynamically add and remove variables in the text file. The second class - CCfg, which is derived from CTxtVar, is used as a base class to map a fixed set of variables or configuration settings in the text file to constant ID's which are used anywhere in the application to access (read and write) the actual variables/settings in the text file.

The CTxtVar class

I have chosen to put the variables in text files in human readable format instead of a binary format in order to make it easy to examine and modify the variables from any text editor. The format of the text file is divided into sections, items and variables:
[SECTION_HEADER]
ITEM VAR,VAR,VAR
ITEM VAR
ITEM VAR,VAR,VAR,VAR,VAR

[SECTION_HEADER]
ITEM VAR
ITEM VAR,VAR,VAR
Every item can have up to 20 variables attached to it (this is #defined to 20 in the CTxtVar header file for now - in the future this may be changed to a dynamic CStringList instead of a fixed array as now). For a real example, see the edit box on the right in the picture of the demo app above.

All variables are handled as strings in the CTxtVar class. Each line in the text file (item and section headers) are stored in a CStringList in the CTxtVar class. Items are accessed with a section header name and an item name. There are also functions to split the item and it's variables from a single string to an array of strings, one for each variable, which makes it possible to extract a single variable from an item. String variables and item names that contains white spaces or commas must be embedded within double quotes to be treated as one single variable. The items and it's variables are written back to the string list as one complete string. It is up to the calling function to build this string before it is written back.

Other functions in the CTxtVar class is: Read stringlist from file, write stringlist to file, find section, find item in section, add item, remove item, remove section and iterate through a section getting the items one by one.

The CTxtVar class is used when the number of items in a section is dynamic - items are added and removed on the fly, or when the item name and number of variables for an item is unknown at design time. Even the section name could be unknown. Example of this is list or combo boxes which could have it's contents manipulated by the user. The demo app demonstrates this example.

The functions SetItem() and SetSectionItem() has a BOOL parameter called bAdd which, if set to TRUE, allows items with identical names to be added to one section as separate items. An example where this could be useful is where the item represents a graphical object of some sort in a view. The name of the item is given by the user - not known at design time. The graphical object could be displayed on several places, perhaps in different modes on the same view. The item is the name supplied by the user, variable 1 could be the drawing mode, variable 2 the x position, variable 3 the y position and so on. This would mean that the item name would show up for every object of this type that is placed in the view. To retrieve the variables for these items FindItem() and FindSectionItem() would only find the first item with this name after the section header. In this case it is more useful to use the function FindSectionHeader() for the section with the items of interest and then iterate through every item of this section with GetNextItem(), perhaps building a linked list or an array of objects for these items, which is then used to access the objects within the application. One way to write back changed settings for the objects (added/removed objects, changed position) is to simply remove all items from the section in the string list with the function EmptySection() and then iterate through the list or array of objects in the app and for each one build the item string and write it back with SetSection() or SetSectionItem().

There is a BOOL member variable in the CTxtVar, m_bChanged, that is set to TRUE whenever a string is added, removed or changed in the string list. This value is checked in the destructor of the class which, if TRUE, automatically updates the text file. This means that there is generally no need to write the stringlist back to the text file manually (with Flush()) unless another class needs to read the text file during the lifetime of the CTxtVar class. This is the case in the demo app since the text file itself is displayed in a rich edit control and updated whenever there has been a change in the string list of the CTxtVar class. Of course, if the app exits unnaturally the destructor Flush() may not work so it will be a good idea Flush() critical changes back to the text file right after they are changed.

See the CTxtVar.cpp file for more information about member functions and variables.

The CCfg class

Whenever I do an MFC app I have a lot of variables and settings that should be saved between sessions. Call me old fashioned but I rather save these variables in a separate file in my app's directory than in the registry for several reasons: It is easy to read and modify (if it is in text format), it is easy to clean up, the same app can have several settings by simply starting it in different directories, just to mention some. The variables used for configuration settings are all known at design time. The CCfg class associates every setting/variable (and section and item) with an ID which is used instead of the section name and item name to access it's value. Furthermore, the variables can be of type string, numeric, limited numeric (limited by a max and min value) and BOOL. Every variable also has a default value which is used if the setting isn't found in the text file (which it isn't the first time the app starts or if the text file is deleted). If a value for a setting isn't found in the text file the default value will be written to the text file.

The CCfg class holds the information for every variable, item and section in a list of CCfgNode derived classes. These classes have information about the ID, the current value, the default value and a maximum and minimum value for the limited numeric type. The CCfg class uses the string list of the CTxtVar to load the CCfgNodes with current values for the settings. The CCfgNode list is written back to the text file in two steps, first the CCfgList is converted back to the string list in CTxtVar and then the base class CTxtVar writes back the string list to the text file. This isn't done until the Flush() function is called which could be as late as in the destructor of the CCfg and CTxtVar classes. The CCfg class dynamically builds the CCfgNode list upon initialization from information in an array of structures typedefed as CFGDEF.

The CFGDEF array is where the programmer specifies what section names, item names types of variables, default values and ID's should be used for the settings. In order to keep things simple and not having to remember too much about how this CFGDEF structure works I have created a set of macros that does most of the job during compile time. Also, these macros automatically assigns the ID a unique number which makes it impossible to have two ID's of the same number by mistake. How can this be done, you may ask, how can a macro both define a structure array and declare a constant with a different value at the same time? Well it can't, but by putting the macros for the definition of the CFGDEF structure in the header file of the CCfg derived class (the user class) and redefining the macros and including this header file twice from the implementation file (.cpp file) of the CCfg derived class it can. The macros that generate the unique ID's and builds the CFGDEF array can look something like this:

BEGIN_CFGDEF(cfgdef)

   CFG_SECTION(CFGID_SETTINGS,"Settings")
      CFG_WINDOWPOS(CFGID_INITWINDOWPOS,"MainWindowPos",
                      100,100,620,510,0)
      CFG_FONT(CFGID_FONT,"Font","System",12,FW_NORMAL,FALSE)

      CFG_ITEM(CFGID_CURRENTCOMBOLIST,1,"Currentcombolist")
      CFG_STRING(CFGID_CURRENTCOMBOLIST_NAME,"")

      CFG_ITEM(CFGID_BOOL,1,"Bool")
      CFG_BOOL(CFGID_BOOLVALUE,0)

      CFG_ITEM(CFGID_NUM,1,"Numeric")
      CFG_NUM(CFGID_NUMVALUE,0)

      CFG_ITEM(CFGID_DIR,1,"Directory")
      CFG_STRING(CFGID_DIRSTRING,"")

END_CFGDEF
The resulting text file with default values for this CFGDEF looks like this:
[Settings]
MainWindowPos 100,100,620,510,0
Font "System",12,400,0
Currentcombolist ""
Bool 0
Numeric 0
Directory ""
The order of the items in the section may vary though.

I have chosen to make the CCfg derived class global in order to make it accessible from all classes that has included the header file of the CCfg derived class. I think this is one case where a global variable is a good thing in a C++ application. This way it is easy for the objects that needs to access non volatile variables or configuration settings themselves without obtaining a pointer from another (global) class.

The variables/settings can be read by the following functions: GetBool(int VariableId), GetString(int VariableId) and GetNum(int VariableId) or GetBool(int ItemId, int VariableIndex), GetString(int ItemId, int VariableIndex) and GetNum(int ItemId, int VariableIndex) where VariableIndex is the indexnumber for a variable in an Item. Index 0 is the first varaible. Use the following functions to write variables/settings: SetBool(int VariableId,BOOL Value), SetString(int VariableId,CString Value) and SetNum(int VariableId,long Value) or SetBool(int ItemId, int VariableIndex, BOOL Value), SetString(int ItemId, int VariableIndex, CString Value) and SetNum(int ItemId, int VariableIndex, CString Value).

To check the integrity of the CFGDEF array the debug version fails ASSERT macros if something is wrong. This could be: A CFG_SECTION isn't the first macro after BEGIN_CFGDEF or an item has more or less variables than specified. ASSERT also fails if the application is trying to use the wrong access function for a variable ID, for example trying to read a string variable with the GetNum() function.

How the CFGDEF macros work

When the header file (the declaration file) for the CCfg derived class is included from the cpp file (the implementation file) for the CCfg derived class the first time or whenever it is included from another class the macros generate a typedef of an enumerated variable that include all ID's from the CFGDEF macros. This way the ID's have been assigned unique consecutive numbers which is known by all classes that includes the declaration file. Before the header file is included a second time from the cpp file of the CCfg derived class it has defined an identifier to tell the header file that this time the macros should generate the implementation of the CFGDEF structure array. To accomplish this the macros are redefined. The definition and redefinition of the macros takes place in the header file for the CCfg class.

How to use it

In order to use the CCfg class you have to derive a class from it and put the macros for the CFGDEF structure array in the derived class' header file. The only function needed is the constructor which has to generate the CfgNode list with a call to MakeCfgList(const CFGDEF *cfg_def). It may be easiest to use the following implementation and declaration files as a template and change the names as you want.

The declaration file (header file)

// CfgDem.h: interface for the CCfgDem class.
//
///////////////////////////////////////////////////////

#if !defined( \
AFX_CFGDEM_H__20008C44_F97E_11D5_8C08_B343B9E2DD77__INCLUDED_)
#define \
AFX_CFGDEM_H__20008C44_F97E_11D5_8C08_B343B9E2DD77__INCLUDED_
#define __CFG_FIRST_RUN__
#endif

#if defined(__CFG_FIRST_RUN__)
#define   __INCLUDE_CFGDEF__
#elif defined(__CFG_IMPLEMENTATION__)
#define   __INCLUDE_CFGDEF__
#endif

#if defined(__INCLUDE_CFGDEF__)
#include "Cfg.h"

/*
   This file must be #included twice from the CCfg
   derived class, once to enumerate the ID's
   (definition) and once to implement the array of
   CFGDEF structures (declaration).
   The CFG_... macros are redefined when
   __CFG_IMPLEMENTATION__ is defined.

   When this file is included from the CCfg derived
   class and __CFG_IMPLEMENTATOIN__ is defined the
   following macros generate the array of CFGDEF
   structures used to access the cfg file.

   When this file is included without
   __CFG_IMPLEMENTATION__ defined (the first time
   it is included in the CCfg derived class and
   whenever it is included in another cpp file) all
   ID's are enumerated to generate unique numbers
   for all cfg ID's.
*/

   BEGIN_CFGDEF(cfgdef)  // cfgdef is the name
                         //for the CFGDEF structure
                    // array - CFGDEF cfgdef[]={

      // Put the rest of the CFGDEF macros here

   END_CFGDEF

#endif

#if defined(__CFG_FIRST_RUN__)

class CCfgDem : public CCfg
{
public:
   CCfgDem();
   virtual ~CCfgDem();

};

extern CCfgDem cfg;    // Make the global cfg
                     // variable visible to
                // other classes that
                     // includes this .h file.

#endif

#undef __INCLUDE_CFGDEF__
#undef __CFG_FIRST_RUN__
#undef __CFG_IMPLEMENTATION__
Note that the #pragma once can not be used in this header file. Rename all instances of CCfgDem to whatever name you want the derived class to have.

The implementation file (cpp file)

// CfgDem.cpp: implementation of the CCfgDem class.
//
//////////////////////////////////////////////////

#include "stdafx.h"
#include "CfgDemo.h"
#include "CfgDem.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define __CFG_IMPLEMENTATION__
#include "CfgDem.h"  // When __CFG_IMPLEMENTATION__ is
                     // defined
                     // CfgDem.h actually defines the CFGDEF
                     // structure array

CCfgDem     cfg;     // Global CCfgDem class.

/////////////////////////////////////////////////////////
// Construction/Destruction
/////////////////////////////////////////////////////////

CCfgDem::CCfgDem()
{
  MakeCfgList(cfgdef);  // Make the cfg node list from
                        // the cfgdef struct array.
}

CCfgDem::~CCfgDem()
{

}
Rename all instances of CCfgDem to whatever name you want the derived class to have.

See the source files for more information about the CCfg class.

About the demo app

The view class together with some custom controls handles all the functionality of the CfgDemo app. The document class is not used at all.

All controls on the left side is used to show and manipulate settings in the text file. The CRichEditCtrl on the right side is used to show the actual contents of the text file itself and is updated whenever the text file is changed.

There are two combo boxes which are used to enter and display data of three lists. The first combo box is of type drop list which selects one of three lists. The other combo box is a drop down type used to select and enter data into the list selected by the first combo box. The selection of an item in the second combo doesn't do anything in this demo, though. There is also a button to delete the currently selected list. The lists are updated and accessed in the text file by CTxtVar (base class of the CCfg class) functions that directly reads and writes to and from the CStringList representing the text file in the CTxtVar class. This is done to demonstrate that dynamic sections and items can be read and written to the same text file as CFGID linked sections and items.

There is a read only edit box which displays a directory selection done with a SHBrowseForFolder dialog through a button next to the edit box.

There is an edit box with a spin control used for entering a numeric value.

There is a check box used for a BOOL value.

There is a button which opens up a modal font selection dialog box to set the font for the CRichEditCtrl. The font setting is also stored in the text file.

The app also uses a custom class derived from CFormView called CMyFormView as a base class for the view. This class automatically handles resizing and repositioning of controls on the form when the main frame is resized. The size, position and maximized/normal state is saved in the text file when the app closes and is restored when the app is loaded the next time.

Use the source as you want. If you do - please send me a mail to tell me.

Downloads

Download demo project - 21 Kb
Download source - 47 Kb

Tools:
Add www.codeguru.com to your favorites
Add www.codeguru.com to your browser search box
IE 7 | Firefox 2.0 | Firefox 1.5.x
Receive news via our XML/RSS feed

Is it time to make your move to the multi-threaded and parallel processing world? Find out!
Generate Complete .NET Web Apps in Minutes . Download Iron Speed Designer today.
Developing Intelligent Communications? Visit the Avaya DevConnect Center on DevX.
Download: Intel AMT Developer's Tool Kit (DTK)
Download: Intel AMT Setup and Configuration Service (SCS)


RATE THIS ARTICLE:   Excellent  Very Good  Average  Below Average  Poor  

(You must be signed in to rank an article. Not a member? Click here to register)

Latest Comments:
Thanks, works great - Legacy CodeGuru (02/05/2002)
interest - Legacy CodeGuru (01/27/2002)

View All Comments
Add a Comment:
Title:
Comment:
Pre-Formatted: Check this if you want the text to display with the formatting as typed (good for source code)



(You must be signed in to comment on an article. Not a member? Click here to register)


JupiterOnlineMedia

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info

Solutions
Whitepapers and eBooks
Microsoft Article: Will Hyper-V Make VMware This Decade's Netscape?
Microsoft Article: 7.0, Microsoft's Lucky Version?
Microsoft Article: Hyper-V--The Killer Feature in Windows Server 2008
Avaya Article: How to Feed Data into the Avaya Event Processor
Microsoft Article: Install What You Need with Windows Server 2008
HP eBook: Putting the Green into IT
Whitepaper: HP Integrated Citrix XenServer for HP ProLiant Servers
Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 1
Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 2--The Future of Concurrency
Avaya Article: Setting Up a SIP A/S Development Environment
IBM Article: How Cool Is Your Data Center?
Microsoft Article: Managing Virtual Machines with Microsoft System Center
HP eBook: Storage Networking , Part 1
Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
MORE WHITEPAPERS, EBOOKS, AND ARTICLES
Webcasts
Intel Video: Are Multi-core Processors Here to Stay?
On-Demand Webcast: Five Virtualization Trends to Watch
HP Video: Page Cost Calculator
Intel Video: APIs for Parallel Programming
HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
MORE WEBCASTS, PODCASTS, AND VIDEOS
Downloads and eKits
Sun Download: Solaris 8 Migration Assistant
Sybase Download: SQL Anywhere Developer Edition
Red Gate Download: SQL Backup Pro and free DBA Best Practices eBook
Red Gate Download: SQL Compare Pro 6
Iron Speed Designer Application Generator
MORE DOWNLOADS, EKITS, AND FREE TRIALS
Tutorials and Demos
How-to-Article: Preparing for Hyper-Threading Technology and Dual Core Technology
eTouch PDF: Conquering the Tyranny of E-Mail and Word Processors
IBM Article: Collaborating in the High-Performance Workplace
HP Demo: StorageWorks EVA4400
Intel Featured Algorhythm: Intel Threading Building Blocks--The Pipeline Class
Microsoft How-to Article: Get Going with Silverlight and Windows Live
MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES