Enumerating, Creating, and Deleting Registry Keys and the Windows API

The RegOpenKeyEx() function retrieves an HKEY open handle that is assigned to an HKEY variable via a pointer to that variable, which is passed in as the fifth and final parameter of the function. The return value for RegOpenKeyEx() is normally ERROR_SUCCESS.

The RegEnumKeyEx() function enumerates the subkey names of an open registry key. The RegEnumKeyEx() function takes 8 parameters. The first parameter of RegOpenKeyEx() is a handle to an open registry key that was opened with the KEY_ENUMERATE_SUB_KEYS access right. The KEY_READ access right encompasses the KEY_ENUMERATE_SUB_KEYS access right.

The second parameter for the RegEnumKeyEx() function is a DWORD value indicating the index of the subkey to retrieve. This DWORD value should be 0 on the first call and then should be incremented on each subsequent call.

The third parameter for the RegNumKeyEx() function is a pointer to the buffer that stores the name of the subkey, including a terminating NULL character. The size limit for a key name is 255 characters. The fourth parameter is a pointer to a DWORD value that indicates the size limit of the buffer we are sending into the function; this size is in characters and includes the terminating NULL character.

The fifth parameter is reserved and must be NULL; the sixth and seventh parameters can be set to NULL, so we will. To be fair, they are rarely used. The final parameter is a pointer to a FILETIME structure.

If the function succeeds, the value is ERROR_SUCCESS.

#include "stdafx.h"
#include <Windows.h>

int main()
{
 const int Max_Key_Length = 256;
 LONG lRValue;
 DWORD dwIndex;
 DWORD dwKeyNameLength = Max_Key_Length;
 HKEY hOpenKey; 

 //let's get an open key 
 //use the HKEY_CURRENT_USER predefined key
 //let's look for the Console subkey
 //third argument is reserved, so 0
 //we want to be able to read and enumerate the subkeys
 //final argument is a pointer to the 
 //HKEY variable
 lRValue = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE"), 0, KEY_READ, &hOpenKey);
 
 //check to see that we opened the key
 if (lRValue == ERROR_SUCCESS) {
 printf("Opened the subkey successfully.\n\n");
 }
 else {
 printf("Error encountered.\n");
 exit(EXIT_FAILURE);
 }

 //let's enumerate the subkeys
 
 //priming read 
 lRValue = RegEnumKeyEx(hOpenKey, dwIndex, keyName, &dwKeyNameLength, 0, NULL, NULL, &structFT);
 while (lRValue == ERROR_SUCCESS) {
 _tprintf(_T("%s\n"), keyName);
 dwKeyNameLength = Max_Key_Length;
 lRValue = RegEnumKeyEx(hOpenKey, ++dwIndex, keyName, &dwKeyNameLength, 0, NULL, NULL, &structFT);
 }

 if (lRValue == ERROR_NO_MORE_ITEMS) {
 printf("\nSubkeys all enumerated successfully.\n\n");
 }

 return 0;
}

We can create a new Registry key with the RegCreateKeyEx() function. If the subkey already exists, then the RegCreateKeyEx() function opens it. The RegCreateKeyEx() function takes 9 parameters.

The first parameter for RegCreateKeyEx() is an open handle to a registry key. We must have KEY_CREATE_SUB_KEY access to the specified key. The second parameter is the name of the subkey to be created or opened. This parameter cannot be NULL.

The third parameter for RegCreateKeyEx() is reserved and so must be set to 0. The fourth parameter can be set to NULL. The fifth parameter is usually set to 0; however, we will set the option to REG_OPTION_VOLATILE, which means that the key created by the function will not be saved. Nonvolatile registry information is stored in a file and saved for when Windows restarts. Volatile registry keys only exist in memory and do not persist between system restarts.

The sixth parameter specifies the security and access rights for the new key. We will use KEY_ALL_ACCESS for this parameter. The seventh parameter is a pointer to a SECURITY_ATTRIBUTES structure; if we specify NULL for this parameter, then the key receives the default security descriptor.

The eighth argument is a pointer to an HKEY handle that will receive the handle to the new key. The ninth and final parameter is a pointer to a DWORD variable the will store one of two values, REG_OPENED_EXISTING_KEY or REG_CREATED_NEW_KEY.

#include "stdafx.h"
#include <Windows.h>

int main()
{
 HKEY hKey, hSubkey;
 DWORD dwDisposition;
 TCHAR *tszSubkeyName = _T("Volatile Environment");
 TCHAR *tszNewkeyName = _T("testing");
 LONG lReturnValue = 0;

 lReturnValue = RegOpenKeyEx(HKEY_CURRENT_USER, tszSubkeyName, 0, KEY_CREATE_SUB_KEY, &hKey);

 if (lReturnValue == ERROR_SUCCESS) {
 _tprintf(_T("Accessed HKEY_CURRENT_USER\\%s\n"), tszSubkeyName);
 }
 else {
 exit(EXIT_FAILURE);
 }

 //create new key
 lReturnValue = RegCreateKeyEx(hKey, tszNewkeyName, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubkey, &dwDisposition);

 if (lReturnValue == ERROR_SUCCESS) {
 printf("Created/opened new subkey.\n");
 if (dwDisposition == REG_OPENED_EXISTING_KEY) {
 _tprintf(_T("%s already exists, is now opened.\n"), tszNewkeyName);
 }
 else {
 _tprintf(_T("%s created, is now opened.\n"), tszNewkeyName);
 }
 }

 //clean up after ourselves
 RegCloseKey(hKey);

 return 0;
}

Note that we use the RegCloseKey() function to close an open handle to a Registry key.

We use the RegDeleteKey() function to delete a key. It is a simple function to use; it takes only two arguments. The first argument is an open key handle, the second is the name of the subkey to be deleted.

#include "stdafx.h"
#include <Windows.h>

int main()
{

 LONG lRValue = 0;

 lRValue = RegDeleteKey(HKEY_CURRENT_USER, _T("Volatile Environment\\testing"));
 
 if (lRValue == ERROR_SUCCESS) {
 printf("The testing subkey was deleted successfully.\n");
 }
 else {
 printf("The testing subkey was not deleted successfully.\n");
 printf("Error %d\n", lRValue);
 if (lRValue == ERROR_FILE_NOT_FOUND) {
 printf("The registry key was not found.\n");
 }
 }

 return 0;
}

Opening a Windows Registry Key with C

The registry is a database for system and application configuration information. We access registry values through registry keys, which in turn can contain other keys, or else key/value pairs.

Information stored in the registry includes the Windows version number, information about the computer’s hardware, user-specific information, security information, installed services, and more.

Several predefined keys function as entry points into the registry. The HKEY_LOCAL_MACHINE key stores physical information about the system, along with information about installed software. The HKEY_USERS key stores user configuration information. The HKEY_CURRENT_USER key stores user-specific information, including environment variables and application preferences. The HKEY_CURRENT_CONFIG key defines current settings, such as display resolution and fonts.

We can access and manage the registry through a number of registry API functions. Registry management functions empower us to query and modify the key/value pairs that make up the registry, as well as create new subkeys and key/value pairs.

The RegOpenKeyEx() function can be used to open a named subkey. The function takes five parameters. The first parameter can be an HKEY handle, or else one of eight predefined keys.

#include "stdafx.h"
#include <Windows.h>

int main()
{
 printf("HKEY_CLASSES_ROOT (%x) - used by shell and COM applications.\n", HKEY_CLASSES_ROOT);
 printf("HKEY_CURRENT_USER (%p) - defines the preferences of the current user.\n", HKEY_CURRENT_USER);
 printf("HKEY_LOCAL_MACHINE (%p) - defines the physical state of the computer, including plug and play informaton.\n", HKEY_LOCAL_MACHINE);
 printf("HKEY_USERS (%p) - defines the default configuration for new users and the configuration for the current user.\n", HKEY_USERS);
 printf("HKEY_CURRENT_CONFIG (%p) - contains information about the current hardware profile of the local system.\n", HKEY_CURRENT_CONFIG);

 return 0;
}

The second parameter is the name of the subkey we wish to open. The subkey can be a path, or we can specify NULL here; this causes a new, duplicate key to be opened. The third parameter is reserved; we must specify 0 here. The fourth parameter is an access mask that describes the security level for the new key.

#include "stdafx.h"
#include <Windows.h>

int main()
{
 printf("KEY_ALL_ACCESS (%p)\n", KEY_ALL_ACCESS);
 printf("KEY_WRITE (%p)\n", KEY_WRITE);
 printf("KEY_QUERY_VALUE (%p)\n", KEY_QUERY_VALUE);
 printf("KEY_ENUMERATE_SUB_KEYS (%p)\n", KEY_ENUMERATE_SUB_KEYS);

 return 0;
}

Note that the function fails if the specified key’s security descriptor does not permit the requested level of access. Upon success, the function returns ERROR_SUCCESS.

 #include "stdafx.h"
#include <Windows.h>

int main()
{
 HKEY hTheKey;
 long long int llRValue;
 
 llRValue = RegOpenKeyEx(
 HKEY_CURRENT_USER, //use predefined key
 NULL, //just open a copy of above
 0, //don't mess with this one
 KEY_QUERY_VALUE, //just asking questions
 &hTheKey //pointer to HKEY variable
 );

 //check the return value
 if (llRValue == ERROR_SUCCESS) {
 printf("Duplicate registry key created!\n");
 }
 else {
 printf("Duplicate registry key not created!\n");
 }

 return 0;
}

We should close an open key handle with the RegCloseKey() function.

#include "stdafx.h"
#include <Windows.h>

int main()
{
 HKEY hOurKey;
 long long llReturn;
 WCHAR wszRegistryKeyName[] = L"SOFTWARE\\Microsoft";


 llReturn = RegOpenKeyEx(
 HKEY_LOCAL_MACHINE,
 wszRegistryKeyName,
 0,
 KEY_READ,
 &hOurKey
 );

 if (llReturn == ERROR_SUCCESS) {
 printf("Key acquired!\n");
 }
 else {
 printf("Key not acquired!\n");
 exit(EXIT_FAILURE);
 }

 //clean up!!!
 RegCloseKey(hOurKey);

 return 0;
}

Note that registry keys are not case sensitive.