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.

658 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: registry.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #pragma hdrstop
  12. #include "registry.h"
  13. RegKey::RegKey(
  14. void
  15. ) : m_hkeyRoot(NULL),
  16. m_hkey(NULL)
  17. {
  18. m_szSubKey[0] = TEXT('\0');
  19. }
  20. RegKey::RegKey(
  21. HKEY hkeyRoot,
  22. LPCTSTR pszSubKey
  23. ) : m_hkeyRoot(hkeyRoot),
  24. m_hkey(NULL)
  25. {
  26. lstrcpyn(m_szSubKey, pszSubKey, ARRAYSIZE(m_szSubKey));
  27. }
  28. RegKey::~RegKey(
  29. void
  30. )
  31. {
  32. Close();
  33. }
  34. HRESULT
  35. RegKey::Open(
  36. REGSAM samDesired, // Access mask (i.e. KEY_READ, KEY_WRITE etc.)
  37. bool bCreate // Create key if it doesn't exist?
  38. ) const
  39. {
  40. DWORD dwResult = ERROR_SUCCESS;
  41. HKEY hkeyRoot = m_hkeyRoot; // Assume we'll use m_hkeyRoot;
  42. bool bCloseRootKey = false;
  43. Close();
  44. if (HKEY_CURRENT_USER == hkeyRoot)
  45. {
  46. //
  47. // Special-case HKEY_CURRENT_USER.
  48. // Since we're running from winlogon and need to open
  49. // the user hive during tricky times we need to
  50. // call RegOpenCurrentUser(). If it's successful all
  51. // we do is replace the hkeyRoot member with the
  52. // returned key. From here on out things remain
  53. // unchanged.
  54. //
  55. if (ERROR_SUCCESS == RegOpenCurrentUser(samDesired, &hkeyRoot))
  56. {
  57. bCloseRootKey = true;
  58. }
  59. }
  60. dwResult = RegOpenKeyEx(hkeyRoot,
  61. m_szSubKey,
  62. 0,
  63. samDesired,
  64. &m_hkey);
  65. if ((ERROR_FILE_NOT_FOUND == dwResult) && bCreate)
  66. {
  67. DWORD dwDisposition;
  68. dwResult = RegCreateKeyEx(hkeyRoot,
  69. m_szSubKey,
  70. 0,
  71. NULL,
  72. 0,
  73. samDesired,
  74. NULL,
  75. &m_hkey,
  76. &dwDisposition);
  77. }
  78. if (bCloseRootKey)
  79. {
  80. RegCloseKey(hkeyRoot);
  81. }
  82. return HRESULT_FROM_WIN32(dwResult);
  83. }
  84. void
  85. RegKey::Attach(
  86. HKEY hkey
  87. )
  88. {
  89. Close();
  90. m_szSubKey[0] = TEXT('\0');
  91. m_hkeyRoot = NULL;
  92. m_hkey = hkey;
  93. }
  94. void
  95. RegKey::Detach(
  96. void
  97. )
  98. {
  99. m_hkey = NULL;
  100. }
  101. void
  102. RegKey::Close(
  103. void
  104. ) const
  105. {
  106. if (NULL != m_hkey)
  107. {
  108. //
  109. // Do this little swap so that the m_hkey member is NULL
  110. // when the actual key is being closed. This lets the async
  111. // change proc determine if it was signaled because of a true
  112. // change or because the key was being closed.
  113. //
  114. HKEY hkeyTemp = m_hkey;
  115. m_hkey = NULL;
  116. RegCloseKey(hkeyTemp);
  117. }
  118. }
  119. //
  120. // Determine if a particular registry value exists.
  121. //
  122. HRESULT
  123. RegKey::ValueExists(
  124. LPCTSTR pszValueName
  125. ) const
  126. {
  127. DWORD dwResult = ERROR_SUCCESS;
  128. int iValue = 0;
  129. TCHAR szValue[MAX_PATH];
  130. DWORD cchValue;
  131. while(ERROR_SUCCESS == dwResult)
  132. {
  133. cchValue = ARRAYSIZE(szValue);
  134. dwResult = RegEnumValue(m_hkey,
  135. iValue++,
  136. szValue,
  137. &cchValue,
  138. NULL,
  139. NULL,
  140. NULL,
  141. NULL);
  142. if (ERROR_SUCCESS == dwResult && (0 == lstrcmpi(pszValueName, szValue)))
  143. {
  144. return S_OK;
  145. }
  146. }
  147. if (ERROR_NO_MORE_ITEMS == dwResult)
  148. {
  149. return S_FALSE;
  150. }
  151. return HRESULT_FROM_WIN32(dwResult);
  152. }
  153. //
  154. // This is the basic form of GetValue. All other forms of
  155. // GetValue() call into this one.
  156. //
  157. HRESULT
  158. RegKey::GetValue(
  159. LPCTSTR pszValueName,
  160. DWORD dwTypeExpected,
  161. LPBYTE pbData,
  162. int cbData
  163. ) const
  164. {
  165. DWORD dwType;
  166. DWORD dwResult = RegQueryValueEx(m_hkey,
  167. pszValueName,
  168. 0,
  169. &dwType,
  170. pbData,
  171. (LPDWORD)&cbData);
  172. if (ERROR_SUCCESS == dwResult && dwType != dwTypeExpected)
  173. dwResult = ERROR_INVALID_DATATYPE;
  174. return HRESULT_FROM_WIN32(dwResult);
  175. }
  176. //
  177. // Get a DWORD value (REG_DWORD).
  178. //
  179. HRESULT
  180. RegKey::GetValue(
  181. LPCTSTR pszValueName,
  182. DWORD *pdwDataOut
  183. ) const
  184. {
  185. return GetValue(pszValueName, REG_DWORD, (LPBYTE)pdwDataOut, sizeof(DWORD));
  186. }
  187. //
  188. // Get a byte buffer value (REG_BINARY).
  189. //
  190. HRESULT
  191. RegKey::GetValue(
  192. LPCTSTR pszValueName,
  193. LPBYTE pbDataOut,
  194. int cbDataOut
  195. ) const
  196. {
  197. return GetValue(pszValueName, REG_BINARY, pbDataOut, cbDataOut);
  198. }
  199. //
  200. // Get a text string value (REG_SZ).
  201. //
  202. HRESULT
  203. RegKey::GetValue(
  204. LPCTSTR pszValueName,
  205. LPTSTR pszDataOut,
  206. UINT cchDataOut
  207. ) const
  208. {
  209. return GetValue(pszValueName,
  210. REG_SZ,
  211. (LPBYTE)pszDataOut,
  212. cchDataOut * sizeof(*pszDataOut));
  213. }
  214. //
  215. // Get a multi-text string value (REG_MULTI_SZ).
  216. //
  217. HRESULT
  218. RegKey::GetValue(
  219. LPCTSTR pszValueName,
  220. HDPA hdpaStringsOut
  221. ) const
  222. {
  223. HRESULT hr = E_FAIL;
  224. int cb = GetValueBufferSize(pszValueName);
  225. if (NULL != hdpaStringsOut && 0 < cb)
  226. {
  227. LPTSTR psz = (LPTSTR)LocalAlloc(LPTR, cb);
  228. if (NULL != psz)
  229. {
  230. hr = GetValue(pszValueName, REG_MULTI_SZ, (LPBYTE)psz, cb);
  231. if (SUCCEEDED(hr))
  232. {
  233. while(psz && TEXT('\0') != *psz && SUCCEEDED(hr))
  234. {
  235. LPTSTR pszCopy = StrDup(psz);
  236. if (NULL != pszCopy)
  237. {
  238. if (-1 == DPA_AppendPtr(hdpaStringsOut, pszCopy))
  239. {
  240. LocalFree(pszCopy);
  241. hr = E_OUTOFMEMORY;
  242. }
  243. }
  244. psz += lstrlen(psz) + 1;
  245. }
  246. }
  247. if (FAILED(hr))
  248. {
  249. //
  250. // Something failed. Clean up the DPA.
  251. //
  252. const int cStrings = DPA_GetPtrCount(hdpaStringsOut);
  253. for (int i = 0; i < cStrings; i++)
  254. {
  255. LPTSTR pszDel = (LPTSTR)DPA_GetPtr(hdpaStringsOut, i);
  256. if (NULL != pszDel)
  257. {
  258. LocalFree(pszDel);
  259. }
  260. DPA_DeletePtr(hdpaStringsOut, i);
  261. }
  262. }
  263. LocalFree(psz);
  264. }
  265. }
  266. return hr;
  267. }
  268. //
  269. // Return the required buffer size for a given registry value.
  270. //
  271. int
  272. RegKey::GetValueBufferSize(
  273. LPCTSTR pszValueName
  274. ) const
  275. {
  276. DWORD dwType;
  277. int cbData = 0;
  278. DWORD dwDummy;
  279. DWORD dwResult = RegQueryValueEx(m_hkey,
  280. pszValueName,
  281. 0,
  282. &dwType,
  283. (LPBYTE)&dwDummy,
  284. (LPDWORD)&cbData);
  285. if (ERROR_MORE_DATA != dwResult)
  286. cbData = 0;
  287. return cbData;
  288. }
  289. //
  290. // This is the basic form of SetValue. All other forms of
  291. // SetValue() call into this one.
  292. //
  293. HRESULT
  294. RegKey::SetValue(
  295. LPCTSTR pszValueName,
  296. DWORD dwValueType,
  297. const LPBYTE pbData,
  298. int cbData
  299. )
  300. {
  301. DWORD dwResult = RegSetValueEx(m_hkey,
  302. pszValueName,
  303. 0,
  304. dwValueType,
  305. pbData,
  306. cbData);
  307. return HRESULT_FROM_WIN32(dwResult);
  308. }
  309. //
  310. // Set a DWORD value (REG_DWORD).
  311. //
  312. HRESULT
  313. RegKey::SetValue(
  314. LPCTSTR pszValueName,
  315. DWORD dwData
  316. )
  317. {
  318. return SetValue(pszValueName, REG_DWORD, (const LPBYTE)&dwData, sizeof(dwData));
  319. }
  320. //
  321. // Set a byte buffer value (REG_BINARY).
  322. //
  323. HRESULT
  324. RegKey::SetValue(
  325. LPCTSTR pszValueName,
  326. const LPBYTE pbData,
  327. int cbData
  328. )
  329. {
  330. return SetValue(pszValueName, REG_BINARY, pbData, cbData);
  331. }
  332. //
  333. // Set a text string value (REG_SZ).
  334. //
  335. HRESULT
  336. RegKey::SetValue(
  337. LPCTSTR pszValueName,
  338. LPCTSTR pszData
  339. )
  340. {
  341. return SetValue(pszValueName, REG_SZ, (const LPBYTE)pszData, (lstrlen(pszData) + 1) * sizeof(TCHAR));
  342. }
  343. //
  344. // Set a text string value (REG_MULTI_SZ).
  345. //
  346. HRESULT
  347. RegKey::SetValue(
  348. LPCTSTR pszValueName,
  349. HDPA hdpaStrings
  350. )
  351. {
  352. HRESULT hr = E_OUTOFMEMORY;
  353. LPTSTR pszDblNul = CreateDoubleNulTermList(hdpaStrings);
  354. if (NULL != pszDblNul)
  355. {
  356. int cch = 1;
  357. LPTSTR psz = pszDblNul;
  358. while(*psz)
  359. {
  360. while(*psz++)
  361. cch++;
  362. psz++;
  363. }
  364. hr = SetValue(pszValueName, REG_MULTI_SZ, (const LPBYTE)pszDblNul, cch * sizeof(TCHAR));
  365. LocalFree(pszDblNul);
  366. }
  367. return hr;
  368. }
  369. LPTSTR
  370. RegKey::CreateDoubleNulTermList(
  371. HDPA hdpaStrings
  372. ) const
  373. {
  374. LPTSTR pszBuf = NULL;
  375. if (NULL != hdpaStrings)
  376. {
  377. const int cEntries = DPA_GetPtrCount(hdpaStrings);
  378. int cch = 1; // Account for 2nd nul term.
  379. int i;
  380. for (i = 0; i < cEntries; i++)
  381. {
  382. LPTSTR psz = (LPTSTR)DPA_GetPtr(hdpaStrings, i);
  383. if (NULL != psz)
  384. {
  385. cch += lstrlen(psz) + 1;
  386. }
  387. }
  388. pszBuf = (LPTSTR)LocalAlloc(LPTR, cch * sizeof(*pszBuf));
  389. if (NULL != pszBuf)
  390. {
  391. LPTSTR pszWrite = pszBuf;
  392. for (i = 0; i < cEntries; i++)
  393. {
  394. LPTSTR psz = (LPTSTR)DPA_GetPtr(hdpaStrings, i);
  395. if (NULL != psz)
  396. {
  397. lstrcpy(pszWrite, psz);
  398. pszWrite += lstrlen(psz) + 1;
  399. }
  400. }
  401. *pszWrite = TEXT('\0'); // Double nul term.
  402. }
  403. }
  404. return pszBuf;
  405. }
  406. HRESULT
  407. RegKey::DeleteAllValues(
  408. int *pcNotDeleted
  409. )
  410. {
  411. HRESULT hr;
  412. KEYINFO ki;
  413. if (NULL != pcNotDeleted)
  414. *pcNotDeleted = 0;
  415. hr = QueryInfo(&ki, QIM_VALUENAMEMAXCHARCNT);
  416. if (FAILED(hr))
  417. return hr;
  418. TCHAR szName[MAX_PATH];
  419. DWORD cchValueName;
  420. DWORD dwError = ERROR_SUCCESS;
  421. int cNotDeleted = 0;
  422. int iValue = 0;
  423. while(ERROR_SUCCESS == dwError)
  424. {
  425. cchValueName = ARRAYSIZE(szName);
  426. dwError = RegEnumValue(m_hkey,
  427. iValue,
  428. szName,
  429. &cchValueName,
  430. NULL,
  431. NULL,
  432. NULL,
  433. NULL);
  434. if (ERROR_SUCCESS == dwError)
  435. {
  436. if (FAILED(hr = DeleteValue(szName)))
  437. {
  438. cNotDeleted++;
  439. iValue++; // Skip to next value to avoid infinite loop.
  440. Trace((TEXT("Error %d deleting reg value \"%s\""),
  441. HRESULT_CODE(hr), szName));
  442. }
  443. }
  444. }
  445. if (ERROR_NO_MORE_ITEMS == dwError)
  446. dwError = ERROR_SUCCESS;
  447. if (pcNotDeleted)
  448. *pcNotDeleted = cNotDeleted;
  449. return HRESULT_FROM_WIN32(dwError);
  450. }
  451. HRESULT
  452. RegKey::DeleteValue(
  453. LPCTSTR pszValue
  454. )
  455. {
  456. LONG lRet = RegDeleteValue(m_hkey, pszValue);
  457. return HRESULT_FROM_WIN32(lRet);
  458. }
  459. HRESULT
  460. RegKey::QueryInfo(
  461. RegKey::KEYINFO *pInfo,
  462. DWORD fMask
  463. ) const
  464. {
  465. LONG lResult = RegQueryInfoKey(m_hkey,
  466. NULL,
  467. NULL,
  468. NULL,
  469. (QIM_SUBKEYCNT & fMask) ? &pInfo->cSubKeys : NULL,
  470. (QIM_SUBKEYMAXCHARCNT & fMask) ? &pInfo->cchSubKeyMax : NULL,
  471. (QIM_CLASSMAXCHARCNT & fMask) ? &pInfo->cchClassMax : NULL,
  472. (QIM_VALUECNT & fMask) ? &pInfo->cValues : NULL,
  473. (QIM_VALUENAMEMAXCHARCNT & fMask) ? &pInfo->cchValueNameMax : NULL,
  474. (QIM_VALUEMAXBYTECNT & fMask) ? &pInfo->cbValueMax : NULL,
  475. (QIM_SECURITYBYTECNT & fMask) ? &pInfo->cbSecurityDesc : NULL,
  476. (QIM_LASTWRITETIME & fMask) ? &pInfo->LastWriteTime : NULL);
  477. return HRESULT_FROM_WIN32(lResult);
  478. }
  479. RegKey::ValueIterator::ValueIterator(
  480. RegKey& key
  481. ) : m_key(key),
  482. m_iValue(0),
  483. m_cchValueName(0)
  484. {
  485. KEYINFO ki;
  486. if (SUCCEEDED(key.QueryInfo(&ki, QIM_VALUENAMEMAXCHARCNT)))
  487. {
  488. m_cchValueName = ki.cchValueNameMax + 1;
  489. }
  490. }
  491. //
  492. // Returns: S_OK = More items.
  493. // S_FALSE = No more items.
  494. HRESULT
  495. RegKey::ValueIterator::Next(
  496. LPTSTR pszNameOut,
  497. UINT cchNameOut,
  498. LPDWORD pdwType,
  499. LPBYTE pbData,
  500. LPDWORD pcbData
  501. )
  502. {
  503. HRESULT hr = S_OK;
  504. DWORD cchName = cchNameOut;
  505. LONG lResult = RegEnumValue(m_key,
  506. m_iValue,
  507. pszNameOut,
  508. &cchName,
  509. NULL,
  510. pdwType,
  511. pbData,
  512. pcbData);
  513. switch(lResult)
  514. {
  515. case ERROR_SUCCESS:
  516. m_iValue++;
  517. break;
  518. case ERROR_NO_MORE_ITEMS:
  519. hr = S_FALSE;
  520. break;
  521. default:
  522. Trace((TEXT("Error %d enumerating reg value \"%s\""),
  523. lResult, m_key.SubKeyName()));
  524. hr = HRESULT_FROM_WIN32(lResult);
  525. break;
  526. }
  527. return hr;
  528. };
  529. RegKeyCU::RegKeyCU(
  530. REGSAM samDesired
  531. ) : m_hkey(NULL)
  532. {
  533. RegOpenCurrentUser(samDesired, &m_hkey);
  534. }
  535. RegKeyCU::~RegKeyCU(
  536. void
  537. )
  538. {
  539. if (NULL != m_hkey)
  540. RegCloseKey(m_hkey);
  541. }
  542. //
  543. // Version of RegEnumValue that expands environment variables
  544. // in all string values.
  545. //
  546. LONG
  547. _RegEnumValueExp(
  548. HKEY hKey,
  549. DWORD dwIndex,
  550. LPTSTR lpValueName,
  551. LPDWORD lpcbValueName,
  552. LPDWORD lpReserved,
  553. LPDWORD lpType,
  554. LPBYTE lpData,
  555. LPDWORD lpcbData
  556. )
  557. {
  558. DWORD cchNameDest = lpcbValueName ? *lpcbValueName / sizeof(TCHAR) : 0;
  559. DWORD cchDataDest = lpcbData ? *lpcbData / sizeof(TCHAR) : 0;
  560. DWORD dwType;
  561. if (NULL == lpType)
  562. lpType = &dwType;
  563. LONG lResult = RegEnumValue(hKey,
  564. dwIndex,
  565. lpValueName,
  566. lpcbValueName,
  567. lpReserved,
  568. lpType,
  569. lpData,
  570. lpcbData);
  571. if (ERROR_SUCCESS == lResult)
  572. {
  573. HRESULT hr = ExpandStringInPlace(lpValueName, cchNameDest);
  574. if ((NULL != lpData) && (REG_SZ == *lpType || REG_EXPAND_SZ == *lpType))
  575. {
  576. hr = ExpandStringInPlace((LPTSTR)lpData, cchDataDest);
  577. }
  578. lResult = HRESULT_CODE(hr);
  579. }
  580. return lResult;
  581. }