|< Windows Registry Tutorial 1 | Main | Windows Registry Tutorial 3 >| Site Index | Download |


 

 

 

 

MODULE O1

WINDOWS OS

.:: REGISTRY:  STORY & PROGRAM EXAMPLES ::.

PART 2

 

 

 

 

What are in this Module?

  1. Registry Functions

  2. Obsolete Functions

  3. Registry Structures

  4. Registry Element Size Limits

  5. Registry Value Types

  6. String Values

  7. Byte Formats

  8. Creating a Security Descriptor from Scratch for a New Object, a Registry key

  9. Set values to the Registry key

 

 

 

 

 

 

 

 

 

 

 

 

 

My Training Period: xx hours. This is a continuation from previous Windows Registry Tutorial 1. Before you begin, read some instruction here.

 

 

The expected abilities:

  • Able to understand Windows Registry.

  • Able to understand and use functions to manipulate Windows Registry.

  • Able to gather and understand the required information in order to use those functions.

Registry Functions

 

The following are the registry functions.

 

Function

Description

RegCloseKey()

Releases a handle to the specified registry key.

RegConnectRegistry()

Establishes a connection to a predefined registry handle on another computer.

RegCreateKeyEx()

Creates the specified registry key.

RegDeleteKey()

Deletes a subkey.

RegDeleteValue()

Removes a named value from the specified registry key.

RegDisablePredefinedCache()

Disables the predefined registry handle table of HKEY_CURRENT_USER for the specified process.

RegEnumKeyEx()

Enumerates subkeys of the specified open registry key.

RegEnumValue()

Enumerates the values for the specified open registry key.

RegFlushKey()

Writes all the attributes of the specified open registry key into the registry.

RegGetKeySecurity()

Retrieves a copy of the security descriptor protecting the specified open registry key.

RegLoadKey()

Creates a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and stores registration information from a specified file into that subkey.

RegNotifyChangeKeyValue()

Notifies the caller about changes to the attributes or contents of a specified registry key.

RegOpenCurrentUser()

Retrieves a handle to the HKEY_CURRENT_USER key for the user the current thread is impersonating.

RegOpenKeyEx()

Opens the specified registry key.

RegOpenUserClassesRoot()

Retrieves a handle to the HKEY_CLASSES_ROOT key for the specified user.

RegOverridePredefKey()

Maps a predefined registry key to a specified registry key.

RegQueryInfoKey()

Retrieves information about the specified registry key.

RegQueryMultipleValues()

Retrieves the type and data for a list of value names associated with an open registry key.

RegQueryValueEx()

Retrieves the type and data for a specified value name associated with an open registry key.

RegReplaceKey()

Replaces the file backing a registry key and all its subkeys with another file.

RegRestoreKey()

Reads the registry information in a specified file and copies it over the specified key.

RegSaveKey()

Saves the specified key and all of its subkeys and values to a new file.

RegSetKeySecurity()

Sets the security of an open registry key.

RegSetValueEx()

Sets the data and type of a specified value under a registry key.

RegUnLoadKey()

Unloads the specified registry key and its subkeys from the registry.

 

Table 6.

 

The following shell functions can be used with the registry.

  1. AssocCreate()

  2. AssocQueryKey()

  3. AssocQueryString()

  4. AssocQueryStringByKey()

  5. SHCopyKey()

  6. SHDeleteEmptyKey()

  7. SHDeleteKey()

  8. SHDeleteValue()

  9. SHEnumKeyEx()

  10. SHEnumValue()

  11. SHGetValue()

  12. SHQueryInfoKey()

  13. SHQueryValueEx()

  14. SHRegCloseUSKey()

  15. SHRegCreateUSKey()

  16. SHRegDeleteEmptyUSKey()

  17. SHRegDeleteUSValue()

  18. SHRegDuplicateHKey()

  19. SHRegEnumUSKey()

  20. SHRegEnumUSValue()

  21. SHRegGetBoolUSValue()

  22. SHRegGetIntW()

  23. SHRegGetPath()

  24. SHRegGetUSValue()

  25. SHRegOpenUSKey()

  26. SHRegQueryInfoUSKey()

  27. SHRegQueryUSValue()

  28. SHRegSetPath()

  29. SHRegSetUSValue()

  30. SHRegWriteUSValue() and

  31. SHSetValue().

 

The following are the initialization-file functions.  They retrieve information from and copy information to a system- or application-defined initialization file.  These functions are provided only for compatibility with 16-bit versions of Windows.  New applications should use the registry.

 

Function

Description

GetPrivateProfileInt()

Retrieves an integer associated with a key in the specified section of an initialization file.

GetPrivateProfileSection()

Retrieves all the keys and values for the specified section of an initialization file.

GetPrivateProfileSectionNames()

Retrieves the names of all sections in an initialization file.

GetPrivateProfileString()

Retrieves a string from the specified section in an initialization file.

GetPrivateProfileStruct()

Retrieves the data associated with a key in the specified section of an initialization file.

GetProfileInt()

Retrieves an integer from a key in the specified section of the Win.ini file.

GetProfileSection()

Retrieves all the keys and values for the specified section of the Win.ini file.

GetProfileString()

Retrieves the string associated with a key in the specified section of the Win.ini file.

WritePrivateProfileSection()

Replaces the keys and values for the specified section in an initialization file.

WritePrivateProfileString()

Copies a string into the specified section of an initialization file.

WritePrivateProfileStruct()

Copies data into a key in the specified section of an initialization file.

WriteProfileSection()

Replaces the contents of the specified section in the Win.ini file with specified keys and values.

WriteProfileString()

Copies a string into the specified section of the Win.ini file.

 

Table 7

 

Obsolete Functions

 

These functions are provided only for compatibility with 16-bit versions of Windows.

RegCreateKey(), RegEnumKey(), RegOpenKey(), RegQueryValue() and RegSetValue().

Registry Structures

 

The structure used with the registry is VALENT

 

Registry Element Size Limits

 

The following are the size limits for the various registry elements.

 

Registry Element

Size Limit

Key name

255 characters.

Value name

16,383 characters. Windows 2000:  260 ANSI characters or 16,383 Unicode characters. Windows Me/98/95:  255 characters.

Value

Available memory. Windows Me/98/95:  16,300 bytes.  There is a 64K limit for the total size of all values of a key.

 

Table 8.

 

Long values (more than 2,048 bytes) should be stored as files with the file names stored in the registry. This helps the registry perform efficiently.

 

Registry Value Types

 

A registry value can store data in various formats.  When you store data under a registry value, for instance by calling the RegSetValueEx() function, you can specify one of the following values to indicate the type of data being stored.  When you retrieve a registry value, functions such as RegQueryValueEx() use these values to indicate the type of data retrieved.  The following registry value types are defined in WinNT.h.

 

Value

Meaning

REG_BINARY

Binary data in any form.

REG_DWORD

A 32-bit number.

REG_DWORD_LITTLE_ENDIAN

A 32-bit number in little-endian format.

Microsoft® Windows® is designed to run on little-endian computer architectures (Intel processor family).  Therefore, this value is defined as REG_DWORD in the Windows header files.

REG_DWORD_BIG_ENDIAN

A 32-bit number in big-endian format.  Some UNIX systems support big-endian architectures such as a system that use Sun SPARC processor.

REG_EXPAND_SZ

Null-terminated string that contains unexpanded references to environment variables (for example, "%PATH%").  It will be a Unicode or ANSI string depending on whether you use the Unicode or ANSI functions.  To expand the environment variable references, use the ExpandEnvironmentStrings() function.

REG_LINK

Reserved for system use.

REG_MULTI_SZ

Array of null-terminated strings, terminated by two null characters.

REG_NONE

No defined value type.

REG_QWORD

A 64-bit number.

REG_QWORD_LITTLE_ENDIAN

A 64-bit number in little-endian format.  Windows is designed to run on little-endian computer architectures.  Therefore, this value is defined as REG_QWORD in the Windows header files.

REG_SZ

Null-terminated string.  It will be a Unicode or ANSI string, depending on whether you use the Unicode or ANSI functions.

 

Table 9.

 

String Values

 

When writing a string to the registry, you must specify the length of the string, including the terminating null character (\0).  A common error is to use the strlen() function to determine the length of the string, but to forget that strlen() returns only the number of characters in the string, not including the terminating null.  Therefore, the length of the string should be calculated as:

 

strlen(string) + 1

 

Note that a REG_MULTI_SZ string, which contains multiple null-terminated strings, ends with two null characters, which must be factored into the length of the string.  For example, a REG_MULTI_SZ string can be represented in memory as follows:

 

string1\0string2\0string3\0laststring\0\0

 

When calculating the length of a REG_MULTI_SZ string, add the length of each of the component strings, as above, and add one for the final terminating null.

 

Byte Formats

 

In little-endian format, a multi-byte value is stored in memory from the lowest byte (the "little end") to the highest byte.  For example, the value 0x12345678 is stored as (0x78 0x56 0x34 0x12) in little-endian format.  In big-endian format, a multi-byte value is stored in memory from the highest byte (the "big end") to the lowest byte.  For example, the value 0x12345678 is stored as (0x12 0x34 0x56 0x78) in big-endian format.

 

----------------------------Program examples-------------------------------

 

Creating a Security Descriptor from Scratch for a New Object, a Registry key

 

The following example (taken from the Access Control Module) creates a security descriptor for a new registry key.  Similar code can be used to create a security descriptor for other object types as well.  The steps:

  1. The example fills an array of EXPLICIT_ACCESS structures with the information for two ACEs.  One ACE allows read access to everyone; the other ACE allows full access to administrators.

  2. The EXPLICIT_ACCESS array is passed to the SetEntriesInAcl() function to create a DACL for the security descriptor.

  3. After allocating memory for the security descriptor, the example calls the InitializeSecurityDescriptor() and SetSecurityDescriptorDacl() functions to initialize the security descriptor and attach the DACL.

  4. The security descriptor is then stored in a SECURITY_ATTRIBUTES structure and passed to the RegCreateKeyEx() function, which attaches the security descriptor to the newly created key.

 

// Creating a security descriptor for a new object,

// a registry key and then delete the key...

 

// #define _WIN32_WINNT 0x0502   // Windows Server 2003 family

// For Win Xp, change accordingly...

#define _WIN32_WINNT 0x0501

// #define _WIN32_WINNT 0x0500   // Windows 2000

// #define _WIN32_WINNT 0x0400   // Windows NT 4.0

// #define _WIN32_WINDOWS 0x0500 // Windows ME

// #define _WIN32_WINDOWS 0x0410 // Windows 98

// #define _WIN32_WINDOWS 0x0400 // Windows 95

 

#include <windows.h>

#include <stdio.h>

#include <aclapi.h>

 

// Buffer clean up routine

void Cleanup(PSID pEveryoneSID, PSID pAdminSID, PACL pACL, PSECURITY_DESCRIPTOR pSD, HKEY hkSub)

{

    if(pEveryoneSID)

        FreeSid(pEveryoneSID);

    if(pAdminSID)

        FreeSid(pAdminSID);

    if(pACL)

        LocalFree(pACL);

    if(pSD)

        LocalFree(pSD);

    if(hkSub)

        RegCloseKey(hkSub);

}

 

int main(int argc, char *argv[])

{

    DWORD dwRes, dwDisposition;

    PSID pEveryoneSID = NULL, pAdminSID = NULL;

    PACL pACL = NULL;

    PSECURITY_DESCRIPTOR pSD = NULL;

    // An array of EXPLICIT_ACCESS structure

    EXPLICIT_ACCESS ea[2];

    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;

    SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;

    SECURITY_ATTRIBUTES sa;

    LONG lRes;

    HKEY hkSub = NULL;

    // Create a well-known SID for the Everyone group.

    if(!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID,

                     0, 0, 0, 0, 0, 0, 0, &pEveryoneSID))

    {

        printf("AllocateAndInitializeSid() error %u\n", GetLastError());

        Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);

    }

    else

        printf("AllocateAndInitializeSid() for the Everyone group is OK\n");

    // Initialize an EXPLICIT_ACCESS structure for an ACE. The ACE will allow Everyone read access to the key.

    ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS));

    ea[0].grfAccessPermissions = KEY_READ;

    ea[0].grfAccessMode = SET_ACCESS;

    ea[0].grfInheritance= NO_INHERITANCE;

    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;

    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;

    ea[0].Trustee.ptstrName  = (LPTSTR) pEveryoneSID;

    // Create a SID for the BUILTIN\Administrators group.

    if(!AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID,

                     DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSID))

    {

         printf("AllocateAndInitializeSid() error %u\n", GetLastError());

         Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);

    }

    else

         printf("AllocateAndInitializeSid() for the BUILTIN\\Administrators group is OK\n");

    // Initialize an EXPLICIT_ACCESS structure for an ACE. The ACE will allow the Administrators group full access to the key.

    ea[1].grfAccessPermissions = KEY_ALL_ACCESS;

    ea[1].grfAccessMode = SET_ACCESS;

    ea[1].grfInheritance= NO_INHERITANCE;

    ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;

    ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;

    ea[1].Trustee.ptstrName  = (LPTSTR) pAdminSID;

    // Create a new ACL that contains the new ACEs.

    dwRes = SetEntriesInAcl(2, ea, NULL, &pACL);

    if(dwRes != ERROR_SUCCESS)

    {

       printf("SetEntriesInAcl() error %u\n", GetLastError());

       Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);

    }

    else

       printf("SetEntriesInAcl() for the Administrators group is OK\n");

    // Initialize a security descriptor. 

    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);

    if(pSD == NULL)

    {

        printf("LocalAlloc() error %u\n", GetLastError());

        Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);

    }

    else

       printf("LocalAlloc() is OK\n");

 

    if(!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))

    {

       printf("InitializeSecurityDescriptor Error %u\n", GetLastError());

       Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);

    }

    else

       printf("InitializeSecurityDescriptor() is OK\n");

    // Add the ACL to the security descriptor.

    if(!SetSecurityDescriptorDacl(pSD,

            TRUE,     // bDaclPresent flag  

            pACL,

            FALSE))   // not a default DACL

    {

       printf("SetSecurityDescriptorDacl() Error %u\n", GetLastError());

       Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);

    }

    else

       printf("SetSecurityDescriptorDacl() is OK\n");

    // Initialize a security attributes structure.

    sa.nLength = sizeof(SECURITY_ATTRIBUTES);

    sa.lpSecurityDescriptor = pSD;

    sa.bInheritHandle = FALSE;

 

    //******************* Registry key **********************

    // Use the security attributes to set the security descriptor

    // when you create a registry key.

    // make the subkey as char...

    #define MAX_KEY_NAME 255

    char cName[MAX_KEY_NAME] = "AnotherTestKey";  // Change accordingly...

    HKEY hKey = HKEY_CURRENT_USER; // Change to other key accordingly...

 

    lRes = RegCreateKeyEx(hKey, // handle to an open key

              cName,        // name of the subkey

              0,                 // Reserved, must be 0

              "",                // class or object type of this key, may be ignored

              0,                // Options

               KEY_ALL_ACCESS, // Access right for the key

              &sa,              // Pointer to security attribute structure, can be inherited or not. NULL is not inherited

              &hkSub,       // variable that receives a handle to the opened or created key

              &dwDisposition);  // variable that receives:

                             // REG_CREATED_NEW_KEY - create new key (non-exist)

                             // REG_OPENED_EXISTING_KEY - just open the existing key (already exist)

       // If successful

       if(lRes == 0)

       {

           printf("The value of the \'&dwDisposition\': %u\n", dwDisposition);

           printf("HKEY_CURRENT_USER\\%s successfully created.\n", cName);

       }

       else

           printf("Creating and opening HKEY_CURRENT_USER\\%s is failed.\n", cName);

        // TODO: Call other functions such as setting the key values...

        // Just to see the key has been created before it is deleted...

        // You can verify through the regedit/regedt32...

       system("pause");

       // Then delete the subkey...

       LONG res = RegDeleteKey(

                           hKey,      // The key

                           cName   // The subkey

                           );

       if(res == ERROR_SUCCESS)

          printf("HKEY_CURRENT_USER\\%s successfully deleted.\n", cName);

 

       RegCloseKey(hKey);

    return 0;

}

 

A sample output:

AllocateAndInitializeSid() for the Everyone group is OK

AllocateAndInitializeSid() for the BUILTIN\Administrators group is OK

SetEntriesInAcl() for the Administrators group is OK

LocalAlloc() is OK

InitializeSecurityDescriptor() is OK

SetSecurityDescriptorDacl() is OK

The value of the '&dwDisposition': 1

HKEY_CURRENT_USER\AnotherTestKey successfully created.

Press any key to continue . . .

HKEY_CURRENT_USER\AnotherTestKey successfully deleted.

Press any key to continue

The following screenshot is the verification through the regedt32/regedit before the created key was deleted.

 

A new registry key was created

 

Figure 11: A new registry key was created.

 

 

Set values to the Registry key

 

You can use the default Application log without adding an event source to the registry.  However, Event Viewer will not be able to map your event identifier codes to message strings unless you register your event source and provide a message file.

You can add a new source name to the registry by opening a new registry subkey under the Application key or a custom log using the RegCreateKey() function, and adding registry values to the new subkey using the RegSetValueEx() function.  The following example opens a new source and adds a message-file name and a bitmask of supported types.

 

// WARNING!!!

// If you don't know what you are doing, please don't try

// this code...and don't forget to delete the key or use

// RegDeleteKey()...

 

// #define _WIN32_WINNT 0x0502   // Windows Server 2003 family

// For Win Xp, change accordingly...

#define _WIN32_WINNT 0x0501

// #define _WIN32_WINNT 0x0500   // Windows 2000

// #define _WIN32_WINNT 0x0400   // Windows NT 4.0

// #define _WIN32_WINDOWS 0x0500 // Windows ME

// #define _WIN32_WINDOWS 0x0410 // Windows 98

// #define _WIN32_WINDOWS 0x0400 // Windows 95

 

#include <windows.h>

#include <stdio.h>

#include <aclapi.h>

 

BOOL AddMyEventSource(

   LPTSTR pszLogName, // Application log or a custom log

   LPTSTR pszSrcName, // event source name

   LPTSTR pszMsgDLL,  // path for message DLL

   DWORD  dwNum)      // number of categories

{

   HKEY hk;

   DWORD dwData;

   TCHAR szBuf[MAX_PATH];

 

   // Create the event source as a subkey of the log.

   wsprintf(szBuf, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s", pszLogName, pszSrcName);

 

   //********************************************

   // Create the registry key

   if(RegCreateKey(HKEY_LOCAL_MACHINE, szBuf, &hk))

   {

      printf("Could not create the registry key.");

      return FALSE;

   }

   else

       printf("SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s created successfully.\n", pszLogName, pszSrcName);

 

   //********************************************

   // Set the name of the message file.

    if(RegSetValueEx(hk,                   // subkey handle

           "EventMessageFile",             // value name

           0,                                              // must be zero

           REG_EXPAND_SZ,             // value type

           (LPBYTE) pszMsgDLL,        // pointer to value data

           (DWORD) lstrlen(szBuf)+1)) // length of value data

   {

      printf("Could not set the event message file.");

      return FALSE;

   }

   else

      printf("The event message file has been set successfully.\n");

   // Set the supported event types.

   dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;

 

   //********************************************

   if(RegSetValueEx(hk,        // subkey handle

           "TypesSupported",    // value name

           0,                                 // must be zero

           REG_DWORD,         // value type

           (LPBYTE) &dwData,  // pointer to value data

           sizeof(DWORD)))    // length of value data

   {

      printf("Could not set the supported types.");

      return FALSE;

   }

   else

      printf("The supported types have been set successfully.\n");

   //********************************************************

   // Set the category message file and number of categories.

   if(RegSetValueEx(hk,                    // subkey handle

           "CategoryMessageFile",      // value name

           0,                                             // must be zero

           REG_EXPAND_SZ,             // value type

           (LPBYTE) pszMsgDLL,        // pointer to value data here we set same as "EventMessageFile"

           (DWORD) lstrlen(szBuf)+1)) // length of value data

   {

      printf("Could not set the category message file.");

      return FALSE;

   }

   else

       printf("The category message file has been set successfully.\n");

   //********************************************

   if(RegSetValueEx(hk,          // subkey handle

           "CategoryCount",        // value name

           0,                                   // must be zero

           REG_DWORD,          // value type

           (LPBYTE) &dwNum,   // pointer to value data

           sizeof(DWORD)))    // length of value data

   {

      printf("Could not set the category count.");

      return FALSE;

   }

   else

      printf("The category count has been set successfully.\n");

   // Close the key

   RegCloseKey(hk);

 

   return TRUE;

}

 

int main(int argc, wchar_t *argv[ ])

{

   // Application log or a custom log. Here we put a custom log just for learning!

   LPTSTR pszLogName = "MyCustLogTest";

   // The event source name

   LPTSTR pszSrcName = "MyEventSrcName";

   // The path for message dll, this dll or other executable file must exist lol!

   // here, mytestdll.dll just a dummy. You will know it when you restart

   // your computer if the created key does not deleted...:o)

   LPTSTR pszMsgDLL = "%SystemRoot%\\System32\\mytestdll.dll";

   // number of categories.

   DWORD  dwNum = 0x00000003;

 

   BOOL test = AddMyEventSource(

                   pszLogName, // Application log or a custom log.  Custom log here...

                   pszSrcName, // event source name.

                   pszMsgDLL,  // path for message DLL.

                   dwNum           // number of categories.

                   );

   // Just to check the return value...

   printf("The AddMyEventSource() return value is: %u\n", test);

 

       return 0;

}

 

A sample output:

SYSTEM\CurrentControlSet\Services\EventLog\MyCustLogTest\MyEventSrcName created successfully.

The event message file has been set successfully.

The supported types have been set successfully.

The category message file has been set successfully.

The category count has been set successfully.

The AddMyEventSource() return value is: 1

Press any key to continue

 

Creating registry key, subkey and values

 

Figure 12: Registry key, subkey and values have been created.

 

 

---------------------------Windows Registry: Story and Program Examples, Part I-----------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

 

  1. For Multibytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).

  2. Structure, enum, union and typedef story can be found C/C++ struct, enum, union & typedef.

  3. Check the best selling C, C++ and Windows books at Amazon.com.

  4. Microsoft Visual C++, online MSDN.

  5. MSDN library.

  6. Notation used in MSDN is Hungarian Notation instead of CamelCase and is discussed Windows programming notations.

  7. Windows data type information is in Windows data types used in Win32 programming.

 

 

 

 

 

 

 

|< Windows Registry Tutorial 1 | Main | Windows Registry Tutorial 3 >| Site Index | Download |