Programming the Win32 registry

The first function you need to use when working with the Win32 registry is the RegOpenKey function. This function opens a registry key and assigns it to a handle. (The key handle must already be created before you use the RegOpenKey function.) In actuality, RegOpenKey is "provided for compatibility with Windows version 3.1", according to the Windows 32-bit API reference, and 32-bit Windows applications should use RegOpenKeyEx instead, which does the same thing but has a few more options.

After the desired registry key has been opened, the function used to read ("query") a particular value under that key is RegQueryValue. Again, RegQueryValue is "provided for compatibility with Windows version 3.1", and 32-bit applications should use RegQueryValueEx instead. This time, however, RegQueryValueEx actually provides a significant functionality that plain old RegQueryValue does not: It lets you query values which have a name, whereas RegQueryValue only lets you query "the unnamed value" of a key, which is often denoted as the "(Default)" value. If you use the Registry Editor (regedit) to browse through your registry, you will notice that every registry key has a value associated with it that is simply called "(Default)". Officially, this value has no name, or rather, a NULL name, and the Win32 API reference calls it "the unnamed value" for the key. The RegQueryValue function is only capable of querying this value, while RegQueryValueEx allows you to actually specify a named value within a key to query. Clearly, then, RegQueryValueEx is what you'll be using when reading values from the registry, unless you really want to read a key's default value.

Now that you know these two Win32 API functions, you can make a simple program that reads a value from the registry. Let's go through a few other notes to keep in mind when making such a program.

The header file for these registry API functions is winreg.h. So you'll need to include the following line in your #includes:

#include <winreg.h>

A key handle is actually declared just like a variable type; It's designated by the type HKEY. So you'll need to create the handle to the key with a line like this:

HKEY MyKey;

The syntax of RegOpenKeyEx is as follows:

RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, phkResult);

hKey is the handle of a key. In this case (as in most cases), you'll be using one of the pre-defined reserved Windows key handle values. These include:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpSubkey is supposed to be a pointer to a string, but you can just make it a hard-coded string. Remember that it must be null-terminated, so put \0 (which denotes a null character) at the end of the string.

ulOptions is reserved and must be zero.

samDesired is the security access mask that you want to use for this key access. Since we're just making a program to read the key right now, you should set this to KEY_READ.

Finally, phkResult points to a variable that receives the handle of the opened key. In this case, we'll use an HKEY type that we created before.

The syntax of RegQueryValueEx is as follows:

RegQueryValueEx(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);

hKey is, again, the handle of a key. In this case we'll use the HKEY that we used with RegOpenKeyEx.

lpValueName is supposed to be a pointer to a string that contains the name of the value to be queried. In this case, we'll just hard-code this as a string directly into RegQueryValueEx's arguments.

lpReserved is reserved and must be NULL.

lpType is a pointer to a variable that contains the value's type. There are a few types of values that you can query in the registry, including REG_BINARY and REG_DWORD. In this case, we'll use REG_DWORD because we'll be querying a DWORD value, as you'll soon see.

lpData is a pointer to a buffer to receive the data in the value.

Finally, lpcbData is a pointer to a variable that specifies, in bytes, the size of the buffer pointed to by lpData. (Notice that everything in the world is a pointer, or at least everything that's a parameter to these registry functions. It seems like Microsoft likes to point to everything with their registry API functions.)

We now know everything we need to know to create a program that reads the registry. I started learning about programs that use the registry when I got interested in the idea of a program that could quickly and easily change the Active Scripting option in Internet Explorer. I turn this setting on and off constantly, because I browse with it off, but there are an enormous number of people stupid enough to actually use JavaScript on their websites, which means you have to turn it on or their worthless, uninformative websites don't work. Your Active Scripting setting is located in the following registry path:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3\1400

1400 is a DWORD registry value. If it is set to zero, it means that Active Scripting is enabled. If it is set to 3, it means that Active Scripting is disabled. And if it is set to 1, that means Active Scripting is set to "Prompt", meaning Internet Explorer will prompt you when a website wants to run a script on your computer.

Given all this, it's reasonably easy to make a program which checks this registry value and tells you whether Active Scripting is on or off. We'll start with our #includes. Recall that we need to include the winreg.h file to use the Windows registry functions. We'll also be using malloc in this program, and we need to include stdlib.h for that. So, our program starts with:

#include <winreg.h>
#include <stdlib.h>

Once we get the program rolling inside WinMain, we create our key handle. Let's call it MyKey because I like to be gratuitously cute:

HKEY MyKey;

We'll also need to declare values for RegQueryValue's lpType and lpcbData. We also need to create the actual buffer that it's going to store the value's value in. We do that with these declarations:

DWORD VarType = REG_DWORD; //the value's a REG_DWORD type
DWORD BuffSize = 4;
int *Buff = (unsigned int*)malloc(BuffSize);

And now it's time to use RegOpenKeyEx!

RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3\0", 0, KEY_READ, &MyKey);

Keep in mind that within a literal string, you need to use double-backslashes (\\) to create a literal backslash character within the string. Also remember that the string needs to be terminated with a null character (\0), and that ulOptions is reserved and must be zero.

Next, it's time to use RegQueryValueEx! We're about to actually read the registry value!

RegQueryValueEx(MyKey,"1400\0",NULL,&VarType,Buff,&BuffSize);

"1400" is the name of the value we're querying under the key we just opened with RegOpenKeyEx. Again, we need to make this a proper string by terminating it with a null character.

It's all done! Buff now points to the value of Active Scripting's setting. We just need to do a few ifs to determine what it is, and we can display a message as appropriate.

The complete code of a working program is below:

#include <winreg.h>
#include <stdlib.h>

int STDCALL
WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
{

HKEY MyKey;

DWORD VarType = REG_DWORD; //the value's a REG_DWORD type
DWORD BuffSize = 4;
int *Buff = (unsigned int*)malloc(BuffSize);


RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3\0", 0, KEY_READ, &MyKey);

RegQueryValueEx(MyKey,"1400\0",NULL,&VarType,Buff,&BuffSize);

if (*Buff==0) MessageBox (NULL, "Active Scripting is on.", "Scripting report", MB_OK);
else if (*Buff==3) MessageBox (NULL, "Active Scripting is off.", "Scripting report", MB_OK);
else if (*Buff==1) MessageBox (NULL, "Active Scripting is set to prompt.", "Scripting report", MB_OK);
else MessageBox (NULL, "Active Scripting is set to some value that this program doesn't recognize.", "Scripting report", MB_OK);

RegCloseKey (MyKey);

return 0;

}

Notice that there's a RegCloseKey function call at the end to close the key we opened. This isn't really necessary for a small program like this (since open keys are supposed to be closed automatically when the program terminates anyway), but it's good programming practice.

Having made a program to read the registry, the other logical action is to write a value to the registry. Setting a value in the registry is even easier. The function for this is RegSetValue. Note that just as with RegQueryValue, RegSetValue can only set the null, unnamed value of a registry key. To set a named key, you need to use RegSetValueEx.

The syntax of RegSetValueEx is as follows:

RegSetValueEx(hKey, lpValueName, Reserved, dwType, *lpData, cbData);

hKey you should know by now. :)

lpValueName is, as you've probably guessed, the name of the value to set.

Reserved is reserved (coincidence? I think not), and must be zero.

dwType is the value type. Again, we're using a REG_DWORD type.

lpData is a pointer to the actual data that goes into the value we're setting.

And finally, cbData specifies the size, in bytes, of the data pointed to by lpData.

I decided to make a program that sets the aforementioned Active Scripting setting to 3, which disables JavaScript (hooray!) and as such is a very worthy program function. Our program looks like this:

#include <winreg.h>

int STDCALL
WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
{

HKEY MyKey;
int valuevalue = 3;

RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3\0", 0, KEY_WRITE, &MyKey);

RegSetValueEx(MyKey,"1400\0",0,REG_DWORD,&valuevalue,sizeof(int));

RegCloseKey (MyKey);

return 0;

}

Back to the main page