/*++ Copyright (c) 1998 Microsoft Corporation Module Name: regrep.c Abstract: Implements a registry search/replace tool. Author: Jim Schmidt (jimschm) 19-Apr-1999 Revision History: jimschm 26-May-1999 Moved from win9xupg, ported to use different utilities Santanuc 14-Feb-2002 Rewrite the RegistrySearchAndReplaceW to use standard registry api rather than going through reg & mem wrapper api's. --*/ #include "pch.h" UINT CountInstancesOfSubStringW ( IN PCWSTR SourceString, IN PCWSTR SearchString, IN UINT SearchChars ) { UINT Count; UINT SourceChars; PCWSTR End; Count = 0; SourceChars = lstrlenW (SourceString); End = SourceString + SourceChars - SearchChars; if (!SearchChars) { return 0; } while (SourceString <= End) { if (!_wcsnicmp (SourceString, SearchString, SearchChars)) { Count++; SourceString += SearchChars; } else { SourceString++; } } return Count; } PWSTR StringSearchAndReplaceW ( IN PCWSTR SourceString, IN PCWSTR SearchString, IN PCWSTR ReplaceString, IN DWORD* pcbNewString ) { PWSTR NewString; PBYTE p; PBYTE Dest; UINT Count; UINT Size; UINT SearchBytes; UINT ReplaceBytes; UINT SearchChars; // // Count occurances within the string // if (pcbNewString) { *pcbNewString = 0; } SearchBytes = ByteCountW (SearchString); SearchChars = SearchBytes / sizeof (WCHAR); ReplaceBytes = ByteCountW (ReplaceString); Count = CountInstancesOfSubStringW ( SourceString, SearchString, SearchChars ); if (!Count) { return NULL; } Size = SizeOfStringW (SourceString) - Count * SearchBytes + Count * ReplaceBytes; NewString = (PWSTR) LocalAlloc(LPTR, Size); if (!NewString) { return NULL; } if (pcbNewString) { *pcbNewString = Size; } p = (PBYTE) SourceString; Dest = (PBYTE) NewString; while (*((PWSTR) p)) { if (!_wcsnicmp ((PWSTR) p, SearchString, SearchChars)) { CopyMemory (Dest, ReplaceString, ReplaceBytes); Dest += ReplaceBytes; p += SearchBytes; } else { *((PWSTR) Dest) = *((PWSTR) p); p += sizeof (WCHAR); Dest += sizeof (WCHAR); } } *((PWSTR) Dest) = 0; return NewString; } VOID RegistrySearchAndReplaceW ( IN HKEY hRoot, IN PCWSTR szKey, IN PCWSTR Search, IN PCWSTR Replace) { HKEY hKey = NULL; HKEY hSubKey = NULL; DWORD dwType; DWORD cchMaxSubKeyName, cchNewMaxSubKeyName; DWORD cchMaxValueName, cchNewMaxValueName, cchLocalValueName; DWORD cbMaxValue, cbNewMaxValue, cbLocalValue, cbNewLocalValue; PWSTR szValueName = NULL, szNewValueName = NULL; PWSTR szSubKeyName = NULL, szNewSubKeyName = NULL; PBYTE pbValue = NULL, pbNewValue = NULL; LONG lResult; DWORD dwIndex; UNICODE_STRING Unicode_String; lResult = RegOpenKey(hRoot, szKey, &hKey); if (ERROR_SUCCESS != lResult) { DEBUGMSG ((DM_VERBOSE, "Fail to open key %s. Error %d", szKey, lResult)); return; } lResult = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, &cchMaxSubKeyName, NULL, NULL, &cchMaxValueName, &cbMaxValue, NULL, NULL); if (ERROR_SUCCESS != lResult) { DEBUGMSG ((DM_VERBOSE, "Fail to query info for key %s. Error %d", szKey, lResult)); goto Exit; } cchMaxSubKeyName++; // Include the terminating NULL cchMaxValueName++; // Include the terminating NULL // // Now starts enumerating the value and replace value names & // string data with "Replace" string in place of "Search" string // // Allocate enough memory szValueName = (LPWSTR) LocalAlloc(LPTR, cchMaxValueName * sizeof(WCHAR)); if (!szValueName) { goto Exit; } pbValue = (LPBYTE) LocalAlloc(LPTR, cbMaxValue); if (!pbValue) { goto Exit; } dwIndex = 0; cchLocalValueName = cchMaxValueName; cbLocalValue = cbMaxValue; while (RegEnumValue(hKey, dwIndex++, szValueName, &cchLocalValueName, NULL, &dwType, pbValue, &cbLocalValue) == ERROR_SUCCESS) { if (dwType == REG_SZ || dwType == REG_MULTI_SZ || dwType == REG_EXPAND_SZ) { // Construct the new data value only if it's a string pbNewValue = (LPBYTE) StringSearchAndReplaceW((PCWSTR)pbValue, Search, Replace, &cbNewLocalValue); } // Now construct the new value name by replacing szNewValueName = StringSearchAndReplaceW(szValueName, Search, Replace, NULL); // If the value name or data has changed then write a new value if (szNewValueName || pbNewValue) { lResult = RegSetValueEx(hKey, szNewValueName ? szNewValueName : szValueName, 0, dwType, pbNewValue ? pbNewValue : pbValue, pbNewValue ? cbNewLocalValue : cbLocalValue); } if (pbNewValue) { LocalFree(pbNewValue); pbNewValue = NULL; } if (szNewValueName) { LocalFree(szNewValueName); szNewValueName = NULL; if (RegDeleteValue(hKey, szValueName) == ERROR_SUCCESS) { // // Start from begining, as enumeration index no longer valid // with insertion/deletion of value under the key // dwIndex = 0; lResult = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &cchNewMaxValueName, &cbNewMaxValue, NULL, NULL); if (ERROR_SUCCESS != lResult) { DEBUGMSG ((DM_VERBOSE, "Fail to query info for key %s. Error %d", szKey, lResult)); goto Exit; } cchNewMaxValueName++; // Include the terminating NULL if (cchNewMaxValueName > cchMaxValueName) { LocalFree(szValueName); szValueName = NULL; cchMaxValueName = cchNewMaxValueName; szValueName = (LPWSTR) LocalAlloc(LPTR, cchMaxValueName * sizeof(WCHAR)); if (!szValueName) { goto Exit; } } if (cbNewMaxValue > cbMaxValue) { LocalFree(pbValue); pbValue = NULL; cbMaxValue = cbNewMaxValue; pbValue = (LPBYTE) LocalAlloc(LPTR, cbMaxValue); if (!pbValue) { goto Exit; } } } } cchLocalValueName = cchMaxValueName; cbLocalValue = cbMaxValue; } LocalFree(szValueName); szValueName = NULL; LocalFree(pbValue); pbValue = NULL; // // Now enumerate all the sub keys and replace the name as // required in a recursive fashion // szSubKeyName = (LPWSTR) LocalAlloc(LPTR, cchMaxSubKeyName * sizeof(WCHAR)); if (!szSubKeyName) { goto Exit; } dwIndex = 0; while (RegEnumKey(hKey, dwIndex++, szSubKeyName, cchMaxSubKeyName) == ERROR_SUCCESS) { // recursively replace in the sub key tree RegistrySearchAndReplaceW(hKey, szSubKeyName, Search, Replace); szNewSubKeyName = StringSearchAndReplaceW(szSubKeyName, Search, Replace, NULL); if (szNewSubKeyName) { if (RegOpenKey(hKey, szSubKeyName, &hSubKey) == ERROR_SUCCESS) { Unicode_String.Length = ByteCountW(szNewSubKeyName); Unicode_String.MaximumLength = Unicode_String.Length + sizeof(WCHAR); Unicode_String.Buffer = szNewSubKeyName; lResult = NtRenameKey(hSubKey, &Unicode_String); if (lResult == ERROR_SUCCESS) { // // Start from begining, as enumeration index no longer valid // with rename of sub-keys under the key // dwIndex = 0; lResult = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, &cchNewMaxSubKeyName, NULL, NULL, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS != lResult) { DEBUGMSG ((DM_VERBOSE, "Fail to query info for key %s. Error %d", szKey, lResult)); goto Exit; } cchNewMaxSubKeyName++; // Include the terminating NULL if (cchNewMaxSubKeyName > cchMaxSubKeyName) { LocalFree(szSubKeyName); szSubKeyName = NULL; cchMaxSubKeyName = cchNewMaxSubKeyName; szSubKeyName = (LPWSTR) LocalAlloc(LPTR, cchMaxSubKeyName * sizeof(WCHAR)); if (!szSubKeyName) { goto Exit; } } } RegCloseKey(hSubKey); } LocalFree(szNewSubKeyName); szNewSubKeyName = NULL; } } Exit: if (hKey) { RegCloseKey(hKey); } if (szValueName) { LocalFree(szValueName); } if (pbValue) { LocalFree(pbValue); } if (szSubKeyName) { LocalFree(szSubKeyName); } }