You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1237 lines
45 KiB
1237 lines
45 KiB
#include "ntapi.h"
|
|
#include "advpack.h"
|
|
#include "globals.h"
|
|
#include "crc32.h"
|
|
#include "resource.h"
|
|
|
|
|
|
// macro definitions
|
|
#define VDH_EXISTENCE_ONLY 0x01
|
|
#define VDH_GET_VALUE 0x02
|
|
#define VDH_DEL_VALUE 0x04
|
|
|
|
|
|
|
|
#define BIG_BUF_SIZE (1024 + 512) // 1.5K
|
|
|
|
|
|
// type definitions
|
|
typedef struct tagROOTKEY
|
|
{
|
|
PCSTR pcszRootKey;
|
|
HKEY hkRootKey;
|
|
} ROOTKEY;
|
|
|
|
|
|
// prototype declarations
|
|
VOID EnumerateSubKey();
|
|
BOOL RegSaveRestoreHelperWrapper(PCSTR pcszValueName, PCSTR pcszCRCValueName);
|
|
|
|
BOOL RegSaveHelper(HKEY hkBckupKey, HKEY hkRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PCSTR pcszCRCValueName);
|
|
BOOL RegRestoreHelper(HKEY hkBckupKey, HKEY hkRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PCSTR pcszCRCValueName);
|
|
|
|
BOOL AddDelMapping(HKEY hkBckupKey, PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, DWORD dwFlags);
|
|
BOOL MappingExists(HKEY hkBckupKey, PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName);
|
|
|
|
BOOL SetValueData(HKEY hkBckupKey, PCSTR pcszValueName, CONST BYTE *pcbValueData, DWORD dwValueDataLen);
|
|
BOOL ValueDataExists(HKEY hkBckupKey, PCSTR pcszValueName);
|
|
BOOL GetValueData(HKEY hkBckupKey, PCSTR pcszValueName, PBYTE *ppbValueData, PDWORD pdwValueDataLen);
|
|
BOOL DelValueData(HKEY hkBckupKey, PCSTR pcszValueName);
|
|
BOOL ValueDataHelper(HKEY hkBckupKey, PCSTR pcszValueName, PBYTE *ppbValueData, PDWORD pdwValueDataLen, DWORD dwFlags);
|
|
VOID Convert2CRC(PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PSTR pszCRCValueName);
|
|
|
|
BOOL MapRootRegStr2Key(PCSTR pcszRootKey, HKEY *phkRootKey);
|
|
CHAR FindSeparator(PCSTR pcszSubKey, PCSTR pcszValueName);
|
|
BOOL RegKeyEmpty(HKEY hkRootKey, PCSTR pcszSubKey);
|
|
|
|
PSTR GetNextToken(PSTR *ppszData, CHAR chDeLim);
|
|
|
|
BOOL FRunningOnNT();
|
|
|
|
|
|
// global variables
|
|
BOOL g_bRet, g_fRestore, g_fAtleastOneRegSaved, g_fRemovBkData;
|
|
HKEY g_hkBckupKey, g_hkRootKey;
|
|
PCSTR g_pcszRootKey, g_pcszValueName;
|
|
PSTR g_pszCRCTempBuf = NULL, g_pszSubKey = NULL, g_pszCRCSubKey = NULL;
|
|
|
|
|
|
// related to logging
|
|
VOID StartLogging(PCSTR pcszLogFileSecName);
|
|
VOID WriteToLog(PCSTR pcszFormatString, ...);
|
|
VOID StopLogging();
|
|
|
|
HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
HRESULT WINAPI RegSaveRestore(HWND hWnd, PCSTR pszTitleString, HKEY hkBckupKey, PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, DWORD dwFlags)
|
|
{
|
|
HWND hSaveWnd = ctx.hWnd;
|
|
WORD wSaveQuietMode = ctx.wQuietMode;
|
|
LPSTR lpszSaveTitle = ctx.lpszTitle;
|
|
|
|
g_bRet = g_fAtleastOneRegSaved = FALSE;
|
|
|
|
if ( (hWnd == INVALID_HANDLE_VALUE) || (dwFlags & ARSR_NOMESSAGES) )
|
|
ctx.wQuietMode |= QUIETMODE_ALL;
|
|
|
|
if ( hWnd != INVALID_HANDLE_VALUE )
|
|
ctx.hWnd = hWnd;
|
|
|
|
if (pszTitleString != NULL)
|
|
ctx.lpszTitle = (PSTR)pszTitleString;
|
|
|
|
g_hkBckupKey = hkBckupKey;
|
|
g_pcszRootKey = pcszRootKey;
|
|
g_pcszValueName = pcszValueName;
|
|
|
|
g_fRestore = (dwFlags & IE4_RESTORE);
|
|
g_fRemovBkData = (dwFlags & IE4_REMOVREGBKDATA) && g_fRestore;
|
|
|
|
StartLogging(g_fRestore ? REG_RESTORE_LOG_KEY : REG_SAVE_LOG_KEY);
|
|
|
|
if (!MapRootRegStr2Key(pcszRootKey, &g_hkRootKey))
|
|
{
|
|
ErrorMsg1Param(ctx.hWnd, IDS_INVALID_ROOTKEY, pcszRootKey);
|
|
goto ErrExit;
|
|
}
|
|
|
|
// allocate a 1.5K buffer for g_pszCRCTempBuf
|
|
if ((g_pszCRCTempBuf = (PSTR) LocalAlloc(LPTR, BIG_BUF_SIZE)) == NULL)
|
|
{
|
|
ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
|
|
goto ErrExit;
|
|
}
|
|
|
|
if (!g_fRestore && pcszValueName == NULL && !(dwFlags & IE4_NOENUMKEY))
|
|
{
|
|
HKEY hk;
|
|
|
|
// check if pcszSubKey exits; if it doesn't and it has not been already backed up,
|
|
// set the IE4_NOENUMKEY flag so that an entry for this subkey is made in the backup branch
|
|
if (RegOpenKeyEx(g_hkRootKey, pcszSubKey, 0, KEY_READ, &hk) != ERROR_SUCCESS)
|
|
{
|
|
if (!MappingExists(hkBckupKey, pcszRootKey, pcszSubKey, pcszValueName))
|
|
dwFlags |= IE4_NOENUMKEY;
|
|
}
|
|
else
|
|
RegCloseKey(hk);
|
|
}
|
|
|
|
if (pcszValueName != NULL || (dwFlags & IE4_NOENUMKEY))
|
|
{
|
|
g_pszSubKey = g_pszCRCSubKey = (PSTR) pcszSubKey;
|
|
g_bRet = RegSaveRestoreHelperWrapper(g_pcszValueName, g_pcszValueName);
|
|
if (!(dwFlags & IE4_NO_CRC_MAPPING) && g_bRet)
|
|
{
|
|
// store the RootKey, SubKey, Flags and ValueName in *.map.
|
|
// this info would be used by the caller during the restore phase.
|
|
g_bRet = AddDelMapping(g_hkBckupKey, g_pcszRootKey, g_pszSubKey, g_pcszValueName, dwFlags);
|
|
}
|
|
}
|
|
else // save or restore pcszSubKey recursively
|
|
{
|
|
// allocate a 1K buffer for g_pszCRCSubKey
|
|
if ((g_pszCRCSubKey = (PSTR) LocalAlloc(LPTR, 1024)) == NULL)
|
|
{
|
|
ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
|
|
goto ErrExit;
|
|
}
|
|
|
|
if (!g_fRestore)
|
|
{
|
|
// if backup info exists for pcszRootKey\pcszSubKey, then we won't re-backup
|
|
// the key recursively again; if we don't do this, then during an upgrade or reinstall
|
|
// over a build, we would backup potentially newer values that got added during the running
|
|
// of the program.
|
|
if (MappingExists(hkBckupKey, pcszRootKey, pcszSubKey, pcszValueName))
|
|
{
|
|
g_bRet = TRUE;
|
|
|
|
LocalFree(g_pszCRCSubKey);
|
|
g_pszCRCSubKey = NULL;
|
|
|
|
goto ErrExit;
|
|
}
|
|
|
|
// allocate a 1K buffer for g_pszSubKey
|
|
if ((g_pszSubKey = (PSTR) LocalAlloc(LPTR, 1024)) == NULL)
|
|
{
|
|
ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
|
|
LocalFree(g_pszCRCSubKey);
|
|
goto ErrExit;
|
|
}
|
|
}
|
|
else
|
|
g_pszSubKey = (PSTR) pcszSubKey;
|
|
|
|
g_bRet = TRUE;
|
|
lstrcpy(g_pszCRCSubKey, pcszSubKey);
|
|
if (!g_fRestore)
|
|
lstrcpy(g_pszSubKey, pcszSubKey);
|
|
|
|
EnumerateSubKey();
|
|
if (!(dwFlags & IE4_NO_CRC_MAPPING))
|
|
{
|
|
if (g_fRestore)
|
|
{
|
|
if (g_bRet)
|
|
{
|
|
// if we couldn't restore everything; then we shouldn't delete the mapping info.
|
|
g_bRet = AddDelMapping(g_hkBckupKey, g_pcszRootKey, g_pszSubKey, g_pcszValueName, dwFlags);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (g_fAtleastOneRegSaved)
|
|
{
|
|
// save the mapping info only if atleast one reg entry was saved
|
|
g_bRet = AddDelMapping(g_hkBckupKey, g_pcszRootKey, g_pszSubKey, g_pcszValueName, dwFlags);
|
|
}
|
|
}
|
|
}
|
|
|
|
LocalFree(g_pszCRCSubKey);
|
|
g_pszCRCSubKey = NULL;
|
|
if (!g_fRestore)
|
|
{
|
|
LocalFree(g_pszSubKey);
|
|
g_pszSubKey = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
ErrExit:
|
|
StopLogging();
|
|
|
|
if (g_pszCRCTempBuf != NULL)
|
|
{
|
|
LocalFree(g_pszCRCTempBuf);
|
|
g_pszCRCTempBuf = NULL;
|
|
}
|
|
|
|
ctx.hWnd = hSaveWnd;
|
|
ctx.wQuietMode = wSaveQuietMode;
|
|
ctx.lpszTitle = lpszSaveTitle;
|
|
|
|
return g_bRet ? S_OK : E_FAIL;
|
|
}
|
|
|
|
|
|
HRESULT WINAPI RegRestoreAll(HWND hWnd, PSTR pszTitleString, HKEY hkBckupKey)
|
|
{
|
|
HWND hSaveWnd = ctx.hWnd;
|
|
WORD wSaveQuietMode = ctx.wQuietMode;
|
|
LPSTR lpszSaveTitle = ctx.lpszTitle;
|
|
HRESULT hRet;
|
|
|
|
if (hWnd != INVALID_HANDLE_VALUE)
|
|
ctx.hWnd = hWnd;
|
|
else
|
|
ctx.wQuietMode |= QUIETMODE_ALL;
|
|
|
|
if (pszTitleString != NULL)
|
|
ctx.lpszTitle = pszTitleString;
|
|
|
|
hRet = RegRestoreAllEx( hkBckupKey );
|
|
|
|
ctx.hWnd = hSaveWnd;
|
|
ctx.wQuietMode = wSaveQuietMode;
|
|
ctx.lpszTitle = lpszSaveTitle;
|
|
|
|
return hRet;
|
|
}
|
|
|
|
|
|
HRESULT RegRestoreAllEx( HKEY hkBckupKey )
|
|
// In one shot restore all the reg entries by enumerating all the values under hkBckupKey\*.map keys
|
|
// and calling RegSaveRestore on each one of them.
|
|
{
|
|
BOOL bRet = TRUE;
|
|
PSTR pszMappedValueData = NULL;
|
|
CHAR szBuf[32];
|
|
CHAR szSubKey[32];
|
|
DWORD dwKeyIndex;
|
|
HKEY hkSubKey;
|
|
LONG lRetVal;
|
|
|
|
if ((pszMappedValueData = (PSTR) LocalAlloc(LPTR, BIG_BUF_SIZE)) == NULL)
|
|
{
|
|
ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// enumerate all the sub-keys under hkBckupKey
|
|
for (dwKeyIndex = 0; ; dwKeyIndex++)
|
|
{
|
|
PSTR pszPtr;
|
|
|
|
lRetVal = RegEnumKey(hkBckupKey, dwKeyIndex, szSubKey, sizeof(szSubKey));
|
|
if (lRetVal != ERROR_SUCCESS)
|
|
{
|
|
if (lRetVal != ERROR_NO_MORE_ITEMS)
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
// check if the keyname is of the form *.map
|
|
if ((pszPtr = ANSIStrChr(szSubKey, '.')) != NULL && lstrcmpi(pszPtr, ".map") == 0)
|
|
{
|
|
if (RegOpenKeyEx(hkBckupKey, szSubKey, 0, KEY_READ, &hkSubKey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwValIndex, dwValueLen, dwDataLen;
|
|
|
|
// enumerate all the values under this key and restore each one of them
|
|
dwValueLen = sizeof(szBuf);
|
|
dwDataLen = BIG_BUF_SIZE;
|
|
for (dwValIndex = 0; ; dwValIndex++)
|
|
{
|
|
CHAR chSeparator;
|
|
PSTR pszFlags, pszRootKey, pszSubKey, pszValueName, pszPtr;
|
|
DWORD dwMappedFlags;
|
|
|
|
lRetVal = RegEnumValue(hkSubKey, dwValIndex, szBuf, &dwValueLen, NULL, NULL, pszMappedValueData, &dwDataLen);
|
|
if (lRetVal != ERROR_SUCCESS)
|
|
{
|
|
if (lRetVal != ERROR_NO_MORE_ITEMS)
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
// get the separator char first and then point to RootKey, SubKey and ValueName in pszMappedValueData
|
|
pszPtr = pszMappedValueData;
|
|
chSeparator = *pszPtr++;
|
|
pszFlags = GetNextToken(&pszPtr, chSeparator);
|
|
pszRootKey = GetNextToken(&pszPtr, chSeparator);
|
|
pszSubKey = GetNextToken(&pszPtr, chSeparator);
|
|
pszValueName = GetNextToken(&pszPtr, chSeparator);
|
|
|
|
dwMappedFlags = (pszFlags != NULL) ? (DWORD) My_atoi(pszFlags) : 0;
|
|
|
|
if (SUCCEEDED(RegSaveRestore( ctx.hWnd, ctx.lpszTitle, hkBckupKey, pszRootKey, pszSubKey, pszValueName, dwMappedFlags)))
|
|
dwValIndex--; // RegSaveRestore would delete this value
|
|
else
|
|
bRet = FALSE;
|
|
|
|
dwValueLen = sizeof(szBuf);
|
|
dwDataLen = BIG_BUF_SIZE;
|
|
}
|
|
|
|
RegCloseKey(hkSubKey);
|
|
}
|
|
else
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
LocalFree(pszMappedValueData);
|
|
|
|
// delete all the empty subkeys
|
|
for (dwKeyIndex = 0; ; dwKeyIndex++)
|
|
{
|
|
lRetVal = RegEnumKey(hkBckupKey, dwKeyIndex, szSubKey, sizeof(szSubKey));
|
|
if (lRetVal != ERROR_SUCCESS)
|
|
{
|
|
if (lRetVal != ERROR_NO_MORE_ITEMS)
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (RegKeyEmpty(hkBckupKey, szSubKey) && RegDeleteKey(hkBckupKey, szSubKey) == ERROR_SUCCESS)
|
|
dwKeyIndex--;
|
|
}
|
|
|
|
return bRet ? S_OK : E_FAIL;
|
|
}
|
|
|
|
|
|
VOID EnumerateSubKey()
|
|
// Recursively enumerate value names and sub-keys and call Save/Restore on each of them
|
|
{
|
|
HKEY hkSubKey;
|
|
DWORD dwIndex;
|
|
static DWORD dwLen;
|
|
static PCSTR pcszSubKeyPrefix = "_$Sub#";
|
|
static PCSTR pcszValueNamePrefix = "_$Val#";
|
|
static PCSTR pcszValueNamePrefix0 = "_$Val#0";
|
|
static CHAR szValueName[MAX_PATH], szBckupCRCValueName[MAX_PATH];
|
|
static PSTR pszPtr;
|
|
|
|
if (g_fRestore)
|
|
{
|
|
// check if there is an entry in the back-up branch for just the g_pszCRCSubKey itself
|
|
Convert2CRC(g_pcszRootKey, g_pszCRCSubKey, NULL, szBckupCRCValueName);
|
|
if (ValueDataExists(g_hkBckupKey, szBckupCRCValueName)) // restore the no value names sub-key
|
|
g_bRet = RegSaveRestoreHelperWrapper(NULL, NULL) && g_bRet;
|
|
else
|
|
{
|
|
// enumerate values using the aliases
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
{
|
|
wsprintf(szValueName, "%s%lu", pcszValueNamePrefix, dwIndex);
|
|
Convert2CRC(g_pcszRootKey, g_pszCRCSubKey, szValueName, szBckupCRCValueName);
|
|
if (ValueDataExists(g_hkBckupKey, szBckupCRCValueName))
|
|
g_bRet = RegSaveRestoreHelperWrapper(NULL, szValueName) && g_bRet;
|
|
else
|
|
break; // no more value names
|
|
}
|
|
}
|
|
|
|
// enumerate sub-keys using the aliases
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
{
|
|
// check if there is any sub-key under g_pszCRCSubKey; if none, this is our terminating condition.
|
|
// NOTE: a sub-key under g_pszCRCSubKey exists if:
|
|
// (1) the sub-key itself exists OR
|
|
// (2) the sub-key contains atleast one value name.
|
|
|
|
// check if a sub-key by itself exists
|
|
pszPtr = g_pszCRCSubKey + lstrlen(g_pszCRCSubKey);
|
|
wsprintf(pszPtr, "\\%s%lu", pcszSubKeyPrefix, dwIndex);
|
|
Convert2CRC(g_pcszRootKey, g_pszCRCSubKey, NULL, szBckupCRCValueName);
|
|
if (ValueDataExists(g_hkBckupKey, szBckupCRCValueName))
|
|
EnumerateSubKey();
|
|
else
|
|
{
|
|
// check if the sub-key has the first value name alias - "_$Val#0"
|
|
Convert2CRC(g_pcszRootKey, g_pszCRCSubKey, pcszValueNamePrefix0, szBckupCRCValueName);
|
|
if (ValueDataExists(g_hkBckupKey, szBckupCRCValueName))
|
|
EnumerateSubKey();
|
|
else
|
|
{
|
|
GetParentDir(g_pszCRCSubKey);
|
|
break; // no more sub-keys
|
|
}
|
|
}
|
|
|
|
GetParentDir(g_pszCRCSubKey);
|
|
}
|
|
}
|
|
else // backup the key
|
|
{
|
|
if (RegOpenKeyEx(g_hkRootKey, g_pszSubKey, 0, KEY_READ, &hkSubKey) == ERROR_SUCCESS)
|
|
{
|
|
dwLen = sizeof(szValueName);
|
|
if (RegEnumValue(hkSubKey, 0, szValueName, &dwLen, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
|
{
|
|
// no value names; just save the key itself
|
|
g_bRet = g_bRet && RegSaveRestoreHelperWrapper(NULL, NULL);
|
|
}
|
|
else
|
|
{
|
|
// enumerate the values
|
|
dwIndex = 0;
|
|
dwLen = sizeof(szValueName);
|
|
while (RegEnumValue(hkSubKey, dwIndex, szValueName, &dwLen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
|
{
|
|
// szBckupCRCValueName is really szCRCValueName
|
|
wsprintf(szBckupCRCValueName, "%s%lu", pcszValueNamePrefix, dwIndex);
|
|
g_bRet = g_bRet && RegSaveRestoreHelperWrapper(szValueName, szBckupCRCValueName);
|
|
|
|
dwIndex++;
|
|
dwLen = sizeof(szValueName);
|
|
}
|
|
}
|
|
|
|
// enumerate sub-keys
|
|
dwIndex = 0;
|
|
// append '\\' to g_pszSubKey and make pszPtr point to the char after this last '\\' so that
|
|
// when RegEnumKey puts a sub-key name at pszPtr, g_pszSubKey would have the complete sub-key path.
|
|
dwLen = lstrlen(g_pszSubKey);
|
|
pszPtr = g_pszSubKey + dwLen;
|
|
*pszPtr++ = '\\';
|
|
while (RegEnumKey(hkSubKey, dwIndex, pszPtr, 1024 - dwLen - 1) == ERROR_SUCCESS)
|
|
{
|
|
// prepare the sub-key alias
|
|
pszPtr = g_pszCRCSubKey + lstrlen(g_pszCRCSubKey);
|
|
wsprintf(pszPtr, "\\%s%lu", pcszSubKeyPrefix, dwIndex);
|
|
|
|
EnumerateSubKey();
|
|
|
|
GetParentDir(g_pszSubKey);
|
|
GetParentDir(g_pszCRCSubKey);
|
|
|
|
dwIndex++;
|
|
|
|
// append '\\' to g_pszSubKey and make pszPtr point to the char after this last '\\' so that
|
|
// when RegEnumKey puts a sub-key name at pszPtr, g_pszSubKey would have the complete sub-key path.
|
|
dwLen = lstrlen(g_pszSubKey);
|
|
pszPtr = g_pszSubKey + dwLen;
|
|
*pszPtr++ = '\\';
|
|
}
|
|
|
|
*--pszPtr = '\0'; // chop the last '\\'; no DBCS clash because we added it
|
|
|
|
RegCloseKey(hkSubKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL RegSaveRestoreHelperWrapper(PCSTR pcszValueName, PCSTR pcszCRCValueName)
|
|
{
|
|
CHAR szBckupCRCValueName[32];
|
|
|
|
// a unique back-up value name is obtained by concatenating pcszRootKey, pcszSubKey and pcszValueName
|
|
// and the concatenated value name is stored as a 16-byte CRC value (space optimization)
|
|
Convert2CRC(g_pcszRootKey, g_pszCRCSubKey, pcszCRCValueName, szBckupCRCValueName);
|
|
|
|
WriteToLog("\r\nValueName = %1,%2", g_pcszRootKey, g_pszSubKey);
|
|
if (pcszValueName != NULL)
|
|
WriteToLog(",%1", pcszValueName);
|
|
WriteToLog("\r\nCRCValueName = %1\r\n", szBckupCRCValueName);
|
|
|
|
return (g_fRestore) ?
|
|
RegRestoreHelper(g_hkBckupKey, g_hkRootKey, g_pszSubKey, pcszValueName, szBckupCRCValueName) :
|
|
RegSaveHelper(g_hkBckupKey, g_hkRootKey, g_pszSubKey, pcszValueName, szBckupCRCValueName);
|
|
}
|
|
|
|
|
|
BOOL RegSaveHelper(HKEY hkBckupKey, HKEY hkRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PCSTR pcszCRCValueName)
|
|
// If pcszValueName exists in the registry, back-up its value data; otherwise, remember how much of pcszSubKey
|
|
// is present in the registry. This info would help during restoration.
|
|
{
|
|
HKEY hkSubKey = NULL;
|
|
PSTR pszBckupData = NULL, pszCOSubKey = NULL, pszPtr;
|
|
DWORD dwValueDataLen, dwValueType, dwBckupDataLen;
|
|
CHAR chSeparator;
|
|
BOOL fSubKeyValid;
|
|
|
|
// don't backup the value data of pcszCRCValueName if it has been already backed-up
|
|
if (ValueDataExists(hkBckupKey, pcszCRCValueName))
|
|
return TRUE;
|
|
|
|
// make a copy of pcszSubKey
|
|
if ((pszCOSubKey = (PSTR) LocalAlloc(LPTR, lstrlen(pcszSubKey) + 1)) == NULL)
|
|
{
|
|
ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
|
|
goto RegSaveHelperErr;
|
|
}
|
|
lstrcpy(pszCOSubKey, pcszSubKey);
|
|
|
|
// loop through each branch in pszCOSubKey to find out how much of it is already present in the registry.
|
|
// start with the whole sub key first and then chop one branch at a time from the end
|
|
fSubKeyValid = TRUE;
|
|
do
|
|
{
|
|
if (RegOpenKeyEx(hkRootKey, pszCOSubKey, 0, KEY_READ, &hkSubKey) == ERROR_SUCCESS)
|
|
break;
|
|
} while (fSubKeyValid = GetParentDir(pszCOSubKey));
|
|
|
|
// NOTE: fSubKeyValid == FALSE here means that no branch of pcszSubKey is present
|
|
|
|
if (fSubKeyValid && lstrcmpi(pcszSubKey, pszCOSubKey) == 0)
|
|
// entire subkey is present in the registry
|
|
{
|
|
if (pcszValueName != NULL)
|
|
{
|
|
if (*pcszValueName || FRunningOnNT())
|
|
{
|
|
// check if pcszValueName is present in the registry
|
|
if (RegQueryValueEx(hkSubKey, pcszValueName, NULL, &dwValueType, NULL, &dwValueDataLen) != ERROR_SUCCESS)
|
|
pcszValueName = NULL;
|
|
}
|
|
else
|
|
{
|
|
LONG lRetVal;
|
|
CHAR szDummyBuf[1];
|
|
|
|
// On Win95, for the default value name, its existence is checked as follows:
|
|
// - pass in a dummy buffer for the value data but pass in the size of the buffer as 0
|
|
// - the query would succeed if and only if there is no value data set
|
|
// - for all other cases, including the case where the value data is just the empty string,
|
|
// the query would fail and dwValueDataLen would contain the no. of bytes needed to
|
|
// fit in the value data
|
|
// On NT4.0, if no value data is set, the query returns ERROR_FILE_NOT_FOUND
|
|
// NOTE: To minimize risk, we don't follow this code path if running on NT4.0
|
|
|
|
dwValueDataLen = 0;
|
|
lRetVal = RegQueryValueEx(hkSubKey, pcszValueName, NULL, &dwValueType, (LPBYTE) szDummyBuf, &dwValueDataLen);
|
|
if (lRetVal == ERROR_SUCCESS || lRetVal == ERROR_FILE_NOT_FOUND)
|
|
pcszValueName = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
pcszValueName = NULL;
|
|
|
|
WriteToLog("BckupSubKey = ");
|
|
|
|
// compute the length required for pszBckupData
|
|
// format of pszBckupData is (assume that the separator char is ','):
|
|
// ,[<szSubKey>,[<szValueName>,\0<dwValueType><dwValueDataLen><ValueData>]]
|
|
dwBckupDataLen = 1 + 1; // the separator char + '\0'
|
|
if (fSubKeyValid)
|
|
{
|
|
WriteToLog("%1", pszCOSubKey);
|
|
dwBckupDataLen += lstrlen(pszCOSubKey) + 1;
|
|
|
|
if (pcszValueName != NULL)
|
|
{
|
|
WriteToLog(", BckupValueName = %1", pcszValueName);
|
|
dwBckupDataLen += lstrlen(pcszValueName) + 1 + 2 * sizeof(DWORD) + dwValueDataLen;
|
|
// 2 * sizeof(DWORD) == sizeof(dwValueType) + sizeof(dwValueDataLen)
|
|
}
|
|
}
|
|
|
|
WriteToLog("\r\n");
|
|
|
|
// determine a valid separator char that is not one of the chars in SubKey and ValueName
|
|
if ((chSeparator = FindSeparator(fSubKeyValid ? pszCOSubKey : NULL, pcszValueName)) == '\0')
|
|
{
|
|
ErrorMsg(ctx.hWnd, IDS_NO_SEPARATOR_CHAR);
|
|
goto RegSaveHelperErr;
|
|
}
|
|
|
|
// allocate memory for pszBckupData
|
|
if ((pszBckupData = (PSTR) LocalAlloc(LPTR, dwBckupDataLen)) == NULL)
|
|
{
|
|
ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
|
|
goto RegSaveHelperErr;
|
|
}
|
|
|
|
// start building pszBckupData
|
|
// format of pszBckupData is (assume that the separator char is ','):
|
|
// ,[<szSubKey>,[<szValueName>,\0<dwValueType><dwValueDataLen><ValueData>]]
|
|
pszPtr = pszBckupData;
|
|
*pszPtr++ = chSeparator;
|
|
*pszPtr = '\0';
|
|
if (fSubKeyValid)
|
|
{
|
|
lstrcpy(pszPtr, pszCOSubKey);
|
|
pszPtr += lstrlen(pszPtr);
|
|
*pszPtr++ = chSeparator;
|
|
*pszPtr = '\0';
|
|
|
|
if (pcszValueName != NULL)
|
|
{
|
|
lstrcpy(pszPtr, pcszValueName);
|
|
pszPtr += lstrlen(pszPtr);
|
|
*pszPtr++ = chSeparator;
|
|
*pszPtr++ = '\0'; // include the '\0' char
|
|
|
|
*((DWORD UNALIGNED *) pszPtr)++ = dwValueType;
|
|
*((DWORD UNALIGNED *) pszPtr)++ = dwValueDataLen;
|
|
|
|
// NOTE: pszPtr points to the start position of value data in pszBckupData
|
|
RegQueryValueEx(hkSubKey, pcszValueName, NULL, &dwValueType, (PBYTE) pszPtr, &dwValueDataLen);
|
|
}
|
|
}
|
|
|
|
if (!SetValueData(hkBckupKey, pcszCRCValueName, (CONST BYTE *) pszBckupData, dwBckupDataLen))
|
|
{
|
|
ErrorMsg1Param(ctx.hWnd, IDS_ERR_REGSETVALUE, pcszCRCValueName);
|
|
goto RegSaveHelperErr;
|
|
}
|
|
WriteToLog("Value backed-up\r\n");
|
|
|
|
g_fAtleastOneRegSaved = TRUE;
|
|
|
|
if (hkSubKey != NULL)
|
|
RegCloseKey(hkSubKey);
|
|
LocalFree(pszCOSubKey);
|
|
LocalFree(pszBckupData);
|
|
|
|
return TRUE;
|
|
|
|
RegSaveHelperErr:
|
|
if (hkSubKey != NULL)
|
|
RegCloseKey(hkSubKey);
|
|
if (pszCOSubKey != NULL)
|
|
LocalFree(pszCOSubKey);
|
|
if (pszBckupData != NULL)
|
|
LocalFree(pszBckupData);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL RegRestoreHelper(HKEY hkBckupKey, HKEY hkRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PCSTR pcszCRCValueName)
|
|
// (1) If the value name in the backed-up value data is not NULL, it means that pcszValueName existed during
|
|
// back-up time; so, restore the original value data.
|
|
// (2) If the value name in the backed-up value data is NULL and pcszValueName is not NULL, it means that
|
|
// pcszValueName didn't exist during the back-up time; so, delete it.
|
|
// (3) If the backed-up sub key is shorter than pcszSubKey, then delete one branch at a time, if it is empty,
|
|
// from the end in pcszSubKey till pcszSubKey becomes identical to the backed-up sub key.
|
|
{
|
|
HKEY hkSubKey = NULL;
|
|
PSTR pszBckupData = NULL, pszCOSubKey, pszPtr, pszBckupSubKey, pszBckupValueName;
|
|
DWORD dwValueDataLen, dwValueType, dwBckupDataLen, dwDisposition;
|
|
CHAR chSeparator;
|
|
|
|
if (!GetValueData(hkBckupKey, pcszCRCValueName, &pszBckupData, &dwBckupDataLen))
|
|
{
|
|
ErrorMsg1Param(ctx.hWnd, IDS_ERR_REGQUERYVALUE, pcszCRCValueName);
|
|
goto RegRestoreHelperErr;
|
|
}
|
|
|
|
// format of pszBckupData is (assume that the separator char is ','):
|
|
// ,[<szSubKey>,[<szValueName>,\0<dwValueType><dwValueDataLen><ValueData>]]
|
|
pszPtr = pszBckupData;
|
|
chSeparator = *pszPtr++; // initialize the separator char; since it is not part of
|
|
// Leading or Trailing DBCS Character Set, pszPtr++ is fine
|
|
pszBckupSubKey = GetNextToken(&pszPtr, chSeparator);
|
|
pszBckupValueName = GetNextToken(&pszPtr, chSeparator);
|
|
pszPtr++; // skip '\0'
|
|
|
|
if (g_fRemovBkData)
|
|
WriteToLog("RemoveRegistryBackupData: ");
|
|
|
|
WriteToLog("BckupSubKey = ");
|
|
if (pszBckupSubKey != NULL)
|
|
{
|
|
WriteToLog("%1", pszBckupSubKey);
|
|
if (pcszValueName == NULL && lstrlen(pszBckupSubKey) > lstrlen(pcszSubKey))
|
|
{
|
|
// means that pcszSubKey was backed-up thru EnumerateSubKey
|
|
pcszSubKey = pszBckupSubKey;
|
|
}
|
|
}
|
|
|
|
// check to see if we want to restore the reg keys, values or remove reg backup data
|
|
if (g_fRemovBkData)
|
|
{
|
|
if (pszBckupValueName != NULL) // restore the backed-up value data -- case (1)
|
|
{
|
|
WriteToLog(", BckupValueName = %1", pcszValueName);
|
|
}
|
|
DelValueData(hkBckupKey, pcszCRCValueName); // delete the back-up value name
|
|
WriteToLog(" <Done>\r\n");
|
|
goto Done;
|
|
}
|
|
|
|
if (RegCreateKeyEx(hkRootKey, pcszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkSubKey, &dwDisposition) == ERROR_SUCCESS)
|
|
{
|
|
if (pszBckupValueName != NULL) // restore the backed-up value data -- case (1)
|
|
{
|
|
WriteToLog(", BckupValueName = %1", pcszValueName);
|
|
dwValueType = *((DWORD UNALIGNED *) pszPtr)++;
|
|
dwValueDataLen = *((DWORD UNALIGNED *) pszPtr)++;
|
|
if (RegSetValueEx(hkSubKey, pszBckupValueName, 0, dwValueType, (CONST BYTE *) pszPtr, dwValueDataLen) != ERROR_SUCCESS)
|
|
{
|
|
ErrorMsg1Param(ctx.hWnd, IDS_ERR_REGSETVALUE, pszBckupValueName);
|
|
goto RegRestoreHelperErr;
|
|
}
|
|
}
|
|
else if (pcszValueName != NULL)
|
|
{
|
|
// means that the value name didn't exist while backing-up; so delete it -- case (2)
|
|
RegDeleteValue(hkSubKey, pcszValueName);
|
|
}
|
|
|
|
RegCloseKey(hkSubKey);
|
|
|
|
DelValueData(hkBckupKey, pcszCRCValueName); // delete the back-up value name
|
|
WriteToLog("\r\nBackup Value deleted");
|
|
}
|
|
|
|
WriteToLog("\r\n");
|
|
|
|
dwBckupDataLen = 0;
|
|
if (pszBckupValueName == NULL && (pszBckupSubKey == NULL || (DWORD) lstrlen(pcszSubKey) > (dwBckupDataLen = lstrlen(pszBckupSubKey))))
|
|
{
|
|
// only a part of the subkey was present in the registry during back-up;
|
|
// delete the remaining branches if they are empty -- case (3)
|
|
|
|
// make a copy of pcszSubKey
|
|
if ((pszCOSubKey = (PSTR) LocalAlloc(LPTR, lstrlen(pcszSubKey) + 1)) != NULL)
|
|
{
|
|
lstrcpy(pszCOSubKey, pcszSubKey);
|
|
|
|
// start processing one branch at a time from the end in pszCOSubKey;
|
|
// if the branch is empty, delete it;
|
|
// stop processing as soon as pszCOSubKey becomes identical to pszBckupSubKey
|
|
do
|
|
{
|
|
// NOTE: Need to delete a key only if it's empty; otherwise, we would delete
|
|
// more than what we backed up. For example, if component A wanted to backup
|
|
// HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\InternetExplorer
|
|
// and the machine didn't have the Uninstall key, we should not blow away the
|
|
// entire Uninstall key when we uninstall A as other components might have added
|
|
// their uninstall strings there. So delete a key only if it's empty.
|
|
if (RegKeyEmpty(hkRootKey, pszCOSubKey))
|
|
RegDeleteKey(hkRootKey, pszCOSubKey);
|
|
else
|
|
break;
|
|
} while (GetParentDir(pszCOSubKey) && (DWORD) lstrlen(pszCOSubKey) > dwBckupDataLen);
|
|
|
|
LocalFree(pszCOSubKey);
|
|
}
|
|
}
|
|
|
|
Done:
|
|
LocalFree(pszBckupData);
|
|
|
|
return TRUE;
|
|
|
|
RegRestoreHelperErr:
|
|
if (hkSubKey != NULL)
|
|
RegCloseKey(hkSubKey);
|
|
if (pszBckupData != NULL)
|
|
LocalFree(pszBckupData);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL AddDelMapping(HKEY hkBckupKey, PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, DWORD dwFlags)
|
|
{
|
|
CHAR szCRCValueName[32], szBuf[32];
|
|
DWORD dwIndex;
|
|
BOOL bFound = FALSE;
|
|
HKEY hkSubKey = NULL;
|
|
|
|
Convert2CRC(pcszRootKey, pcszSubKey, pcszValueName, szCRCValueName);
|
|
|
|
// enumerate all the sub-keys under hkBckupKey
|
|
for (dwIndex = 0; !bFound && RegEnumKey(hkBckupKey, dwIndex, szBuf, sizeof(szBuf)) == ERROR_SUCCESS; dwIndex++)
|
|
{
|
|
PSTR pszPtr;
|
|
|
|
// check if the keyname is of the form *.map
|
|
if ((pszPtr = ANSIStrChr(szBuf, '.')) != NULL && lstrcmpi(pszPtr, ".map") == 0)
|
|
{
|
|
if (RegOpenKeyEx(hkBckupKey, szBuf, 0, KEY_READ | KEY_WRITE, &hkSubKey) == ERROR_SUCCESS)
|
|
{
|
|
if (RegQueryValueEx(hkSubKey, szCRCValueName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
|
bFound = TRUE;
|
|
else
|
|
{
|
|
RegCloseKey(hkSubKey);
|
|
hkSubKey = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_fRestore)
|
|
{
|
|
if (bFound)
|
|
RegDeleteValue(hkSubKey, szCRCValueName);
|
|
}
|
|
else
|
|
{
|
|
if (!bFound)
|
|
{
|
|
DWORD dwMapKeyIndex = 0;
|
|
|
|
// add the quadruplet, i.e., ",Flags,RootKey,SubKey,ValueName" to hkBckupKey\*.map
|
|
wsprintf(szBuf, "%lu.map", dwMapKeyIndex);
|
|
if (RegCreateKeyEx(hkBckupKey, szBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkSubKey, NULL) == ERROR_SUCCESS)
|
|
{
|
|
PSTR pszPtr;
|
|
CHAR chSeparator;
|
|
|
|
// IMPORTANT: the global buffer g_pszCRCTempBuf is used in Convert2CRC;
|
|
// so be very careful if you want to call Convert2CRC after g_pszCRCTempBuf has been initialized here.
|
|
pszPtr = g_pszCRCTempBuf;
|
|
|
|
// determine a valid separator char that is not one of the chars in SubKey and ValueName
|
|
if ((chSeparator = FindSeparator(pcszSubKey, pcszValueName)) == '\0')
|
|
{
|
|
ErrorMsg(ctx.hWnd, IDS_NO_SEPARATOR_CHAR);
|
|
}
|
|
else
|
|
{
|
|
// reset the IE4_BACKNEW bit and set the IE4_RESTORE bit
|
|
dwFlags &= ~IE4_BACKNEW;
|
|
dwFlags |= IE4_RESTORE;
|
|
wsprintf(szBuf, "%lu", dwFlags);
|
|
|
|
// format of mapping data is (say ',' is chSeparator): ,<Flags>,<RootKey>,<SubKey>,[<ValueName>,]
|
|
{
|
|
*pszPtr++ = chSeparator;
|
|
|
|
lstrcpy(pszPtr, szBuf);
|
|
pszPtr += lstrlen(pszPtr);
|
|
*pszPtr++ = chSeparator;
|
|
|
|
lstrcpy(pszPtr, pcszRootKey);
|
|
pszPtr += lstrlen(pszPtr);
|
|
*pszPtr++ = chSeparator;
|
|
|
|
lstrcpy(pszPtr, pcszSubKey);
|
|
pszPtr += lstrlen(pszPtr);
|
|
*pszPtr++ = chSeparator;
|
|
|
|
if (pcszValueName != NULL)
|
|
{
|
|
lstrcpy(pszPtr, pcszValueName);
|
|
pszPtr += lstrlen(pszPtr);
|
|
*pszPtr++ = chSeparator;
|
|
}
|
|
|
|
*pszPtr = '\0';
|
|
}
|
|
|
|
if (RegSetValueEx(hkSubKey, szCRCValueName, 0, REG_SZ, (CONST BYTE *) g_pszCRCTempBuf, lstrlen(g_pszCRCTempBuf) + 1) != ERROR_SUCCESS)
|
|
{
|
|
do
|
|
{
|
|
// hkBckupKey\<dwIndex>.map key may have reached the 64K limit; create another sub-key
|
|
RegCloseKey(hkSubKey);
|
|
hkSubKey = NULL;
|
|
|
|
wsprintf(szBuf, "%lu.map", ++dwMapKeyIndex);
|
|
if (RegCreateKeyEx(hkBckupKey, szBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkSubKey, NULL) == ERROR_SUCCESS)
|
|
{
|
|
bFound = RegSetValueEx(hkSubKey, szCRCValueName, 0, REG_SZ, (CONST BYTE *) g_pszCRCTempBuf, lstrlen(g_pszCRCTempBuf) + 1) == ERROR_SUCCESS;
|
|
}
|
|
} while (!bFound && dwMapKeyIndex < 64);
|
|
}
|
|
else
|
|
bFound = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hkSubKey != NULL)
|
|
RegCloseKey(hkSubKey);
|
|
|
|
return bFound;
|
|
}
|
|
|
|
|
|
BOOL MappingExists(HKEY hkBckupKey, PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName)
|
|
{
|
|
CHAR szCRCValueName[32], szBuf[32];
|
|
DWORD dwIndex;
|
|
BOOL bFound = FALSE;
|
|
|
|
Convert2CRC(pcszRootKey, pcszSubKey, pcszValueName, szCRCValueName);
|
|
|
|
// enumerate all the sub-keys under hkBckupKey
|
|
for (dwIndex = 0; !bFound && RegEnumKey(hkBckupKey, dwIndex, szBuf, sizeof(szBuf)) == ERROR_SUCCESS; dwIndex++)
|
|
{
|
|
PSTR pszPtr;
|
|
|
|
// check if the keyname is of the form *.map
|
|
if ((pszPtr = ANSIStrChr(szBuf, '.')) != NULL && lstrcmpi(pszPtr, ".map") == 0)
|
|
{
|
|
HKEY hkSubKey;
|
|
|
|
if (RegOpenKeyEx(hkBckupKey, szBuf, 0, KEY_READ | KEY_WRITE, &hkSubKey) == ERROR_SUCCESS)
|
|
{
|
|
if (RegQueryValueEx(hkSubKey, szCRCValueName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
|
bFound = TRUE;
|
|
|
|
RegCloseKey(hkSubKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bFound;
|
|
}
|
|
|
|
|
|
BOOL SetValueData(HKEY hkBckupKey, PCSTR pcszValueName, CONST BYTE *pcbValueData, DWORD dwValueDataLen)
|
|
// Set the (pcszValueName, pcbValueData) pair in hkBckupKey
|
|
{
|
|
BOOL fDone = FALSE;
|
|
HKEY hkSubKey;
|
|
DWORD dwDisposition, dwSubKey;
|
|
CHAR szSubKey[16];
|
|
|
|
// since a key has a size limit of 64K, automatically generate a new sub-key if the other ones are full
|
|
for (dwSubKey = 0; !fDone && dwSubKey < 64; dwSubKey++)
|
|
{
|
|
wsprintf(szSubKey, "%lu", dwSubKey); // sub-keys are named 0, 1, 2, etc.
|
|
if (RegCreateKeyEx(hkBckupKey, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkSubKey, &dwDisposition) == ERROR_SUCCESS)
|
|
{
|
|
if (RegSetValueEx(hkSubKey, pcszValueName, 0, REG_BINARY, pcbValueData, dwValueDataLen) == ERROR_SUCCESS)
|
|
fDone = TRUE;
|
|
|
|
RegCloseKey(hkSubKey);
|
|
}
|
|
}
|
|
|
|
return fDone;
|
|
}
|
|
|
|
|
|
BOOL ValueDataExists(HKEY hkBckupKey, PCSTR pcszValueName)
|
|
// Return TRUE if pcszValueName exists in hkBckupKey; otherwise, return FALSE
|
|
{
|
|
return ValueDataHelper(hkBckupKey, pcszValueName, NULL, NULL, VDH_EXISTENCE_ONLY);
|
|
}
|
|
|
|
|
|
BOOL GetValueData(HKEY hkBckupKey, PCSTR pcszValueName, PBYTE *ppbValueData, PDWORD pdwValueDataLen)
|
|
// Allocate a buffer of required size and return the value data of pcszValueName in hkBckupKey
|
|
{
|
|
return ValueDataHelper(hkBckupKey, pcszValueName, ppbValueData, pdwValueDataLen, VDH_GET_VALUE);
|
|
}
|
|
|
|
|
|
BOOL DelValueData(HKEY hkBckupKey, PCSTR pcszValueName)
|
|
// Delete pcszValueName from hkBckupKey
|
|
{
|
|
return ValueDataHelper(hkBckupKey, pcszValueName, NULL, NULL, VDH_DEL_VALUE);
|
|
}
|
|
|
|
|
|
BOOL ValueDataHelper(HKEY hkBckupKey, PCSTR pcszValueName, PBYTE *ppbValueData, PDWORD pdwValueDataLen, DWORD dwFlags)
|
|
{
|
|
BOOL fDone = FALSE;
|
|
HKEY hkSubKey;
|
|
CHAR szSubKey[16];
|
|
DWORD dwIndex, dwDataLen;
|
|
|
|
if (dwFlags == VDH_GET_VALUE && ppbValueData == NULL)
|
|
return FALSE;
|
|
|
|
// search for pcszValueName in all the sub-keys
|
|
for (dwIndex = 0; !fDone && RegEnumKey(hkBckupKey, dwIndex, szSubKey, sizeof(szSubKey)) == ERROR_SUCCESS; dwIndex++)
|
|
{
|
|
if ( ANSIStrChr(szSubKey, '.') == NULL) // check only in non *.map keys
|
|
{
|
|
if (RegOpenKeyEx(hkBckupKey, szSubKey, 0, KEY_READ | KEY_WRITE, &hkSubKey) == ERROR_SUCCESS)
|
|
{
|
|
if (RegQueryValueEx(hkSubKey, pcszValueName, NULL, NULL, NULL, &dwDataLen) == ERROR_SUCCESS)
|
|
{
|
|
switch (dwFlags)
|
|
{
|
|
case VDH_DEL_VALUE:
|
|
RegDeleteValue(hkSubKey, pcszValueName);
|
|
break;
|
|
|
|
case VDH_GET_VALUE:
|
|
if ((*ppbValueData = (PBYTE) LocalAlloc(LPTR, dwDataLen)) == NULL)
|
|
{
|
|
RegCloseKey(hkSubKey);
|
|
ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
*pdwValueDataLen = dwDataLen;
|
|
RegQueryValueEx(hkSubKey, pcszValueName, NULL, NULL, *ppbValueData, &dwDataLen);
|
|
|
|
break;
|
|
|
|
case VDH_EXISTENCE_ONLY:
|
|
break;
|
|
}
|
|
|
|
fDone = TRUE;
|
|
}
|
|
|
|
RegCloseKey(hkSubKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
return fDone;
|
|
}
|
|
|
|
|
|
VOID Convert2CRC(PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PSTR pszCRCValueName)
|
|
// Concatenate pcszRootKey, pcszSubKey and pcszValueName and convert the concatenated value name
|
|
// to a 16-byte CRC value.
|
|
{
|
|
PSTR pszPtr = g_pszCRCTempBuf;
|
|
ULONG ulCRC = CRC32_INITIAL_VALUE;
|
|
DWORD dwLen;
|
|
|
|
// concatenate pcszRootKey, pcszSubKey, pcszValueName
|
|
lstrcpy(pszPtr, pcszRootKey);
|
|
lstrcat(pszPtr, pcszSubKey);
|
|
if (pcszValueName != NULL)
|
|
lstrcat(pszPtr, pcszValueName);
|
|
|
|
// call CRC32Compute on each half of szBuf and store the 2-DWORD result in ASCII form (16 bytes)
|
|
for (dwLen = lstrlen(pszPtr) / 2; dwLen; dwLen = lstrlen(pszPtr))
|
|
{
|
|
ulCRC = CRC32Compute(pszPtr, dwLen, ulCRC);
|
|
|
|
wsprintf(pszCRCValueName, "%08x", ulCRC);
|
|
pszCRCValueName += 8;
|
|
|
|
pszPtr += dwLen; // point to the beginning of the other half
|
|
}
|
|
}
|
|
|
|
|
|
static ROOTKEY rkRoots[] =
|
|
{
|
|
{"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
|
|
{"HKLM", HKEY_LOCAL_MACHINE},
|
|
{"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT},
|
|
{"HKCR", HKEY_CLASSES_ROOT},
|
|
{"", HKEY_CLASSES_ROOT},
|
|
{"HKEY_CURRENT_USER", HKEY_CURRENT_USER},
|
|
{"HKCU", HKEY_CURRENT_USER},
|
|
{"HKEY_USERS", HKEY_USERS},
|
|
{"HKU", HKEY_USERS}
|
|
};
|
|
|
|
BOOL MapRootRegStr2Key(PCSTR pcszRootKey, HKEY *phkRootKey)
|
|
{
|
|
INT iIndex;
|
|
|
|
for (iIndex = 0; iIndex < ARRAYSIZE(rkRoots); iIndex++)
|
|
if (lstrcmpi(rkRoots[iIndex].pcszRootKey, pcszRootKey) == 0)
|
|
{
|
|
*phkRootKey = rkRoots[iIndex].hkRootKey;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
CHAR FindSeparator(PCSTR pcszSubKey, PCSTR pcszValueName)
|
|
// Go through pcszSeparatorList and return the first char that doesn't appear in any of the parameters;
|
|
// if such a char is not found, return '\0'
|
|
{
|
|
PCSTR pcszSeparatorList = ",$'?%;:"; // since the separator chars are 'pure' ASCII chars, i.e.,
|
|
// they are not part of Leading or Trailing DBCS Character Set,
|
|
// IsSeparator(), which assumes a 'pure' ASCII ch to look for,
|
|
// can be used
|
|
CHAR ch;
|
|
|
|
while (ch = *pcszSeparatorList++)
|
|
if (!IsSeparator(ch, pcszSubKey) && !IsSeparator(ch, pcszValueName))
|
|
break;
|
|
|
|
return ch;
|
|
}
|
|
|
|
|
|
BOOL RegKeyEmpty(HKEY hkRootKey, PCSTR pcszSubKey)
|
|
// Return TRUE if pcszSubKey is emtpy, i.e., no sub keys and value names; otherwise, return FALSE
|
|
{
|
|
HKEY hkKey;
|
|
BOOL bRet = FALSE;
|
|
CHAR szBuf[1];
|
|
DWORD dwBufLen = sizeof(szBuf);
|
|
|
|
if (RegOpenKeyEx(hkRootKey, pcszSubKey, 0, KEY_READ, &hkKey) == ERROR_SUCCESS)
|
|
{
|
|
if (RegEnumKey(hkKey, 0, szBuf, dwBufLen) == ERROR_NO_MORE_ITEMS &&
|
|
RegEnumValue(hkKey, 0, szBuf, &dwBufLen, NULL, NULL, NULL, NULL) == ERROR_NO_MORE_ITEMS)
|
|
bRet = TRUE;
|
|
|
|
RegCloseKey(hkKey);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
PSTR GetNextToken(PSTR *ppszData, CHAR chDeLim)
|
|
// If the next token in *ppszData is delimited by the chDeLim char, replace chDeLim
|
|
// in *ppszData by '\0', set *ppszData to point to the char after '\0' and return
|
|
// ptr to the beginning of the token; otherwise, return NULL
|
|
{
|
|
PSTR pszPos;
|
|
|
|
if (ppszData == NULL || *ppszData == NULL || **ppszData == '\0')
|
|
return NULL;
|
|
|
|
if ((pszPos = ANSIStrChr(*ppszData, chDeLim)) != NULL)
|
|
{
|
|
PSTR pszT = *ppszData;
|
|
|
|
*pszPos = '\0'; // replace chDeLim with '\0'
|
|
*ppszData = pszPos + 1;
|
|
pszPos = pszT;
|
|
}
|
|
else // chDeLim not found; set *ppszData to point to
|
|
// to the end of szData; the next invocation
|
|
// of this function would return NULL
|
|
{
|
|
pszPos = *ppszData;
|
|
*ppszData = pszPos + lstrlen(pszPos);
|
|
}
|
|
|
|
return pszPos;
|
|
}
|
|
|
|
|
|
BOOL FRunningOnNT()
|
|
{
|
|
static BOOL fIsNT4 = 2;
|
|
|
|
if (fIsNT4 == 2)
|
|
{
|
|
OSVERSIONINFO osviVerInfo;
|
|
|
|
osviVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx(&osviVerInfo);
|
|
|
|
fIsNT4 = osviVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT;
|
|
}
|
|
|
|
return fIsNT4;
|
|
}
|
|
|
|
|
|
VOID StartLogging(PCSTR pcszLogFileSecName)
|
|
{
|
|
CHAR szBuf[MAX_PATH], szLogFileName[MAX_PATH];
|
|
HKEY hkSubKey;
|
|
|
|
szLogFileName[0] = '\0';
|
|
|
|
// check if logging is enabled
|
|
GetProfileString("RegBackup", pcszLogFileSecName, "", szLogFileName, sizeof(szLogFileName));
|
|
if (*szLogFileName == '\0') // check in the registry
|
|
{
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_SAVERESTORE, 0, KEY_READ, &hkSubKey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwDataLen = sizeof(szLogFileName);
|
|
|
|
if (RegQueryValueEx(hkSubKey, pcszLogFileSecName, NULL, NULL, szLogFileName, &dwDataLen) != ERROR_SUCCESS)
|
|
*szLogFileName = '\0';
|
|
|
|
RegCloseKey(hkSubKey);
|
|
}
|
|
}
|
|
|
|
if (*szLogFileName)
|
|
{
|
|
if (szLogFileName[1] != ':') // crude way of determining if fully qualified path is specified or not
|
|
{
|
|
GetWindowsDirectory(szBuf, sizeof(szBuf)); // default to windows dir
|
|
AddPath(szBuf, szLogFileName);
|
|
}
|
|
else
|
|
lstrcpy(szBuf, szLogFileName);
|
|
|
|
if ((g_hLogFile = CreateFile(szBuf, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
|
|
SetFilePointer(g_hLogFile, 0, NULL, FILE_END); // append logging info to the file
|
|
}
|
|
}
|
|
|
|
|
|
VOID WriteToLog(PCSTR pcszFormatString, ...)
|
|
{
|
|
va_list vaArgs;
|
|
PSTR pszFullErrMsg = NULL;
|
|
DWORD dwBytesWritten;
|
|
|
|
if (g_hLogFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
va_start(vaArgs, pcszFormatString);
|
|
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_STRING,
|
|
(LPCVOID) pcszFormatString, 0, 0, (PSTR) &pszFullErrMsg, 0, &vaArgs);
|
|
|
|
if (pszFullErrMsg != NULL)
|
|
{
|
|
WriteFile(g_hLogFile, pszFullErrMsg, lstrlen(pszFullErrMsg), &dwBytesWritten, NULL);
|
|
LocalFree(pszFullErrMsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID StopLogging()
|
|
{
|
|
if (g_hLogFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(g_hLogFile);
|
|
g_hLogFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|