Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A set of template classes for working with the registry

0.00/5 (No votes)
3 Jul 2002 1  
Writing generic code with templates and the C++ standard library.

Yet another registry class!? But why?

I recently read an article here on CodeProject that described a set of classes to work with the registry. A request for a template version of the classes inevitably popped up. The author of that article had a couple of reasons for not writing a template version. After thinking about it for a while I came to the conclusion that a template could indeed be made. So here it is.

Usage

The class is really three classes. However, instead of making one class for each type to store I made one template class for each type of data type that the registry supports. Well not really. Classes for string, dword and binary storage are provided. I feel that these three cover most things one would want to store in the registry.

So, say we want to store a string:

typedef registry_string<std::string> regstring;

regstring str("Software\\RegValueTest\\blah", HKEY_CURRENT_USER);

str = "Hello world!";
std::string stored = str;
std::cout << stored << std::endl;
First a convenience typedef. Our template type is std::string, that's the type we wish to load or store. Because we use the registry_string template the string will be stored with type REG_SZ in the registry. Storing is as easy as assigning to the registring object. Reading from the registry is also performed this way, simply create an object of the right type and assign from the regstring. All this is courtesy of operator= and operator T (conversion operator). If one doesn't like the use of a conversion operator (they're not exactly the best thing in the world) it's enough just to change the name of the functions.

To store a POINT:

typedef registry_binary<POINT> regpoint;

regpoint pnt("Software\\RegValueTest\\blah", HKEY_CURRENT_USER);

POINT p = {99,88};
pnt = p;
POINT stored = p;
std::cout << stored.x << "," << stored.y << std::endl;
The last class, registry_int, works the same way as the other two so an example should not be necessary. These three classes can be used to store a large number of classes. A few examples:
typedef registry_string<std::string>    regstring;
typedef registry_int<bool>              regbool;
typedef registry_binary<RECT>           regRECT;
typedef registry_string<double>         regdouble;

A double in a registry_string?

The registry_string template class is quite handy. To be able to store an arbitrary type in a string a std::stringstream is used. This enables the use of this template class with any type that can serialize itself to a stream. This includes the built in types; bool, double, char etc. The registry_string<double> will convert the double the user wishes to store into a textual representation of the value. This might be better than storing a binary version of the number (but if you want to store it in binary then it's as simple as making a registry_binary<double>).

The classes are also capable of some other nice things:

registry_value val("Software\\RegValueTest\\blah", HKEY_CURRENT_USER);

if(val.exists())
{
    val.remove_value();
    val.remove_key();
}
This would check if the value existed and if that was the case remove both the value and the key. The registry_value class is a base class for the other three. More on that in the next section.

Implementation

I put the functions that all three classes used in a common base class, registry_value. Here's a simplified overview of that class:
class registry_value
{
    public:
        registry_value(const std::string & name, HKEY base_);

        bool exists();
        void remove_value(void);
        void remove_key(void);

    protected:

        bool open(bool write_access);
        void close(void);
        bool query_value(DWORD * type, DWORD * size, void * buffer);
        bool set_value(DWORD type, DWORD size, const void * buffer);

    private:

        void make_path(const std::string & name);

        HKEY key;
        HKEY base;

        std::string valuename;
        std::string keyname;
};

Nothing spectacular here. The public interface consists of the three functions described above. The protected interface has functions for gaining access to a key and reading/writing. The private section includes a utility function and data that the other functions use. As described above, the class can be used on it's own to check if a value exists etc.

As clearly visible, registry_value is not a template class. Let's take a closer look at registry_binary.

template<class T>
class registry_binary : public registry_value
{
    public:
        registry_binary(const std::string & name, HKEY base) : 
            registry_value(name, base)
        {
        }
        
The constructor simply forwards the parameters to the base class.
operator T()
{
    T returnval = T();

    if(open(false) == true)
    {
        DWORD type, size = sizeof(T);
        if(query_value(&type, &size, &returnval) == true)
        {
            assert(type == REG_BINARY);
        }

        close();
    }

    return returnval;
}
The conversion operator handles reading from the registry. Nothing particularly noteworthy here except perhaps the initialization of the value we store the data in. The reason for '= T();' is that it ensures that returnval doesn't contain random crap data since this value is returned from the function unchanged if something goes wrong with the queries.
const registry_binary & operator=(const T & value)
{
    if(open(true) == true)
    {
        set_value(REG_BINARY, sizeof(T), &value);
        close();
    }

    return *this;
}
The operator= handles writing to the registry. The set_value function defined in registry_value and it wants a type, a size and a pointer to the data. That's all there is to registry_binary.

Closing words

This article is not so much about registry access itself but more about showing how templates can be used to get more functionality with less code.

As a side note: there is also a specialized version for registry_string<std::string> that omits the stringstream code that registry_string normally uses.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here