Working with the Windows Registry in C++

The Windows Registry is a crucial part of each Microsoft Windows-based operating system. It acts exactly like a directory, storing all kinds of user settings, options, and configuration data about applications, file associations, user policies, and so forth. Therefore, the ability to work with the registry is something that can’t be missing from the arsenal of a software programmer. In this article we are going to learn how to accomplish this task in C++.

Contributed by
Rating: 4 stars4 stars4 stars4 stars4 stars / 24
April 02, 2008
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

We are going to approach this situation using dedicated API functions that allow us to work with the registry. During this article we’ll learn how to create a console-based application that will be able to do the following: open a specified subkey, create and set a new value, create a new subkey, delete subkeys and values, and dump the content of a particular “tree” (or the whole registry) into a file. We won’t use additional libraries!

However, at first we’re going to refresh our memory of the structure of the registry so that we crush any possible dilemmas regarding particular terminology such as keys, values, subkeys, name-data pairs, trees, hive, and such. Then we will proceed to creating our application, taking a step-by-step approach while thoroughly explaining the correct usage of the registry functions.

I wouldn’t classify the required skill level for this tutorial higher than intermediate. Learning how to work with the registry using the soon-to-be-presented functions is almost as easy as learning a Hello World example, if you already know the way the registry works. I foresee that following along will be easy even for a beginner that is familiar with the syntax of C++.

All of this being said – I invite you to join us for the tutorial.

The Basics

It’s important to understand the structure of the registry so that there won’t be any confusion during our explanations later on. Here we’ll be very quick and right on topic because we don’t have time to waste. First of all, you may imagine the registry as a folder. It can have folders and files within it. Now let’s see how we call these.

The Windows registry contains the following two elements: keys and values. Keys stand for folders of a sort (branches) while the values represent files in our analogy. In reality, values are name-data pairs, meaning that a value is split into two parts: name and data. The name is used for identification purposes and the data part is the actual data.

Each of the keys can have values but also subkeys. The entire registry is split into logical sections that are called hives. These are the HKCR, HKCU, HKLM, HKU, and HKCC. The whole registry in its entirety is sometimes called the root hive.

Now my final suggestion before we begin is that you should open your Registry Editor (regedit.exe or regedt32.exe) and look around a bit. Once you can find your way around with ease inside the structure of the your registry, you should be prepared. Oh, and you should backup your registry just in case. However, we won’t do any harm!

Basic Registry Functions

During this tutorial we are going to learn how to read from, modify, and write to the registry. In this section we’ll cover some of the basic functions for opening subkeys and working with them, while in the next section we’ll code our registry dump application. Launch your Visual Studio IDE and create a new Win32 console application. Don’t forget to check the checkboxes of precompiled header files as well as MFC.

The functions we’re going to work with can be found in the following places: windows.h header file, Advapi32.lib library file requiring Advapi32.dll. And they work with any NT-based Windows OS such as 2000, XP, 2003, Vista, and 2008 Server.

Our first function is RegOpenKeyEx(). This function opens a specified registry key and returns ERROR_SUCCESS on success. It’s important to understand that this function only opens the desired key if it already exists; it does not create a new key if the specified key is nonexistent. Let’s see how to use it.

HKEY hKey;

If (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SoftwareDevShed TutorialTest"), 0, KEY_ALL_ACCESS, &hKey)!=ERROR_SUCCESS)

   printf("nError opening the desired subkey (doesn't exist?).n");

Else

   Printf("nSucceess!");

In the above example we’ve also declared an hKey variable that’s HKEY type. It will serve us for the handle of the specified key. Also, as you can see we’ve opted for the KEY_ALL_ACCESS type of permission so that we could have full access.

Now let’s add some functionality to it. We’ll use the RegSetValueEx() function to create a new value in our hKey. For the purpose of this article, we are going to create a new string value.

unsigned char szStr[2];

szStr[0]='1'; szStr[1]='';

if (RegSetValueEx(hKey, TEXT("String Value"), NULL, REG_SZ, szStr, sizeof(szStr))==ERROR_SUCCESS)

   printf("nThe value of the key was set successfully.n");

else

   printf("nError setting the value of the key.n");

RegCloseKey(hKey);

The above code snippet is pretty straightforward. We declared an unsigned char array with two elements and we built it up with a ‘1’ and the EOF character. This variable will serve as the data in our string value. We create the new “String Value” value using the RegSetValueEx() function. Reg_SZ stands for the null-terminated string value data type. At the end we also close this hKey because we’ve finished dealing with it.

Now let’s see how can we create a new subkey ourselves and then do some deleting too. The RegCreateKeyEx() function will be used to create a new key, while for deleting we’ll opt for RegDeleteValue(). If you are using Vista or Win2008 Server then you may also use RegDeleteTree(). With it you delete a whole tree. It’s not present in earlier versions of Windows. But we’ll still present its usage.

DWORD dwDisposition;

HKEY hKey;

RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("SoftwareDevShed TutorialTestAnother SubKey"), 0, NULL, 0, 0, NULL, &hKey, &dwDisposition);

if (dwDisposition != REG_CREATED_NEW_KEY && dwDisposition != REG_OPENED_EXISTING_KEY)

       printf("nError creating the desired key (permissions?).n");

else

       printf("nThe key was successfully created.n");

RegCloseKey(hKey);

The dwDisposition DWORD variable is used to identify whether the key has been created (if it was nonexistent) or if it already existed, and whether it could be opened successfully with writing permissions. After this you may add the required actions. Don’t forget to close the key.

Finally, let’s find out how to “clean up” the registry by learning delete functions.

if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SoftwareDevShed TutorialTest"), 0, KEY_ALL_ACCESS, &hKey)==ERROR_SUCCESS)

{

   if (RegDeleteValue(hKey, TEXT("String Value"))==ERROR_SUCCESS)

      printf("nString Value value successfully removed.n");

   else

      printf("nError removing the specified value. n");

   //--->>> requires Windows VISTA and/or Windows 2008 Server <<<---

   #if WINVER >= 0x0600

   { 

      printf("nWindows Vista or Win2008 Server Platform detected.");

      if (RegDeleteTree(hKey, NULL)==ERROR_SUCCESS)

         printf("nThe subkey we created was removed as a tree.");

      else

         printf("nError removing the specified subkey tree.");

   }

   #else

      printf("nSkipping this part - no Vista or Win2008 Server.n");

   #endif

   //--->>> requires Windows VISTA and/or Windows 2008 Server <<<---

}

else

   printf("nError opening the specified subkey path (doesn't exist?).n");

RegCloseKey(hKey);

The above code snippet opens our DevShed TutorialTest subkey and then deletes our “String Value” value that we created a while ago if you still remember. Of course, as you can see we followed these actions with error handling so that if something goes wrong you can immediately locate the source of problem. Ultimately, if you are on a Vista-based OS then you can use the RegDeleteTree() too.

By now you should understand how to open and create keys and values, work with them, and delete them. Now we can move on and create a recursive method that exports each and every subkey of a particular (sub)key. Additionally, we’ll code our registry dumper, too. There we will also learn about privileges and tokens!

More Registry Stuff

On the previous page I mentioned that here we’ll create a block of code that works recursively and enumerates the subkeys of the specified subkey. Since it’s recursive, the method calls itself and goes further (deeper) with each step until it reaches the bottom (end of the tree) and then continues along.

Here’s how we call our RecurseEnumKeys() method. Don’t forget to declare its prototype at the top of your source file if you are coding using the top-down principle.

RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SoftwareDevShed Tutorial"), 0, KEY_ALL_ACCESS, &hKey);

RecurseEnumKeys(hKey, 0);

RegCloseKey(hKey);

Now let’s see how the recursive method itself is written. We have two parameters. The first one is our hKey handle while the second is the level (how deep are we inside our subkey; you may need to use it later on even if we don’t use it right now in this snippet). We declare a few necessary variables at the beginning which will be used while calling the RegEnumKeyEx() function. dwIdx is the Index, szKeyName is the key name string, dwSize is the size for the keys, while fTime is a filetime variable.

void RecurseEnumKeys(HKEY hKey, DWORD level)

{

   DWORD dwIdx=0;

   TCHAR szKeyName[1024];

   DWORD dwSize=1024;

   FILETIME fTime;

   while(RegEnumKeyEx(hKey, dwIdx, szKeyName, &dwSize, NULL, NULL, NULL, &fTime) == ERROR_SUCCESS)

   {

       _tprintf(_T("\%s"),szKeyName);

       dwIdx++;

       HKEY hSubKey;

       if (RegOpenKeyEx(hKey, szKeyName, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)

       {

          RecurseEnumKeys(hSubKey, level+1);

          RegCloseKey(hSubKey);

       }

       printf("n");

   }

}

We simply move alongside the tree by calling its subkeys and moving deeper and deeper until we reach the bottom of the tree and then continue along, picking up the next subkey path (if there is one) and going on and on using the same methodology until we finish. Error handling is also included so that you can identify errors right away.

Now let’s see how we are going to accomplish the dumping action. By dumping I mean exporting the contents of a particular subkey from the registry (or the entire registry per se – but that takes time and a little bit of disk space). The process per se isn’t hard at all but unfortunately it requires a certain “special privilege” to be enabled for the access token. It is disabled by default. Yes, even for Administrator profiles.

I’m talking about the SE_BACKUP_NAME privilege. We are going to use the RegSaveKeyEx() function which does the job well; however, it requires the aforementioned privilege to be enabled (TRUE), otherwise it won’t work. This privilege allows the particular process for backup actions (such as using the RegSaveKeyEx for backing up).

At first we will present our algorithm and then we’ll write a function that sets any explicitly specified privilege for any process token. This function will be called ModifyPrivilege(). We're going to call it for the SE_BACKUP_NAME privilege and ask for it to enable the privilege for us – “making it TRUE.”

int hr = ModifyPrivilege(SE_BACKUP_NAME, TRUE);

if (hr != S_OK)

   printf("nThe necessary SE_BACKUP_NAME privilege couldn't be enabled (no admin rights?).");

if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control PanelDesktop"), 0, KEY_ALL_ACCESS, &hKey)==ERROR_SUCCESS && RegSaveKeyEx(hKey, TEXT("C:dump.txt"), NULL, REG_LATEST_FORMAT)==ERROR_SUCCESS)

   printf("nSuccessfully dumped the contents of the specified hive.");

RegCloseKey(hKey);

Also, make sure that the output file does not exist already because our code doesn’t overwrite it. This is important; if you are playing around and have trouble figuring out why the file doesn’t update, this is why. You may implement a workaround but that’s not the point of our tutorial. Let’s stick with the topic.

Below you can see our ModifyPrivilege() function. In the above code snippet we call this function for the SE_BACKUP_NAME and TRUE parameters. The function returns either an S_OK on success or ERROR_FUNCTION_FAILED in case of errors. But for the purpose of this tutorial I’ve added error handling after each step. Check it out!

HRESULT ModifyPrivilege(LPCTSTR szPrivilege, BOOL bEnable)

{

   HRESULT hr=S_OK;           // assuming success

   TOKEN_PRIVILEGES NewTokenPrivileges;

   LUID luid;

   HANDLE hToken=NULL;

   // we open the processtoken of the current process

   if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))

   {

       printf("OpenProcessToken - Fail!n");

       return ERROR_FUNCTION_FAILED;

   }

   printf("OpenProcessToken - Success!n");

   // we lookup the local unique ID for the required privilege

   if (!LookupPrivilegeValue(NULL, szPrivilege, &luid))

   {

       CloseHandle(hToken);

       printf("LookupPrivilegeValue - Fail!n");

       return ERROR_FUNCTION_FAILED;

   }

   printf("LookupPrivilegeValue - Success!n");

   // we assign the values to the new token privileges struct

   NewTokenPrivileges.PrivilegeCount=1;

   NewTokenPrivileges.Privileges[0].Luid=luid;

   NewTokenPrivileges.Privileges[0].Attributes=(bEnable ? SE_PRIVILEGE_ENABLED : 0);

   // we overwrite the current token privileges with the new ones

   if (!AdjustTokenPrivileges(hToken, FALSE, &NewTokenPrivileges, 0, NULL, NULL))

   {

       CloseHandle(hToken);

       printf("AdjustTokenPrivileges - Fail!n");

       printf("nError: %un", GetLastError());

       return ERROR_FUNCTION_FAILED;

   }

   printf("AdjustTokenPrivileges - Success!n");

   CloseHandle(hToken);

   return hr;

}

This implementation is from Microsoft’s MSDN Library. The original source of the algorithm and code is here. I’ve slightly adjusted it to fit our purposes and managed its error handling and clarity so that it’s easier to understand the way it works. However, it's worth checking out the original MSDN article too.

Now let’s explain how it works. We declare a few necessary variables and assume success (our hr variable gets S_OK). We proceed to open the process token of our current process using the OpenProcessToken() function. We have a handle which will point to our required token. With the help of GetCurrentProcess() we’ll find out its token. After we successfully open the token of our process we look up the ID (unique and local) for the specified privilege (which in our case is SE_BACKUP_NAME).

Once we’ve done this too, we notify the user that we arrived at this point, and we start to build our NewState token_privileges struct. It’s going to contain only one privilege (thus Count = 1), Luid stands for its local unique ID, and the attribute for the privilege is of course the boolean fEnable parameter of our function. In our case we’ll call it for TRUE so we create our NewState struct specifying TRUE for our privilege.

After this we have two more things left to do. One is to actually adjust the token privileges for our token using the AdjustTokenPrivileges() function. Don’t forget that we’ve already opened our token and we have a handle (hToken) that points to it. So we just call it for our NewState struct. Error handling is also included. Finally, we need to close our handle for the token of our process and then return the results.

I truly hope that my above explanations and the comments in the block of code above helped you to understand and comprehend the algorithm and its implementation. But if you couldn’t follow along, have no fear because you can download the source code of the entire project that we created during this tutorial in archived format (ZIP).

Final Words

That’s all – we’ve arrived at the end of this tutorial. We have explored the ways we can manage and work with the Windows Registry without additional libraries, relying totally on the built-in functions. We have included examples and code snippets to describe their correct usage.

Then as we became more and more familiar with working with the registry in C++, we also created a recursive enumeration method and a dumping function. You can use the latter to export hives or parts of your registry to a file. Later on, you can also import them, of course. However, this required us to look into and endeavor into the somewhat dark world of special privileges and find a means of implementation.

On the previous page you could also download the source of the project we coded during this tutorial if you experienced some difficulty in following along. Check out the screenshot below to see its output in a command prompt – that’s what it did for me (under a non-Vista platform).

Please do understand that this tutorial mainly targets the beginner or intermediate programmer-- generally C++ coders that are familiar with the syntax of language but haven’t had the chance to work with the registry yet. Therefore, I started almost from the beginning but leaped ahead assuming that the reader is able to follow along. It doesn’t target the pros.

The registry is, as I said, a very critical part of Windows. It acts like a huge database storing configuration data about applications and lots of additional information such as group policies, associates, and such. Whether you are designing a stand-alone application that works on Windows or just writing a simple script for administrative purposes, you can bet that working with the registry could make your job easier.

If you still have unanswered questions or are facing some programming issues then don’t hesitate to join our community at “DevHardware Forums” or any other forums in the Shed network that specialize in coding such as the “DevShed Forums.” Our communities are friendly and we’re doing our best to help. See you there.

blog comments powered by Disqus
WINDOWS SCRIPTING ARTICLES

- More Windows Scripting Workarounds from Nilpo
- Overloading Methods and More in VBScript
- Improving MFC for Windows Vista
- Regular Expressions in VBScript
- Working with Dates in WMI
- Completing Calendars with VBScript Date Func...
- Building Calendars with VBScript Date Functi...
- Working With Dates and Times in VBScript
- Designing WCF DataContract Classes Using the...
- Understanding Dates and Times in VBScript
- Working With Arrays in VBScript
- Compressed Folders in WSH
- Using .NET Interops in VBScript
- Nilpo`s Scripting Secrets, Vol I
- Database operations using Silverlight 2.0 WC...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
 
 
 

ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 5 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials