This describes the classes and miscellaneous features of the system registry support in Classics.
The Win32 API offers a number of functions for manipulating the registry. For an improved object-oriented C++-centric way to access the registry, nothing comes to mind. So this effort concentrates on making the existing primitves properly robust, and uses classes where such use is obvious and not contrived.
Beyond better-wrapped primitives for accessing the registry, the real benefit comes from higher level functions. [more later...]
The Classics registry primitives address issues with the Win32 API concerning error checking and Unicode/ANSI transparancy.
For some strange reason, the
RegXxx primitives in the Win32 API return an error code directly as the function
result, which is different from normal Win32 API policy which is to return a Boolean success (1) or failure (0) and
in the latter case set the error code to be retreived using
The Classics functions uniformly use exceptions to indicate unexpected failures. In the case of the registry functions, the return value is used to return something useful, and errors are indicated by throwing a highly detailed exception object, as usual.
This difference in the error handling of the registry Win32 functions is something that appears to have gone
unnoticed by other programmers and Microsoft, too. In addition, it was clearly not tested properly. Specifically,
a problem shows up with the Unicode forms of the functions under Win95. If the Unicode form is called, the
correct behavior would be to return
ERROR_CALL_NOT_IMPLEMENTED (whose value happens to be 120).
Instead, the functions return
ERROR_SUCCESS, indicating normal completion, but don't actually do anything and return
bogus results such as invalid
This problem seems to be caused by the implementation of the function returning
FALSE to indicate an error and
setting the 120 code into the
GetLastError area. Since
ERROR_SUCCESS also happens to be zero, you have the
appearance of a successful function. Since the registry functions don't normally modify the
GetLastError value (that is,
they don't clear it out on success), a work around is to explicitly clear it before making the call, and then if a zero
is received as a return value, check
GetLastError. If set, the zero must have been
FALSE, otherwise it can be assumed
This problem appears to only effect the Unicode not-implemented stubs, so the extra logic is only needed when deciding whether Unicode forms of the functions are available. As the distinction between Unicode and ANSI is taken care of automatically by Classics, this code is used internally the first time a registry function is called in order to determine the availability of Unicode support, and after that more efficient code is used.
Another discrepency, though less of a problem, exists in the documentation. The Platform SDK documents the
legal characters in a registry Key name to consist of "printable ANSI characters" in the range of
'\x7e' inclusive, except for space,
'?', and backslash. If true, it means that there is no real distinction between
ANSI and Unicode for key names, since key names are restricted to using 92 possible characters. However, inspecting
the registry it is instantly clear that Microsoft doesn't read their own documentation, as there are lots of keys present
such as "Control Panel" and "Internet Explorer", not to mention the key named "*" under
Experiments indicate that as far as actual implementation goes, anything is accepted including the proscribed
characters listed in the documentation. So the Classics functions do not do any additional error checking, and are
written to allow any Unicode strings. In addition, the
registry_UT.cxx program includes tests to see what is actually
allowed (what works) on the current system.