Source code of Windows XP (NT5)
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
43 KiB

  1. #include "ntapi.h"
  2. #include "advpack.h"
  3. #include "globals.h"
  4. #include "crc32.h"
  5. #include "resource.h"
  6. // macro definitions
  7. #define VDH_EXISTENCE_ONLY 0x01
  8. #define VDH_GET_VALUE 0x02
  9. #define VDH_DEL_VALUE 0x04
  10. #define BIG_BUF_SIZE (1024 + 512) // 1.5K
  11. // type definitions
  12. typedef struct tagROOTKEY
  13. {
  14. PCSTR pcszRootKey;
  15. HKEY hkRootKey;
  16. } ROOTKEY;
  17. // prototype declarations
  18. VOID EnumerateSubKey();
  19. BOOL RegSaveRestoreHelperWrapper(PCSTR pcszValueName, PCSTR pcszCRCValueName);
  20. BOOL RegSaveHelper(HKEY hkBckupKey, HKEY hkRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PCSTR pcszCRCValueName);
  21. BOOL RegRestoreHelper(HKEY hkBckupKey, HKEY hkRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PCSTR pcszCRCValueName);
  22. BOOL AddDelMapping(HKEY hkBckupKey, PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, DWORD dwFlags);
  23. BOOL MappingExists(HKEY hkBckupKey, PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName);
  24. BOOL SetValueData(HKEY hkBckupKey, PCSTR pcszValueName, CONST BYTE *pcbValueData, DWORD dwValueDataLen);
  25. BOOL ValueDataExists(HKEY hkBckupKey, PCSTR pcszValueName);
  26. BOOL GetValueData(HKEY hkBckupKey, PCSTR pcszValueName, PBYTE *ppbValueData, PDWORD pdwValueDataLen);
  27. BOOL DelValueData(HKEY hkBckupKey, PCSTR pcszValueName);
  28. BOOL ValueDataHelper(HKEY hkBckupKey, PCSTR pcszValueName, PBYTE *ppbValueData, PDWORD pdwValueDataLen, DWORD dwFlags);
  29. VOID Convert2CRC(PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PSTR pszCRCValueName);
  30. BOOL MapRootRegStr2Key(PCSTR pcszRootKey, HKEY *phkRootKey);
  31. CHAR FindSeparator(PCSTR pcszSubKey, PCSTR pcszValueName);
  32. BOOL RegKeyEmpty(HKEY hkRootKey, PCSTR pcszSubKey);
  33. PSTR GetNextToken(PSTR *ppszData, CHAR chDeLim);
  34. BOOL FRunningOnNT();
  35. // global variables
  36. BOOL g_bRet, g_fRestore, g_fAtleastOneRegSaved, g_fRemovBkData;
  37. HKEY g_hkBckupKey, g_hkRootKey;
  38. PCSTR g_pcszRootKey, g_pcszValueName;
  39. PSTR g_pszCRCTempBuf = NULL, g_pszSubKey = NULL, g_pszCRCSubKey = NULL;
  40. // related to logging
  41. VOID StartLogging(PCSTR pcszLogFileSecName);
  42. VOID WriteToLog(PCSTR pcszFormatString, ...);
  43. VOID StopLogging();
  44. HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
  45. HRESULT WINAPI RegSaveRestore(HWND hWnd, PCSTR pszTitleString, HKEY hkBckupKey, PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, DWORD dwFlags)
  46. {
  47. HWND hSaveWnd = ctx.hWnd;
  48. WORD wSaveQuietMode = ctx.wQuietMode;
  49. LPSTR lpszSaveTitle = ctx.lpszTitle;
  50. g_bRet = g_fAtleastOneRegSaved = FALSE;
  51. if ( (hWnd == INVALID_HANDLE_VALUE) || (dwFlags & ARSR_NOMESSAGES) )
  52. ctx.wQuietMode |= QUIETMODE_ALL;
  53. if ( hWnd != INVALID_HANDLE_VALUE )
  54. ctx.hWnd = hWnd;
  55. if (pszTitleString != NULL)
  56. ctx.lpszTitle = (PSTR)pszTitleString;
  57. g_hkBckupKey = hkBckupKey;
  58. g_pcszRootKey = pcszRootKey;
  59. g_pcszValueName = pcszValueName;
  60. g_fRestore = (dwFlags & IE4_RESTORE);
  61. g_fRemovBkData = (dwFlags & IE4_REMOVREGBKDATA) && g_fRestore;
  62. StartLogging(g_fRestore ? REG_RESTORE_LOG_KEY : REG_SAVE_LOG_KEY);
  63. if (!MapRootRegStr2Key(pcszRootKey, &g_hkRootKey))
  64. {
  65. ErrorMsg1Param(ctx.hWnd, IDS_INVALID_ROOTKEY, pcszRootKey);
  66. goto ErrExit;
  67. }
  68. // allocate a 1.5K buffer for g_pszCRCTempBuf
  69. if ((g_pszCRCTempBuf = (PSTR) LocalAlloc(LPTR, BIG_BUF_SIZE)) == NULL)
  70. {
  71. ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
  72. goto ErrExit;
  73. }
  74. if (!g_fRestore && pcszValueName == NULL && !(dwFlags & IE4_NOENUMKEY))
  75. {
  76. HKEY hk;
  77. // check if pcszSubKey exits; if it doesn't and it has not been already backed up,
  78. // set the IE4_NOENUMKEY flag so that an entry for this subkey is made in the backup branch
  79. if (RegOpenKeyEx(g_hkRootKey, pcszSubKey, 0, KEY_READ, &hk) != ERROR_SUCCESS)
  80. {
  81. if (!MappingExists(hkBckupKey, pcszRootKey, pcszSubKey, pcszValueName))
  82. dwFlags |= IE4_NOENUMKEY;
  83. }
  84. else
  85. RegCloseKey(hk);
  86. }
  87. if (pcszValueName != NULL || (dwFlags & IE4_NOENUMKEY))
  88. {
  89. g_pszSubKey = g_pszCRCSubKey = (PSTR) pcszSubKey;
  90. g_bRet = RegSaveRestoreHelperWrapper(g_pcszValueName, g_pcszValueName);
  91. if (!(dwFlags & IE4_NO_CRC_MAPPING) && g_bRet)
  92. {
  93. // store the RootKey, SubKey, Flags and ValueName in *.map.
  94. // this info would be used by the caller during the restore phase.
  95. g_bRet = AddDelMapping(g_hkBckupKey, g_pcszRootKey, g_pszSubKey, g_pcszValueName, dwFlags);
  96. }
  97. }
  98. else // save or restore pcszSubKey recursively
  99. {
  100. // allocate a 1K buffer for g_pszCRCSubKey
  101. if ((g_pszCRCSubKey = (PSTR) LocalAlloc(LPTR, 1024)) == NULL)
  102. {
  103. ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
  104. goto ErrExit;
  105. }
  106. if (!g_fRestore)
  107. {
  108. // if backup info exists for pcszRootKey\pcszSubKey, then we won't re-backup
  109. // the key recursively again; if we don't do this, then during an upgrade or reinstall
  110. // over a build, we would backup potentially newer values that got added during the running
  111. // of the program.
  112. if (MappingExists(hkBckupKey, pcszRootKey, pcszSubKey, pcszValueName))
  113. {
  114. g_bRet = TRUE;
  115. LocalFree(g_pszCRCSubKey);
  116. g_pszCRCSubKey = NULL;
  117. goto ErrExit;
  118. }
  119. // allocate a 1K buffer for g_pszSubKey
  120. if ((g_pszSubKey = (PSTR) LocalAlloc(LPTR, 1024)) == NULL)
  121. {
  122. ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
  123. LocalFree(g_pszCRCSubKey);
  124. goto ErrExit;
  125. }
  126. }
  127. else
  128. g_pszSubKey = (PSTR) pcszSubKey;
  129. g_bRet = TRUE;
  130. lstrcpy(g_pszCRCSubKey, pcszSubKey);
  131. if (!g_fRestore)
  132. lstrcpy(g_pszSubKey, pcszSubKey);
  133. EnumerateSubKey();
  134. if (!(dwFlags & IE4_NO_CRC_MAPPING))
  135. {
  136. if (g_fRestore)
  137. {
  138. if (g_bRet)
  139. {
  140. // if we couldn't restore everything; then we shouldn't delete the mapping info.
  141. g_bRet = AddDelMapping(g_hkBckupKey, g_pcszRootKey, g_pszSubKey, g_pcszValueName, dwFlags);
  142. }
  143. }
  144. else
  145. {
  146. if (g_fAtleastOneRegSaved)
  147. {
  148. // save the mapping info only if atleast one reg entry was saved
  149. g_bRet = AddDelMapping(g_hkBckupKey, g_pcszRootKey, g_pszSubKey, g_pcszValueName, dwFlags);
  150. }
  151. }
  152. }
  153. LocalFree(g_pszCRCSubKey);
  154. g_pszCRCSubKey = NULL;
  155. if (!g_fRestore)
  156. {
  157. LocalFree(g_pszSubKey);
  158. g_pszSubKey = NULL;
  159. }
  160. }
  161. ErrExit:
  162. StopLogging();
  163. if (g_pszCRCTempBuf != NULL)
  164. {
  165. LocalFree(g_pszCRCTempBuf);
  166. g_pszCRCTempBuf = NULL;
  167. }
  168. ctx.hWnd = hSaveWnd;
  169. ctx.wQuietMode = wSaveQuietMode;
  170. ctx.lpszTitle = lpszSaveTitle;
  171. return g_bRet ? S_OK : E_FAIL;
  172. }
  173. HRESULT WINAPI RegRestoreAll(HWND hWnd, PSTR pszTitleString, HKEY hkBckupKey)
  174. {
  175. HWND hSaveWnd = ctx.hWnd;
  176. WORD wSaveQuietMode = ctx.wQuietMode;
  177. LPSTR lpszSaveTitle = ctx.lpszTitle;
  178. HRESULT hRet;
  179. if (hWnd != INVALID_HANDLE_VALUE)
  180. ctx.hWnd = hWnd;
  181. else
  182. ctx.wQuietMode |= QUIETMODE_ALL;
  183. if (pszTitleString != NULL)
  184. ctx.lpszTitle = pszTitleString;
  185. hRet = RegRestoreAllEx( hkBckupKey );
  186. ctx.hWnd = hSaveWnd;
  187. ctx.wQuietMode = wSaveQuietMode;
  188. ctx.lpszTitle = lpszSaveTitle;
  189. return hRet;
  190. }
  191. HRESULT RegRestoreAllEx( HKEY hkBckupKey )
  192. // In one shot restore all the reg entries by enumerating all the values under hkBckupKey\*.map keys
  193. // and calling RegSaveRestore on each one of them.
  194. {
  195. BOOL bRet = TRUE;
  196. PSTR pszMappedValueData = NULL;
  197. CHAR szBuf[32];
  198. CHAR szSubKey[32];
  199. DWORD dwKeyIndex;
  200. HKEY hkSubKey;
  201. LONG lRetVal;
  202. if ((pszMappedValueData = (PSTR) LocalAlloc(LPTR, BIG_BUF_SIZE)) == NULL)
  203. {
  204. ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
  205. return E_FAIL;
  206. }
  207. // enumerate all the sub-keys under hkBckupKey
  208. for (dwKeyIndex = 0; ; dwKeyIndex++)
  209. {
  210. PSTR pszPtr;
  211. lRetVal = RegEnumKey(hkBckupKey, dwKeyIndex, szSubKey, sizeof(szSubKey));
  212. if (lRetVal != ERROR_SUCCESS)
  213. {
  214. if (lRetVal != ERROR_NO_MORE_ITEMS)
  215. bRet = FALSE;
  216. break;
  217. }
  218. // check if the keyname is of the form *.map
  219. if ((pszPtr = ANSIStrChr(szSubKey, '.')) != NULL && lstrcmpi(pszPtr, ".map") == 0)
  220. {
  221. if (RegOpenKeyEx(hkBckupKey, szSubKey, 0, KEY_READ, &hkSubKey) == ERROR_SUCCESS)
  222. {
  223. DWORD dwValIndex, dwValueLen, dwDataLen;
  224. // enumerate all the values under this key and restore each one of them
  225. dwValueLen = sizeof(szBuf);
  226. dwDataLen = BIG_BUF_SIZE;
  227. for (dwValIndex = 0; ; dwValIndex++)
  228. {
  229. CHAR chSeparator;
  230. PSTR pszFlags, pszRootKey, pszSubKey, pszValueName, pszPtr;
  231. DWORD dwMappedFlags;
  232. lRetVal = RegEnumValue(hkSubKey, dwValIndex, szBuf, &dwValueLen, NULL, NULL, pszMappedValueData, &dwDataLen);
  233. if (lRetVal != ERROR_SUCCESS)
  234. {
  235. if (lRetVal != ERROR_NO_MORE_ITEMS)
  236. bRet = FALSE;
  237. break;
  238. }
  239. // get the separator char first and then point to RootKey, SubKey and ValueName in pszMappedValueData
  240. pszPtr = pszMappedValueData;
  241. chSeparator = *pszPtr++;
  242. pszFlags = GetNextToken(&pszPtr, chSeparator);
  243. pszRootKey = GetNextToken(&pszPtr, chSeparator);
  244. pszSubKey = GetNextToken(&pszPtr, chSeparator);
  245. pszValueName = GetNextToken(&pszPtr, chSeparator);
  246. dwMappedFlags = (pszFlags != NULL) ? (DWORD) My_atoi(pszFlags) : 0;
  247. if (SUCCEEDED(RegSaveRestore( ctx.hWnd, ctx.lpszTitle, hkBckupKey, pszRootKey, pszSubKey, pszValueName, dwMappedFlags)))
  248. dwValIndex--; // RegSaveRestore would delete this value
  249. else
  250. bRet = FALSE;
  251. dwValueLen = sizeof(szBuf);
  252. dwDataLen = BIG_BUF_SIZE;
  253. }
  254. RegCloseKey(hkSubKey);
  255. }
  256. else
  257. bRet = FALSE;
  258. }
  259. }
  260. LocalFree(pszMappedValueData);
  261. // delete all the empty subkeys
  262. for (dwKeyIndex = 0; ; dwKeyIndex++)
  263. {
  264. lRetVal = RegEnumKey(hkBckupKey, dwKeyIndex, szSubKey, sizeof(szSubKey));
  265. if (lRetVal != ERROR_SUCCESS)
  266. {
  267. if (lRetVal != ERROR_NO_MORE_ITEMS)
  268. bRet = FALSE;
  269. break;
  270. }
  271. if (RegKeyEmpty(hkBckupKey, szSubKey) && RegDeleteKey(hkBckupKey, szSubKey) == ERROR_SUCCESS)
  272. dwKeyIndex--;
  273. }
  274. return bRet ? S_OK : E_FAIL;
  275. }
  276. VOID EnumerateSubKey()
  277. // Recursively enumerate value names and sub-keys and call Save/Restore on each of them
  278. {
  279. HKEY hkSubKey;
  280. DWORD dwIndex;
  281. static DWORD dwLen;
  282. static PCSTR pcszSubKeyPrefix = "_$Sub#";
  283. static PCSTR pcszValueNamePrefix = "_$Val#";
  284. static PCSTR pcszValueNamePrefix0 = "_$Val#0";
  285. static CHAR szValueName[MAX_PATH], szBckupCRCValueName[MAX_PATH];
  286. static PSTR pszPtr;
  287. if (g_fRestore)
  288. {
  289. // check if there is an entry in the back-up branch for just the g_pszCRCSubKey itself
  290. Convert2CRC(g_pcszRootKey, g_pszCRCSubKey, NULL, szBckupCRCValueName);
  291. if (ValueDataExists(g_hkBckupKey, szBckupCRCValueName)) // restore the no value names sub-key
  292. g_bRet = RegSaveRestoreHelperWrapper(NULL, NULL) && g_bRet;
  293. else
  294. {
  295. // enumerate values using the aliases
  296. for (dwIndex = 0; ; dwIndex++)
  297. {
  298. wsprintf(szValueName, "%s%lu", pcszValueNamePrefix, dwIndex);
  299. Convert2CRC(g_pcszRootKey, g_pszCRCSubKey, szValueName, szBckupCRCValueName);
  300. if (ValueDataExists(g_hkBckupKey, szBckupCRCValueName))
  301. g_bRet = RegSaveRestoreHelperWrapper(NULL, szValueName) && g_bRet;
  302. else
  303. break; // no more value names
  304. }
  305. }
  306. // enumerate sub-keys using the aliases
  307. for (dwIndex = 0; ; dwIndex++)
  308. {
  309. // check if there is any sub-key under g_pszCRCSubKey; if none, this is our terminating condition.
  310. // NOTE: a sub-key under g_pszCRCSubKey exists if:
  311. // (1) the sub-key itself exists OR
  312. // (2) the sub-key contains atleast one value name.
  313. // check if a sub-key by itself exists
  314. pszPtr = g_pszCRCSubKey + lstrlen(g_pszCRCSubKey);
  315. wsprintf(pszPtr, "\\%s%lu", pcszSubKeyPrefix, dwIndex);
  316. Convert2CRC(g_pcszRootKey, g_pszCRCSubKey, NULL, szBckupCRCValueName);
  317. if (ValueDataExists(g_hkBckupKey, szBckupCRCValueName))
  318. EnumerateSubKey();
  319. else
  320. {
  321. // check if the sub-key has the first value name alias - "_$Val#0"
  322. Convert2CRC(g_pcszRootKey, g_pszCRCSubKey, pcszValueNamePrefix0, szBckupCRCValueName);
  323. if (ValueDataExists(g_hkBckupKey, szBckupCRCValueName))
  324. EnumerateSubKey();
  325. else
  326. {
  327. GetParentDir(g_pszCRCSubKey);
  328. break; // no more sub-keys
  329. }
  330. }
  331. GetParentDir(g_pszCRCSubKey);
  332. }
  333. }
  334. else // backup the key
  335. {
  336. if (RegOpenKeyEx(g_hkRootKey, g_pszSubKey, 0, KEY_READ, &hkSubKey) == ERROR_SUCCESS)
  337. {
  338. dwLen = sizeof(szValueName);
  339. if (RegEnumValue(hkSubKey, 0, szValueName, &dwLen, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
  340. {
  341. // no value names; just save the key itself
  342. g_bRet = g_bRet && RegSaveRestoreHelperWrapper(NULL, NULL);
  343. }
  344. else
  345. {
  346. // enumerate the values
  347. dwIndex = 0;
  348. dwLen = sizeof(szValueName);
  349. while (RegEnumValue(hkSubKey, dwIndex, szValueName, &dwLen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  350. {
  351. // szBckupCRCValueName is really szCRCValueName
  352. wsprintf(szBckupCRCValueName, "%s%lu", pcszValueNamePrefix, dwIndex);
  353. g_bRet = g_bRet && RegSaveRestoreHelperWrapper(szValueName, szBckupCRCValueName);
  354. dwIndex++;
  355. dwLen = sizeof(szValueName);
  356. }
  357. }
  358. // enumerate sub-keys
  359. dwIndex = 0;
  360. // append '\\' to g_pszSubKey and make pszPtr point to the char after this last '\\' so that
  361. // when RegEnumKey puts a sub-key name at pszPtr, g_pszSubKey would have the complete sub-key path.
  362. dwLen = lstrlen(g_pszSubKey);
  363. pszPtr = g_pszSubKey + dwLen;
  364. *pszPtr++ = '\\';
  365. while (RegEnumKey(hkSubKey, dwIndex, pszPtr, 1024 - dwLen - 1) == ERROR_SUCCESS)
  366. {
  367. // prepare the sub-key alias
  368. pszPtr = g_pszCRCSubKey + lstrlen(g_pszCRCSubKey);
  369. wsprintf(pszPtr, "\\%s%lu", pcszSubKeyPrefix, dwIndex);
  370. EnumerateSubKey();
  371. GetParentDir(g_pszSubKey);
  372. GetParentDir(g_pszCRCSubKey);
  373. dwIndex++;
  374. // append '\\' to g_pszSubKey and make pszPtr point to the char after this last '\\' so that
  375. // when RegEnumKey puts a sub-key name at pszPtr, g_pszSubKey would have the complete sub-key path.
  376. dwLen = lstrlen(g_pszSubKey);
  377. pszPtr = g_pszSubKey + dwLen;
  378. *pszPtr++ = '\\';
  379. }
  380. *--pszPtr = '\0'; // chop the last '\\'; no DBCS clash because we added it
  381. RegCloseKey(hkSubKey);
  382. }
  383. }
  384. }
  385. BOOL RegSaveRestoreHelperWrapper(PCSTR pcszValueName, PCSTR pcszCRCValueName)
  386. {
  387. CHAR szBckupCRCValueName[32];
  388. // a unique back-up value name is obtained by concatenating pcszRootKey, pcszSubKey and pcszValueName
  389. // and the concatenated value name is stored as a 16-byte CRC value (space optimization)
  390. Convert2CRC(g_pcszRootKey, g_pszCRCSubKey, pcszCRCValueName, szBckupCRCValueName);
  391. WriteToLog("\r\nValueName = %1,%2", g_pcszRootKey, g_pszSubKey);
  392. if (pcszValueName != NULL)
  393. WriteToLog(",%1", pcszValueName);
  394. WriteToLog("\r\nCRCValueName = %1\r\n", szBckupCRCValueName);
  395. return (g_fRestore) ?
  396. RegRestoreHelper(g_hkBckupKey, g_hkRootKey, g_pszSubKey, pcszValueName, szBckupCRCValueName) :
  397. RegSaveHelper(g_hkBckupKey, g_hkRootKey, g_pszSubKey, pcszValueName, szBckupCRCValueName);
  398. }
  399. BOOL RegSaveHelper(HKEY hkBckupKey, HKEY hkRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PCSTR pcszCRCValueName)
  400. // If pcszValueName exists in the registry, back-up its value data; otherwise, remember how much of pcszSubKey
  401. // is present in the registry. This info would help during restoration.
  402. {
  403. HKEY hkSubKey = NULL;
  404. PSTR pszBckupData = NULL, pszCOSubKey = NULL, pszPtr;
  405. DWORD dwValueDataLen, dwValueType, dwBckupDataLen;
  406. CHAR chSeparator;
  407. BOOL fSubKeyValid;
  408. // don't backup the value data of pcszCRCValueName if it has been already backed-up
  409. if (ValueDataExists(hkBckupKey, pcszCRCValueName))
  410. return TRUE;
  411. // make a copy of pcszSubKey
  412. if ((pszCOSubKey = (PSTR) LocalAlloc(LPTR, lstrlen(pcszSubKey) + 1)) == NULL)
  413. {
  414. ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
  415. goto RegSaveHelperErr;
  416. }
  417. lstrcpy(pszCOSubKey, pcszSubKey);
  418. // loop through each branch in pszCOSubKey to find out how much of it is already present in the registry.
  419. // start with the whole sub key first and then chop one branch at a time from the end
  420. fSubKeyValid = TRUE;
  421. do
  422. {
  423. if (RegOpenKeyEx(hkRootKey, pszCOSubKey, 0, KEY_READ, &hkSubKey) == ERROR_SUCCESS)
  424. break;
  425. } while (fSubKeyValid = GetParentDir(pszCOSubKey));
  426. // NOTE: fSubKeyValid == FALSE here means that no branch of pcszSubKey is present
  427. if (fSubKeyValid && lstrcmpi(pcszSubKey, pszCOSubKey) == 0)
  428. // entire subkey is present in the registry
  429. {
  430. if (pcszValueName != NULL)
  431. {
  432. if (*pcszValueName || FRunningOnNT())
  433. {
  434. // check if pcszValueName is present in the registry
  435. if (RegQueryValueEx(hkSubKey, pcszValueName, NULL, &dwValueType, NULL, &dwValueDataLen) != ERROR_SUCCESS)
  436. pcszValueName = NULL;
  437. }
  438. else
  439. {
  440. LONG lRetVal;
  441. CHAR szDummyBuf[1];
  442. // On Win95, for the default value name, its existence is checked as follows:
  443. // - pass in a dummy buffer for the value data but pass in the size of the buffer as 0
  444. // - the query would succeed if and only if there is no value data set
  445. // - for all other cases, including the case where the value data is just the empty string,
  446. // the query would fail and dwValueDataLen would contain the no. of bytes needed to
  447. // fit in the value data
  448. // On NT4.0, if no value data is set, the query returns ERROR_FILE_NOT_FOUND
  449. // NOTE: To minimize risk, we don't follow this code path if running on NT4.0
  450. dwValueDataLen = 0;
  451. lRetVal = RegQueryValueEx(hkSubKey, pcszValueName, NULL, &dwValueType, (LPBYTE) szDummyBuf, &dwValueDataLen);
  452. if (lRetVal == ERROR_SUCCESS || lRetVal == ERROR_FILE_NOT_FOUND)
  453. pcszValueName = NULL;
  454. }
  455. }
  456. }
  457. else
  458. pcszValueName = NULL;
  459. WriteToLog("BckupSubKey = ");
  460. // compute the length required for pszBckupData
  461. // format of pszBckupData is (assume that the separator char is ','):
  462. // ,[<szSubKey>,[<szValueName>,\0<dwValueType><dwValueDataLen><ValueData>]]
  463. dwBckupDataLen = 1 + 1; // the separator char + '\0'
  464. if (fSubKeyValid)
  465. {
  466. WriteToLog("%1", pszCOSubKey);
  467. dwBckupDataLen += lstrlen(pszCOSubKey) + 1;
  468. if (pcszValueName != NULL)
  469. {
  470. WriteToLog(", BckupValueName = %1", pcszValueName);
  471. dwBckupDataLen += lstrlen(pcszValueName) + 1 + 2 * sizeof(DWORD) + dwValueDataLen;
  472. // 2 * sizeof(DWORD) == sizeof(dwValueType) + sizeof(dwValueDataLen)
  473. }
  474. }
  475. WriteToLog("\r\n");
  476. // determine a valid separator char that is not one of the chars in SubKey and ValueName
  477. if ((chSeparator = FindSeparator(fSubKeyValid ? pszCOSubKey : NULL, pcszValueName)) == '\0')
  478. {
  479. ErrorMsg(ctx.hWnd, IDS_NO_SEPARATOR_CHAR);
  480. goto RegSaveHelperErr;
  481. }
  482. // allocate memory for pszBckupData
  483. if ((pszBckupData = (PSTR) LocalAlloc(LPTR, dwBckupDataLen)) == NULL)
  484. {
  485. ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
  486. goto RegSaveHelperErr;
  487. }
  488. // start building pszBckupData
  489. // format of pszBckupData is (assume that the separator char is ','):
  490. // ,[<szSubKey>,[<szValueName>,\0<dwValueType><dwValueDataLen><ValueData>]]
  491. pszPtr = pszBckupData;
  492. *pszPtr++ = chSeparator;
  493. *pszPtr = '\0';
  494. if (fSubKeyValid)
  495. {
  496. lstrcpy(pszPtr, pszCOSubKey);
  497. pszPtr += lstrlen(pszPtr);
  498. *pszPtr++ = chSeparator;
  499. *pszPtr = '\0';
  500. if (pcszValueName != NULL)
  501. {
  502. lstrcpy(pszPtr, pcszValueName);
  503. pszPtr += lstrlen(pszPtr);
  504. *pszPtr++ = chSeparator;
  505. *pszPtr++ = '\0'; // include the '\0' char
  506. *((DWORD UNALIGNED *) pszPtr)++ = dwValueType;
  507. *((DWORD UNALIGNED *) pszPtr)++ = dwValueDataLen;
  508. // NOTE: pszPtr points to the start position of value data in pszBckupData
  509. RegQueryValueEx(hkSubKey, pcszValueName, NULL, &dwValueType, (PBYTE) pszPtr, &dwValueDataLen);
  510. }
  511. }
  512. if (!SetValueData(hkBckupKey, pcszCRCValueName, (CONST BYTE *) pszBckupData, dwBckupDataLen))
  513. {
  514. ErrorMsg1Param(ctx.hWnd, IDS_ERR_REGSETVALUE, pcszCRCValueName);
  515. goto RegSaveHelperErr;
  516. }
  517. WriteToLog("Value backed-up\r\n");
  518. g_fAtleastOneRegSaved = TRUE;
  519. if (hkSubKey != NULL)
  520. RegCloseKey(hkSubKey);
  521. LocalFree(pszCOSubKey);
  522. LocalFree(pszBckupData);
  523. return TRUE;
  524. RegSaveHelperErr:
  525. if (hkSubKey != NULL)
  526. RegCloseKey(hkSubKey);
  527. if (pszCOSubKey != NULL)
  528. LocalFree(pszCOSubKey);
  529. if (pszBckupData != NULL)
  530. LocalFree(pszBckupData);
  531. return FALSE;
  532. }
  533. BOOL RegRestoreHelper(HKEY hkBckupKey, HKEY hkRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PCSTR pcszCRCValueName)
  534. // (1) If the value name in the backed-up value data is not NULL, it means that pcszValueName existed during
  535. // back-up time; so, restore the original value data.
  536. // (2) If the value name in the backed-up value data is NULL and pcszValueName is not NULL, it means that
  537. // pcszValueName didn't exist during the back-up time; so, delete it.
  538. // (3) If the backed-up sub key is shorter than pcszSubKey, then delete one branch at a time, if it is empty,
  539. // from the end in pcszSubKey till pcszSubKey becomes identical to the backed-up sub key.
  540. {
  541. HKEY hkSubKey = NULL;
  542. PSTR pszBckupData = NULL, pszCOSubKey, pszPtr, pszBckupSubKey, pszBckupValueName;
  543. DWORD dwValueDataLen, dwValueType, dwBckupDataLen, dwDisposition;
  544. CHAR chSeparator;
  545. if (!GetValueData(hkBckupKey, pcszCRCValueName, &pszBckupData, &dwBckupDataLen))
  546. {
  547. ErrorMsg1Param(ctx.hWnd, IDS_ERR_REGQUERYVALUE, pcszCRCValueName);
  548. goto RegRestoreHelperErr;
  549. }
  550. // format of pszBckupData is (assume that the separator char is ','):
  551. // ,[<szSubKey>,[<szValueName>,\0<dwValueType><dwValueDataLen><ValueData>]]
  552. pszPtr = pszBckupData;
  553. chSeparator = *pszPtr++; // initialize the separator char; since it is not part of
  554. // Leading or Trailing DBCS Character Set, pszPtr++ is fine
  555. pszBckupSubKey = GetNextToken(&pszPtr, chSeparator);
  556. pszBckupValueName = GetNextToken(&pszPtr, chSeparator);
  557. pszPtr++; // skip '\0'
  558. if (g_fRemovBkData)
  559. WriteToLog("RemoveRegistryBackupData: ");
  560. WriteToLog("BckupSubKey = ");
  561. if (pszBckupSubKey != NULL)
  562. {
  563. WriteToLog("%1", pszBckupSubKey);
  564. if (pcszValueName == NULL && lstrlen(pszBckupSubKey) > lstrlen(pcszSubKey))
  565. {
  566. // means that pcszSubKey was backed-up thru EnumerateSubKey
  567. pcszSubKey = pszBckupSubKey;
  568. }
  569. }
  570. // check to see if we want to restore the reg keys, values or remove reg backup data
  571. if (g_fRemovBkData)
  572. {
  573. if (pszBckupValueName != NULL) // restore the backed-up value data -- case (1)
  574. {
  575. WriteToLog(", BckupValueName = %1", pcszValueName);
  576. }
  577. DelValueData(hkBckupKey, pcszCRCValueName); // delete the back-up value name
  578. WriteToLog(" <Done>\r\n");
  579. goto Done;
  580. }
  581. if (RegCreateKeyEx(hkRootKey, pcszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkSubKey, &dwDisposition) == ERROR_SUCCESS)
  582. {
  583. if (pszBckupValueName != NULL) // restore the backed-up value data -- case (1)
  584. {
  585. WriteToLog(", BckupValueName = %1", pcszValueName);
  586. dwValueType = *((DWORD UNALIGNED *) pszPtr)++;
  587. dwValueDataLen = *((DWORD UNALIGNED *) pszPtr)++;
  588. if (RegSetValueEx(hkSubKey, pszBckupValueName, 0, dwValueType, (CONST BYTE *) pszPtr, dwValueDataLen) != ERROR_SUCCESS)
  589. {
  590. ErrorMsg1Param(ctx.hWnd, IDS_ERR_REGSETVALUE, pszBckupValueName);
  591. goto RegRestoreHelperErr;
  592. }
  593. }
  594. else if (pcszValueName != NULL)
  595. {
  596. // means that the value name didn't exist while backing-up; so delete it -- case (2)
  597. RegDeleteValue(hkSubKey, pcszValueName);
  598. }
  599. RegCloseKey(hkSubKey);
  600. DelValueData(hkBckupKey, pcszCRCValueName); // delete the back-up value name
  601. WriteToLog("\r\nBackup Value deleted");
  602. }
  603. WriteToLog("\r\n");
  604. dwBckupDataLen = 0;
  605. if (pszBckupValueName == NULL && (pszBckupSubKey == NULL || (DWORD) lstrlen(pcszSubKey) > (dwBckupDataLen = lstrlen(pszBckupSubKey))))
  606. {
  607. // only a part of the subkey was present in the registry during back-up;
  608. // delete the remaining branches if they are empty -- case (3)
  609. // make a copy of pcszSubKey
  610. if ((pszCOSubKey = (PSTR) LocalAlloc(LPTR, lstrlen(pcszSubKey) + 1)) != NULL)
  611. {
  612. lstrcpy(pszCOSubKey, pcszSubKey);
  613. // start processing one branch at a time from the end in pszCOSubKey;
  614. // if the branch is empty, delete it;
  615. // stop processing as soon as pszCOSubKey becomes identical to pszBckupSubKey
  616. do
  617. {
  618. // NOTE: Need to delete a key only if it's empty; otherwise, we would delete
  619. // more than what we backed up. For example, if component A wanted to backup
  620. // HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\InternetExplorer
  621. // and the machine didn't have the Uninstall key, we should not blow away the
  622. // entire Uninstall key when we uninstall A as other components might have added
  623. // their uninstall strings there. So delete a key only if it's empty.
  624. if (RegKeyEmpty(hkRootKey, pszCOSubKey))
  625. RegDeleteKey(hkRootKey, pszCOSubKey);
  626. else
  627. break;
  628. } while (GetParentDir(pszCOSubKey) && (DWORD) lstrlen(pszCOSubKey) > dwBckupDataLen);
  629. LocalFree(pszCOSubKey);
  630. }
  631. }
  632. Done:
  633. LocalFree(pszBckupData);
  634. return TRUE;
  635. RegRestoreHelperErr:
  636. if (hkSubKey != NULL)
  637. RegCloseKey(hkSubKey);
  638. if (pszBckupData != NULL)
  639. LocalFree(pszBckupData);
  640. return FALSE;
  641. }
  642. BOOL AddDelMapping(HKEY hkBckupKey, PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, DWORD dwFlags)
  643. {
  644. CHAR szCRCValueName[32], szBuf[32];
  645. DWORD dwIndex;
  646. BOOL bFound = FALSE;
  647. HKEY hkSubKey = NULL;
  648. Convert2CRC(pcszRootKey, pcszSubKey, pcszValueName, szCRCValueName);
  649. // enumerate all the sub-keys under hkBckupKey
  650. for (dwIndex = 0; !bFound && RegEnumKey(hkBckupKey, dwIndex, szBuf, sizeof(szBuf)) == ERROR_SUCCESS; dwIndex++)
  651. {
  652. PSTR pszPtr;
  653. // check if the keyname is of the form *.map
  654. if ((pszPtr = ANSIStrChr(szBuf, '.')) != NULL && lstrcmpi(pszPtr, ".map") == 0)
  655. {
  656. if (RegOpenKeyEx(hkBckupKey, szBuf, 0, KEY_READ | KEY_WRITE, &hkSubKey) == ERROR_SUCCESS)
  657. {
  658. if (RegQueryValueEx(hkSubKey, szCRCValueName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  659. bFound = TRUE;
  660. else
  661. {
  662. RegCloseKey(hkSubKey);
  663. hkSubKey = NULL;
  664. }
  665. }
  666. }
  667. }
  668. if (g_fRestore)
  669. {
  670. if (bFound)
  671. RegDeleteValue(hkSubKey, szCRCValueName);
  672. }
  673. else
  674. {
  675. if (!bFound)
  676. {
  677. DWORD dwMapKeyIndex = 0;
  678. // add the quadruplet, i.e., ",Flags,RootKey,SubKey,ValueName" to hkBckupKey\*.map
  679. wsprintf(szBuf, "%lu.map", dwMapKeyIndex);
  680. if (RegCreateKeyEx(hkBckupKey, szBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkSubKey, NULL) == ERROR_SUCCESS)
  681. {
  682. PSTR pszPtr;
  683. CHAR chSeparator;
  684. // IMPORTANT: the global buffer g_pszCRCTempBuf is used in Convert2CRC;
  685. // so be very careful if you want to call Convert2CRC after g_pszCRCTempBuf has been initialized here.
  686. pszPtr = g_pszCRCTempBuf;
  687. // determine a valid separator char that is not one of the chars in SubKey and ValueName
  688. if ((chSeparator = FindSeparator(pcszSubKey, pcszValueName)) == '\0')
  689. {
  690. ErrorMsg(ctx.hWnd, IDS_NO_SEPARATOR_CHAR);
  691. }
  692. else
  693. {
  694. // reset the IE4_BACKNEW bit and set the IE4_RESTORE bit
  695. dwFlags &= ~IE4_BACKNEW;
  696. dwFlags |= IE4_RESTORE;
  697. wsprintf(szBuf, "%lu", dwFlags);
  698. // format of mapping data is (say ',' is chSeparator): ,<Flags>,<RootKey>,<SubKey>,[<ValueName>,]
  699. {
  700. *pszPtr++ = chSeparator;
  701. lstrcpy(pszPtr, szBuf);
  702. pszPtr += lstrlen(pszPtr);
  703. *pszPtr++ = chSeparator;
  704. lstrcpy(pszPtr, pcszRootKey);
  705. pszPtr += lstrlen(pszPtr);
  706. *pszPtr++ = chSeparator;
  707. lstrcpy(pszPtr, pcszSubKey);
  708. pszPtr += lstrlen(pszPtr);
  709. *pszPtr++ = chSeparator;
  710. if (pcszValueName != NULL)
  711. {
  712. lstrcpy(pszPtr, pcszValueName);
  713. pszPtr += lstrlen(pszPtr);
  714. *pszPtr++ = chSeparator;
  715. }
  716. *pszPtr = '\0';
  717. }
  718. if (RegSetValueEx(hkSubKey, szCRCValueName, 0, REG_SZ, (CONST BYTE *) g_pszCRCTempBuf, lstrlen(g_pszCRCTempBuf) + 1) != ERROR_SUCCESS)
  719. {
  720. do
  721. {
  722. // hkBckupKey\<dwIndex>.map key may have reached the 64K limit; create another sub-key
  723. RegCloseKey(hkSubKey);
  724. hkSubKey = NULL;
  725. wsprintf(szBuf, "%lu.map", ++dwMapKeyIndex);
  726. if (RegCreateKeyEx(hkBckupKey, szBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkSubKey, NULL) == ERROR_SUCCESS)
  727. {
  728. bFound = RegSetValueEx(hkSubKey, szCRCValueName, 0, REG_SZ, (CONST BYTE *) g_pszCRCTempBuf, lstrlen(g_pszCRCTempBuf) + 1) == ERROR_SUCCESS;
  729. }
  730. } while (!bFound && dwMapKeyIndex < 64);
  731. }
  732. else
  733. bFound = TRUE;
  734. }
  735. }
  736. }
  737. }
  738. if (hkSubKey != NULL)
  739. RegCloseKey(hkSubKey);
  740. return bFound;
  741. }
  742. BOOL MappingExists(HKEY hkBckupKey, PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName)
  743. {
  744. CHAR szCRCValueName[32], szBuf[32];
  745. DWORD dwIndex;
  746. BOOL bFound = FALSE;
  747. Convert2CRC(pcszRootKey, pcszSubKey, pcszValueName, szCRCValueName);
  748. // enumerate all the sub-keys under hkBckupKey
  749. for (dwIndex = 0; !bFound && RegEnumKey(hkBckupKey, dwIndex, szBuf, sizeof(szBuf)) == ERROR_SUCCESS; dwIndex++)
  750. {
  751. PSTR pszPtr;
  752. // check if the keyname is of the form *.map
  753. if ((pszPtr = ANSIStrChr(szBuf, '.')) != NULL && lstrcmpi(pszPtr, ".map") == 0)
  754. {
  755. HKEY hkSubKey;
  756. if (RegOpenKeyEx(hkBckupKey, szBuf, 0, KEY_READ | KEY_WRITE, &hkSubKey) == ERROR_SUCCESS)
  757. {
  758. if (RegQueryValueEx(hkSubKey, szCRCValueName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  759. bFound = TRUE;
  760. RegCloseKey(hkSubKey);
  761. }
  762. }
  763. }
  764. return bFound;
  765. }
  766. BOOL SetValueData(HKEY hkBckupKey, PCSTR pcszValueName, CONST BYTE *pcbValueData, DWORD dwValueDataLen)
  767. // Set the (pcszValueName, pcbValueData) pair in hkBckupKey
  768. {
  769. BOOL fDone = FALSE;
  770. HKEY hkSubKey;
  771. DWORD dwDisposition, dwSubKey;
  772. CHAR szSubKey[16];
  773. // since a key has a size limit of 64K, automatically generate a new sub-key if the other ones are full
  774. for (dwSubKey = 0; !fDone && dwSubKey < 64; dwSubKey++)
  775. {
  776. wsprintf(szSubKey, "%lu", dwSubKey); // sub-keys are named 0, 1, 2, etc.
  777. if (RegCreateKeyEx(hkBckupKey, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkSubKey, &dwDisposition) == ERROR_SUCCESS)
  778. {
  779. if (RegSetValueEx(hkSubKey, pcszValueName, 0, REG_BINARY, pcbValueData, dwValueDataLen) == ERROR_SUCCESS)
  780. fDone = TRUE;
  781. RegCloseKey(hkSubKey);
  782. }
  783. }
  784. return fDone;
  785. }
  786. BOOL ValueDataExists(HKEY hkBckupKey, PCSTR pcszValueName)
  787. // Return TRUE if pcszValueName exists in hkBckupKey; otherwise, return FALSE
  788. {
  789. return ValueDataHelper(hkBckupKey, pcszValueName, NULL, NULL, VDH_EXISTENCE_ONLY);
  790. }
  791. BOOL GetValueData(HKEY hkBckupKey, PCSTR pcszValueName, PBYTE *ppbValueData, PDWORD pdwValueDataLen)
  792. // Allocate a buffer of required size and return the value data of pcszValueName in hkBckupKey
  793. {
  794. return ValueDataHelper(hkBckupKey, pcszValueName, ppbValueData, pdwValueDataLen, VDH_GET_VALUE);
  795. }
  796. BOOL DelValueData(HKEY hkBckupKey, PCSTR pcszValueName)
  797. // Delete pcszValueName from hkBckupKey
  798. {
  799. return ValueDataHelper(hkBckupKey, pcszValueName, NULL, NULL, VDH_DEL_VALUE);
  800. }
  801. BOOL ValueDataHelper(HKEY hkBckupKey, PCSTR pcszValueName, PBYTE *ppbValueData, PDWORD pdwValueDataLen, DWORD dwFlags)
  802. {
  803. BOOL fDone = FALSE;
  804. HKEY hkSubKey;
  805. CHAR szSubKey[16];
  806. DWORD dwIndex, dwDataLen;
  807. if (dwFlags == VDH_GET_VALUE && ppbValueData == NULL)
  808. return FALSE;
  809. // search for pcszValueName in all the sub-keys
  810. for (dwIndex = 0; !fDone && RegEnumKey(hkBckupKey, dwIndex, szSubKey, sizeof(szSubKey)) == ERROR_SUCCESS; dwIndex++)
  811. {
  812. if ( ANSIStrChr(szSubKey, '.') == NULL) // check only in non *.map keys
  813. {
  814. if (RegOpenKeyEx(hkBckupKey, szSubKey, 0, KEY_READ | KEY_WRITE, &hkSubKey) == ERROR_SUCCESS)
  815. {
  816. if (RegQueryValueEx(hkSubKey, pcszValueName, NULL, NULL, NULL, &dwDataLen) == ERROR_SUCCESS)
  817. {
  818. switch (dwFlags)
  819. {
  820. case VDH_DEL_VALUE:
  821. RegDeleteValue(hkSubKey, pcszValueName);
  822. break;
  823. case VDH_GET_VALUE:
  824. if ((*ppbValueData = (PBYTE) LocalAlloc(LPTR, dwDataLen)) == NULL)
  825. {
  826. RegCloseKey(hkSubKey);
  827. ErrorMsg(ctx.hWnd, IDS_ERR_NO_MEMORY);
  828. return FALSE;
  829. }
  830. *pdwValueDataLen = dwDataLen;
  831. RegQueryValueEx(hkSubKey, pcszValueName, NULL, NULL, *ppbValueData, &dwDataLen);
  832. break;
  833. case VDH_EXISTENCE_ONLY:
  834. break;
  835. }
  836. fDone = TRUE;
  837. }
  838. RegCloseKey(hkSubKey);
  839. }
  840. }
  841. }
  842. return fDone;
  843. }
  844. VOID Convert2CRC(PCSTR pcszRootKey, PCSTR pcszSubKey, PCSTR pcszValueName, PSTR pszCRCValueName)
  845. // Concatenate pcszRootKey, pcszSubKey and pcszValueName and convert the concatenated value name
  846. // to a 16-byte CRC value.
  847. {
  848. PSTR pszPtr = g_pszCRCTempBuf;
  849. ULONG ulCRC = CRC32_INITIAL_VALUE;
  850. DWORD dwLen;
  851. // concatenate pcszRootKey, pcszSubKey, pcszValueName
  852. lstrcpy(pszPtr, pcszRootKey);
  853. lstrcat(pszPtr, pcszSubKey);
  854. if (pcszValueName != NULL)
  855. lstrcat(pszPtr, pcszValueName);
  856. // call CRC32Compute on each half of szBuf and store the 2-DWORD result in ASCII form (16 bytes)
  857. for (dwLen = lstrlen(pszPtr) / 2; dwLen; dwLen = lstrlen(pszPtr))
  858. {
  859. ulCRC = CRC32Compute(pszPtr, dwLen, ulCRC);
  860. wsprintf(pszCRCValueName, "%08x", ulCRC);
  861. pszCRCValueName += 8;
  862. pszPtr += dwLen; // point to the beginning of the other half
  863. }
  864. }
  865. static ROOTKEY rkRoots[] =
  866. {
  867. {"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
  868. {"HKLM", HKEY_LOCAL_MACHINE},
  869. {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT},
  870. {"HKCR", HKEY_CLASSES_ROOT},
  871. {"", HKEY_CLASSES_ROOT},
  872. {"HKEY_CURRENT_USER", HKEY_CURRENT_USER},
  873. {"HKCU", HKEY_CURRENT_USER},
  874. {"HKEY_USERS", HKEY_USERS},
  875. {"HKU", HKEY_USERS}
  876. };
  877. BOOL MapRootRegStr2Key(PCSTR pcszRootKey, HKEY *phkRootKey)
  878. {
  879. INT iIndex;
  880. for (iIndex = 0; iIndex < ARRAYSIZE(rkRoots); iIndex++)
  881. if (lstrcmpi(rkRoots[iIndex].pcszRootKey, pcszRootKey) == 0)
  882. {
  883. *phkRootKey = rkRoots[iIndex].hkRootKey;
  884. return TRUE;
  885. }
  886. return FALSE;
  887. }
  888. CHAR FindSeparator(PCSTR pcszSubKey, PCSTR pcszValueName)
  889. // Go through pcszSeparatorList and return the first char that doesn't appear in any of the parameters;
  890. // if such a char is not found, return '\0'
  891. {
  892. PCSTR pcszSeparatorList = ",$'?%;:"; // since the separator chars are 'pure' ASCII chars, i.e.,
  893. // they are not part of Leading or Trailing DBCS Character Set,
  894. // IsSeparator(), which assumes a 'pure' ASCII ch to look for,
  895. // can be used
  896. CHAR ch;
  897. while (ch = *pcszSeparatorList++)
  898. if (!IsSeparator(ch, pcszSubKey) && !IsSeparator(ch, pcszValueName))
  899. break;
  900. return ch;
  901. }
  902. BOOL RegKeyEmpty(HKEY hkRootKey, PCSTR pcszSubKey)
  903. // Return TRUE if pcszSubKey is emtpy, i.e., no sub keys and value names; otherwise, return FALSE
  904. {
  905. HKEY hkKey;
  906. BOOL bRet = FALSE;
  907. CHAR szBuf[1];
  908. DWORD dwBufLen = sizeof(szBuf);
  909. if (RegOpenKeyEx(hkRootKey, pcszSubKey, 0, KEY_READ, &hkKey) == ERROR_SUCCESS)
  910. {
  911. if (RegEnumKey(hkKey, 0, szBuf, dwBufLen) == ERROR_NO_MORE_ITEMS &&
  912. RegEnumValue(hkKey, 0, szBuf, &dwBufLen, NULL, NULL, NULL, NULL) == ERROR_NO_MORE_ITEMS)
  913. bRet = TRUE;
  914. RegCloseKey(hkKey);
  915. }
  916. return bRet;
  917. }
  918. PSTR GetNextToken(PSTR *ppszData, CHAR chDeLim)
  919. // If the next token in *ppszData is delimited by the chDeLim char, replace chDeLim
  920. // in *ppszData by '\0', set *ppszData to point to the char after '\0' and return
  921. // ptr to the beginning of the token; otherwise, return NULL
  922. {
  923. PSTR pszPos;
  924. if (ppszData == NULL || *ppszData == NULL || **ppszData == '\0')
  925. return NULL;
  926. if ((pszPos = ANSIStrChr(*ppszData, chDeLim)) != NULL)
  927. {
  928. PSTR pszT = *ppszData;
  929. *pszPos = '\0'; // replace chDeLim with '\0'
  930. *ppszData = pszPos + 1;
  931. pszPos = pszT;
  932. }
  933. else // chDeLim not found; set *ppszData to point to
  934. // to the end of szData; the next invocation
  935. // of this function would return NULL
  936. {
  937. pszPos = *ppszData;
  938. *ppszData = pszPos + lstrlen(pszPos);
  939. }
  940. return pszPos;
  941. }
  942. BOOL FRunningOnNT()
  943. {
  944. static BOOL fIsNT4 = 2;
  945. if (fIsNT4 == 2)
  946. {
  947. OSVERSIONINFO osviVerInfo;
  948. osviVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  949. GetVersionEx(&osviVerInfo);
  950. fIsNT4 = osviVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT;
  951. }
  952. return fIsNT4;
  953. }
  954. VOID StartLogging(PCSTR pcszLogFileSecName)
  955. {
  956. CHAR szBuf[MAX_PATH], szLogFileName[MAX_PATH];
  957. HKEY hkSubKey;
  958. szLogFileName[0] = '\0';
  959. // check if logging is enabled
  960. GetProfileString("RegBackup", pcszLogFileSecName, "", szLogFileName, sizeof(szLogFileName));
  961. if (*szLogFileName == '\0') // check in the registry
  962. {
  963. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_SAVERESTORE, 0, KEY_READ, &hkSubKey) == ERROR_SUCCESS)
  964. {
  965. DWORD dwDataLen = sizeof(szLogFileName);
  966. if (RegQueryValueEx(hkSubKey, pcszLogFileSecName, NULL, NULL, szLogFileName, &dwDataLen) != ERROR_SUCCESS)
  967. *szLogFileName = '\0';
  968. RegCloseKey(hkSubKey);
  969. }
  970. }
  971. if (*szLogFileName)
  972. {
  973. if (szLogFileName[1] != ':') // crude way of determining if fully qualified path is specified or not
  974. {
  975. GetWindowsDirectory(szBuf, sizeof(szBuf)); // default to windows dir
  976. AddPath(szBuf, szLogFileName);
  977. }
  978. else
  979. lstrcpy(szBuf, szLogFileName);
  980. if ((g_hLogFile = CreateFile(szBuf, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
  981. SetFilePointer(g_hLogFile, 0, NULL, FILE_END); // append logging info to the file
  982. }
  983. }
  984. VOID WriteToLog(PCSTR pcszFormatString, ...)
  985. {
  986. va_list vaArgs;
  987. PSTR pszFullErrMsg = NULL;
  988. DWORD dwBytesWritten;
  989. if (g_hLogFile != INVALID_HANDLE_VALUE)
  990. {
  991. va_start(vaArgs, pcszFormatString);
  992. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_STRING,
  993. (LPCVOID) pcszFormatString, 0, 0, (PSTR) &pszFullErrMsg, 0, &vaArgs);
  994. if (pszFullErrMsg != NULL)
  995. {
  996. WriteFile(g_hLogFile, pszFullErrMsg, lstrlen(pszFullErrMsg), &dwBytesWritten, NULL);
  997. LocalFree(pszFullErrMsg);
  998. }
  999. }
  1000. }
  1001. VOID StopLogging()
  1002. {
  1003. if (g_hLogFile != INVALID_HANDLE_VALUE)
  1004. {
  1005. CloseHandle(g_hLogFile);
  1006. g_hLogFile = INVALID_HANDLE_VALUE;
  1007. }
  1008. }