How to manipulate REG_MULTI_SZ values from the registry (C++)

Hi all,

The other day I had to develop a small C++ sample which shows how to read the list of values of a REG_MULTI_SZ from the registry, and add a new value just after one of the values of the list. Additionally, I used methods and constants from tchar.h extensively, so it didn't matter if I compiled the code as UNICODE or ANSI. Here is the code:

 

 #include "windows.h"
#include "tchar.h"
#include "conio.h"
#include "stdio.h"

#define MY_KEY _T("PathToMyRegistryKey\\MyRegistryKey") // Registry key
#define MY_VALUES _T("NameOfTheREG_MULTI_SZListOfValues") // Registry values
#define NEW_VALUE _T("MyNewValue") // New value
#define FIND_VALUE _T("AnExistingValue") // We will insert the new value after this one

int _tmain(int argc, _TCHAR* argv[])
{
 LONG lResult = 0;
   HKEY hKey = NULL;
   LPTSTR lpValues = NULL;
 LPTSTR lpValue = NULL;
  LPTSTR lpNewValues = NULL;
  LPTSTR lpNewValue = NULL;
   DWORD cbValues = 0;
 DWORD cbNewValues = 0;
  DWORD cbNewValue = 0;
   BOOL bFound = FALSE;

    __try 
  {
       // OPEN THE REGISTRY KEY
        //
      _tprintf(_T("RegOpenKeyEx..."));
        lResult = RegOpenKeyEx(
         HKEY_LOCAL_MACHINE, 
            MY_KEY, 
            0,
          KEY_ALL_ACCESS,
         &hKey
       );
      if (ERROR_SUCCESS != lResult) { _tprintf(_T("ERROR 0x%x\n"), lResult); return 1; } 
     _tprintf(_T("SUCCESS\n"));

      // READ THE REG_MULTI_SZ VALUES
     //
      // Get size of the buffer for the values
        _tprintf(_T("RegQueryValueEx..."));
     lResult = RegQueryValueEx(
          hKey,
           MY_VALUES,
          NULL,
           NULL,
           NULL,
           &cbValues
       );
      if (ERROR_SUCCESS != lResult) { _tprintf(_T("ERROR 0x%x\n"), lResult); return 1; } 
     _tprintf(_T("SUCCESS\n"));

      // Allocate the buffer
      _tprintf(_T("malloc..."));
      lpValues = (LPTSTR)malloc(cbValues);
        if (NULL == lpValues) { _tprintf(_T("ERROR 0x%x\n"), GetLastError()); return 1; } 
      _tprintf(_T("SUCCESS\n"));

      // Get the values
       _tprintf(_T("RegQueryValueEx..."));
     lResult = RegQueryValueEx(
          hKey,
           MY_VALUES, 
         NULL,
           NULL,
           (LPBYTE)lpValues,
           &cbValues
       );
      if (ERROR_SUCCESS != lResult) { _tprintf(_T("ERROR 0x%x\n"), lResult); return 1; } 
     _tprintf(_T("SUCCESS\n"));

      // SHOW THE VALUES
      //
      _tprintf(_T("\n**************************\n"));
     _tprintf(_T("OLD VALUES\n"));
       _tprintf(_T("**************************\n\n"));
     lpValue = lpValues;
     for (; '\0' != *lpValue; lpValue += _tcslen(lpValue) + 1)
       {
           // Show one value
           _tprintf(_T("%s\n"), lpValue);
      }
       _tprintf(_T("\n**************************\n\n"));

       // INSERT A NEW VALUE AFTER A SPECIFIC VALUE IN THE LIST OF VALUES
      //
      // Allocate a new buffer for the old values plus the new one
        _tprintf(_T("malloc..."));
      cbNewValue = (_tcslen(NEW_VALUE) + 1) * sizeof(TCHAR);
      cbNewValues = cbValues + cbNewValue;
        lpNewValues = (LPTSTR)malloc(cbNewValues);
      if (NULL == lpNewValues) { _tprintf(_T("ERROR 0x%x\n"), GetLastError()); return 1; } 
       _tprintf(_T("SUCCESS\n"));      

        // Find the value after which we will insert the new one
        lpValue = lpValues;
     lpNewValue = lpNewValues;
       bFound = FALSE;
     for (; '\0' != *lpValue; lpValue += _tcslen(lpValue) + 1)
       {
           // Copy the current value to the target buffer
          memcpy(lpNewValue, lpValue, (_tcslen(lpValue) + 1) * sizeof(TCHAR));

            if (0 == _tcscmp(lpValue, FIND_VALUE))
          {
               // The current value is the one we wanted to find
               bFound = TRUE;

              // Copy the new value to the target buffer
              lpNewValue += _tcslen(lpValue) + 1;
             memcpy(lpNewValue, NEW_VALUE, (_tcslen(NEW_VALUE) + 1) * sizeof(TCHAR));
                lpNewValue += _tcslen(NEW_VALUE) + 1;
           }
           else
            {
               // This is not the value we want, continue to the next one
              lpNewValue += _tcslen(lpValue) + 1;
         }
       }
       if (!bFound) 
       { 
          // We didn't find the value we wanted. Insert the new value at the end
          memcpy(lpNewValue, NEW_VALUE, (_tcslen(NEW_VALUE) + 1) * sizeof(TCHAR));
            lpNewValue += _tcslen(NEW_VALUE) + 1;
       }
       *lpNewValue = *lpValue;

     // SHOW THE NEW VALUES
      //
      _tprintf(_T("\n**************************\n"));
     _tprintf(_T("NEW VALUES\n"));
       _tprintf(_T("**************************\n\n"));
     lpNewValue = lpNewValues;
       for (; '\0' != *lpNewValue; lpNewValue += _tcslen(lpNewValue) + 1)
      {
           // Show one value
           _tprintf(_T("%s\n"), lpNewValue);
       }
       _tprintf(_T("\n**************************\n\n"));

       // WRITE THE NEW VALUES BACK TO THE KEY
     //
      _tprintf(_T("RegSetValueEx..."));
       lResult = RegSetValueEx(
            hKey,
           MY_VALUES, 
         NULL,
           REG_MULTI_SZ,
           (LPBYTE)lpNewValues,
            cbNewValues
     );
      if (ERROR_SUCCESS != lResult) { _tprintf(_T("ERROR 0x%x\n"), lResult); return 1; } 
     _tprintf(_T("SUCCESS\n"));
  }
   __finally
   {
       // Clean up 
        //
      if (NULL != lpValues) { free(lpValues); }
       if (NULL != lpNewValues) { free(lpNewValues); }
     if (NULL != hKey) { RegCloseKey(hKey); }

        //_tprintf(_T("\n<<PRESS ANY KEY>>\n"));
        //_getch();
 }

   return 0;
}

Regards,

 

Alex (Alejandro Campos Magencio)