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)