Status & Roadmap
Authors & License
Funding Ultimate++
Search on this site

SourceForge.net Logo

About storing configuration

If you want to go on using registry functions (we don't like them very much, honestly), you'll find their wrappers in Core/Win32Com.h:


String GetWinRegString(const char *value, const char *path, HKEY base_key =


int    GetWinRegInt(const char *value, const char *path, HKEY base_key =


bool   SetWinRegString(const String& string, const char *value, const char

*path, HKEY base_key = HKEY_LOCAL_MACHINE);

bool   SetWinRegInt(int data, const char *value, const char *path, HKEY


void   DeleteWinReg(const String& key, HKEY base = HKEY_LOCAL_MACHINE);


However if you want to use your own configuration files, you have basically two possibilities:


1) text-oriented configuration (something like key=value pairs, or perhaps some xml)

2) binary configuration


Text-oriented configuration is somewhat 'cleaner' in the sense that you (or anyone else) can look into the file and possibly find out what went wrong, add or modify its contents using a simple text editor. Sometimes this is useful, sometimes this is exactly what we try to avoid. It depends on your context. Binary configuration, on the other hand, is much simpler to generate / parse, because the data can directly flow between the configuration and the program objects using the serialization functions.


1) Text configuration


If you want simple key=value pairs, you could use the function


VectorMap<String, String> LoadIniFile(const char *filename);


defined in Core/Util.cpp. For some strange reason its declaration is missing in Core/Util.h but I'll fix that immediately. This function parses a given file and turns it into a key-value map. In an application, you can then write e.g.:


VectorMap<String, String> cfg = LoadIniFile("myapp.cfg");

String recentdir = cfg.Get("RECENTDIR", Null);

int id = ScanInt(cfg.Get("ID", Null));



You have to write such file manually, but it's no big problem, just do something like


String cfg;

cfg << "RECENTDIR=" << appobj.recentdir << "\n"

    "ID=" << appobj.id << "\n";

if(!SaveFile("myapp.cfg", cfg))

    Exclamation("Error saving configuration!");


Of course the situation would get much more complicated if you wanted to stored more complex data in the configuration. Basically you have to parse the file by yourself, but you can make use of many text parsing utilities present in uppsrc (like CParser or XMLParser).


2) Binary configuration


For the sake of simplicity let's initially assume you keep the whole configuration in a single object cfgobj of type AppConfig. Your main application function could then look something like:




   String cfgfile = ConfigFile();

   AppConfig cfgobj;

   if(FileExists(cfgfile) && !LoadFromFile(cfgobj, cfgfile))

       Exclamation("Error loading configuration file!");


   if(!StoreToFile(cfgobj, cfgfile))

       Exclamation("Error updating configuration file!");



Note the functions LoadFromFile and StoreToFile, which use the AppConfig::Serialize method to transfer the data between the object and its linear (stream) representation. You have to implement this function and so define how the object is to be linearized. For example:


struct AppConfig {

   AppConfig(); // you usually want to initialize the default configuration



   void Serialize(Stream& stream);


   String recentdir;

   int id;



void AppConfig::Serialize(Stream& stream)


   stream % recentdir % id;



This is sufficient to make the basic thing working. If you wanted to dig deeper into this, you can try to take a look at the following:


a) There are many utility functions for serialization, see e.g. Core/Util.h, functions like Load, Store, LoadFromString / File, StoreToString / File.


b) Some support is present for the so called "distributed configuration" where different parts of the application register their own configuration objects, not necessarily knowing about configuration objects belonging to different parts of the application. See Core/Util.h, functions


void             RegisterGlobalConfig(const char *name);

void             RegisterGlobalConfig(const char *name, Callback WhenFlush);

String&          GlobalConfigData(const char *name);

CriticalSection& GlobalConfigLock();

bool LoadFromGlobal(T& x, const char *name);

void StoreToGlobal(T& x, const char *name);

void SerializeGlobalConfigs(Stream& s);



Last edit by unodgs on 08/20/2006. Do you want to contribute?. T++