Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
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 =

HKEY_LOCAL_MACHINE);

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

HKEY_LOCAL_MACHINE);

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

base_key = HKEY_LOCAL_MACHINE);

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));

etc.

 

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:

 

GUI_APP_MAIN

{

   String cfgfile = ConfigFile();

   AppConfig cfgobj;

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

       Exclamation("Error loading configuration file!");

   RunMyApp(cfgobj);

   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

here

 

   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++