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.

3438 lines
108 KiB

  1. #include "priv.h"
  2. #include <regapix.h>
  3. #ifdef _X86_
  4. #include <w95wraps.h>
  5. #endif
  6. // These private helper functions below call ANSI versions of the
  7. // registry functions so they will run on Win95.
  8. STDAPI_(DWORD)
  9. RegData_AtoW(
  10. IN LPCVOID pvData,
  11. IN DWORD dwSize,
  12. IN DWORD dwType,
  13. /*INOUT*/ LPDWORD pcbData
  14. )
  15. {
  16. DWORD dwRet = NO_ERROR;
  17. if (REG_SZ == dwType || REG_EXPAND_SZ == dwType || REG_MULTI_SZ == dwType)
  18. {
  19. DWORD cbData = pcbData ? *pcbData : -1;
  20. if (pvData)
  21. {
  22. // Allocate a temporary buffer to work with
  23. int cch = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pvData, cbData, NULL, 0);
  24. LPWSTR pwszT = (LPWSTR)LocalAlloc(LPTR, CbFromCchW(cch));
  25. if (!pwszT)
  26. dwRet = ERROR_NOT_ENOUGH_MEMORY;
  27. else
  28. {
  29. if (CbFromCchW(cch) > dwSize)
  30. dwRet = ERROR_MORE_DATA;
  31. else
  32. {
  33. // Convert it to the temporary buffer
  34. MultiByteToWideChar(CP_ACP, 0, (LPSTR)pvData, cbData, pwszT, cch);
  35. // Copy it back to the output buffer
  36. // pwszT can be REG_MULTI_SZ, so we can't use StrCpyW
  37. memcpy((LPVOID)pvData, (LPVOID)pwszT, CbFromCchW(cch));
  38. }
  39. LocalFree(pwszT);
  40. }
  41. // If string data, make room for unicode
  42. if (pcbData)
  43. {
  44. (*pcbData) = cch * sizeof(WCHAR);
  45. }
  46. }
  47. else if (pcbData)
  48. {
  49. // We don't have the data so guess (actual value may be less)
  50. // Does this need to be exact? For now this seem sufficient. (Stevepro)
  51. (*pcbData) *= sizeof(WCHAR);
  52. }
  53. }
  54. return dwRet;
  55. }
  56. /*----------------------------------------------------------
  57. Purpose: Helper function to delete a key that has no subkeys and
  58. no values. Otherwise does nothing. Mimics what RegDeleteKey
  59. does on NT.
  60. Returns:
  61. Cond: --
  62. */
  63. DWORD
  64. DeleteEmptyKey(
  65. IN HKEY hkey,
  66. IN LPCSTR pszSubKey)
  67. {
  68. DWORD dwRet;
  69. HKEY hkeyNew;
  70. dwRet = RegOpenKeyExA(hkey, pszSubKey, 0, KEY_READ | KEY_SET_VALUE,
  71. &hkeyNew);
  72. if (NO_ERROR == dwRet)
  73. {
  74. DWORD ckeys;
  75. DWORD cvalues;
  76. // Are there any subkeys or values?
  77. dwRet = RegQueryInfoKey(hkeyNew, NULL, NULL, NULL, &ckeys,
  78. NULL, NULL, &cvalues, NULL, NULL,
  79. NULL, NULL);
  80. if (NO_ERROR == dwRet &&
  81. 0 == cvalues && 0 == ckeys)
  82. {
  83. // No; delete the subkey
  84. dwRet = RegDeleteKeyA(hkey, pszSubKey);
  85. }
  86. else
  87. {
  88. dwRet = ERROR_DIR_NOT_EMPTY;
  89. }
  90. RegCloseKey(hkeyNew);
  91. }
  92. return dwRet;
  93. }
  94. /*----------------------------------------------------------
  95. Purpose: Recursively delete the key, including all child values
  96. and keys. Mimics what RegDeleteKey does in Win95.
  97. Returns:
  98. Cond: --
  99. */
  100. DWORD
  101. DeleteKeyRecursively(
  102. IN HKEY hkey,
  103. IN LPCSTR pszSubKey)
  104. {
  105. DWORD dwRet;
  106. HKEY hkSubKey;
  107. // Open the subkey so we can enumerate any children
  108. dwRet = RegOpenKeyExA(hkey, pszSubKey, 0, MAXIMUM_ALLOWED, &hkSubKey);
  109. if (ERROR_SUCCESS == dwRet)
  110. {
  111. DWORD dwIndex;
  112. CHAR szSubKeyName[MAX_PATH + 1];
  113. DWORD cchSubKeyName = ARRAYSIZE(szSubKeyName);
  114. // I can't just call RegEnumKey with an ever-increasing index, because
  115. // I'm deleting the subkeys as I go, which alters the indices of the
  116. // remaining subkeys in an implementation-dependent way. In order to
  117. // be safe, I have to count backwards while deleting the subkeys.
  118. // Find out how many subkeys there are
  119. dwRet = RegQueryInfoKeyA(hkSubKey, NULL, NULL, NULL,
  120. &dwIndex, // The # of subkeys -- all we need
  121. NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  122. if (NO_ERROR == dwRet)
  123. {
  124. // dwIndex is now the count of subkeys, but it needs to be
  125. // zero-based for RegEnumKey, so I'll pre-decrement, rather
  126. // than post-decrement.
  127. while (ERROR_SUCCESS == RegEnumKeyA(hkSubKey, --dwIndex, szSubKeyName, cchSubKeyName))
  128. {
  129. DeleteKeyRecursively(hkSubKey, szSubKeyName);
  130. }
  131. }
  132. RegCloseKey(hkSubKey);
  133. if (pszSubKey)
  134. {
  135. dwRet = RegDeleteKeyA(hkey, pszSubKey);
  136. }
  137. else
  138. {
  139. // we want to delete all the values by hand
  140. cchSubKeyName = ARRAYSIZE(szSubKeyName);
  141. while (ERROR_SUCCESS == RegEnumValueA(hkey, 0, szSubKeyName, &cchSubKeyName, NULL, NULL, NULL, NULL))
  142. {
  143. // avoid looping infinitely when we cant delete the value
  144. if (RegDeleteValueA(hkey, szSubKeyName))
  145. break;
  146. cchSubKeyName = ARRAYSIZE(szSubKeyName);
  147. }
  148. }
  149. }
  150. return dwRet;
  151. }
  152. /*----------------------------------------------------------
  153. Purpose: Gets a registry value. This opens and closes the
  154. key in which the value resides.
  155. Perf: if your code involves setting/getting a series
  156. of values in the same key, it is better to open
  157. the key once and set/get the values with the regular
  158. Win32 registry functions, rather than using this
  159. function repeatedly.
  160. Returns:
  161. Cond: --
  162. */
  163. STDAPI_(DWORD)
  164. SHGetValueA(
  165. IN HKEY hkey,
  166. IN LPCSTR pszSubKey, OPTIONAL
  167. IN LPCSTR pszValue, OPTIONAL
  168. OUT LPDWORD pdwType, OPTIONAL
  169. OUT LPVOID pvData, OPTIONAL
  170. OUT LPDWORD pcbData) OPTIONAL
  171. {
  172. DWORD dwRet = ERROR_INVALID_PARAMETER;
  173. HKEY hkClose = NULL;
  174. if (pvData)
  175. {
  176. RIPMSG(pcbData != NULL, "SHGetValueA: caller passed pvData output buffer but not size of buffer (pcbData)!");
  177. }
  178. if (pszSubKey && *pszSubKey)
  179. {
  180. dwRet = RegOpenKeyExA(hkey, pszSubKey, 0, KEY_QUERY_VALUE, &hkClose);
  181. hkey = hkClose;
  182. ASSERT(NO_ERROR == dwRet || !hkey);
  183. }
  184. if (hkey)
  185. {
  186. dwRet = SHQueryValueExA(hkey, pszValue, NULL, pdwType, pvData,
  187. pcbData);
  188. if (hkClose)
  189. RegCloseKey(hkClose);
  190. }
  191. else if (pcbData)
  192. *pcbData = 0;
  193. return dwRet;
  194. }
  195. /*----------------------------------------------------------
  196. Purpose: Gets a registry value. This opens and closes the
  197. key in which the value resides.
  198. On Win95, this function thunks and calls the ansi
  199. version. On NT, this function calls the unicode
  200. registry APIs.
  201. Perf: if your code involves setting/getting a series
  202. of values in the same key, it is better to open
  203. the key once and set/get the values with the regular
  204. Win32 registry functions, rather than using this
  205. function repeatedly.
  206. Returns:
  207. Cond: --
  208. */
  209. STDAPI_(DWORD)
  210. SHGetValueW(
  211. IN HKEY hkey,
  212. IN LPCWSTR pwszSubKey, OPTIONAL
  213. IN LPCWSTR pwszValue, OPTIONAL
  214. OUT LPDWORD pdwType, OPTIONAL
  215. OUT LPVOID pvData, OPTIONAL
  216. OUT LPDWORD pcbData) OPTIONAL
  217. {
  218. DWORD dwRet = ERROR_INVALID_PARAMETER;
  219. if (pvData)
  220. {
  221. RIPMSG(pcbData != NULL, "SHGetValueW: caller passed pvData output buffer but not size of buffer (pcbData)!");
  222. }
  223. if (g_bRunningOnNT)
  224. {
  225. HKEY hkClose = NULL;
  226. if (pwszSubKey && *pwszSubKey)
  227. {
  228. dwRet = RegOpenKeyExW(hkey, pwszSubKey, 0, KEY_QUERY_VALUE, &hkClose);
  229. hkey = hkClose;
  230. ASSERT(NO_ERROR == dwRet || !hkey);
  231. }
  232. if (hkey)
  233. {
  234. dwRet = SHQueryValueExW(hkey, pwszValue, NULL, pdwType, pvData,
  235. pcbData);
  236. if (hkClose)
  237. RegCloseKey(hkClose);
  238. }
  239. else if (pcbData)
  240. *pcbData = 0;
  241. }
  242. else
  243. {
  244. CHAR szSubKey[MAX_PATH];
  245. CHAR szValue[MAX_PATH];
  246. LPSTR pszSubKey = NULL;
  247. LPSTR pszValue = NULL;
  248. DWORD dwType;
  249. DWORD cbSizeSav = 0;
  250. // Thunk the values
  251. if (pwszSubKey)
  252. {
  253. WideCharToMultiByte(CP_ACP, 0, pwszSubKey, -1, szSubKey, SIZECHARS(szSubKey), NULL, NULL);
  254. pszSubKey = szSubKey;
  255. }
  256. if (pwszValue)
  257. {
  258. WideCharToMultiByte(CP_ACP, 0, pwszValue, -1, szValue, SIZECHARS(szValue), NULL, NULL);
  259. pszValue = szValue;
  260. }
  261. if (pcbData)
  262. cbSizeSav = *pcbData; // Save this size for later
  263. dwRet = SHGetValueA(hkey, pszSubKey, pszValue, &dwType, pvData, pcbData);
  264. if (pdwType)
  265. *pdwType = dwType;
  266. if (NO_ERROR == dwRet)
  267. {
  268. dwRet = RegData_AtoW(pvData, cbSizeSav, dwType, pcbData); // Thunk data from ANSI->UNICODE if needed.
  269. }
  270. }
  271. return dwRet;
  272. }
  273. /*----------------------------------------------------------
  274. Purpose: Sets a registry value. This opens and closes the
  275. key in which the value resides.
  276. Perf: if your code involves setting/getting a series
  277. of values in the same key, it is better to open
  278. the key once and set/get the values with the regular
  279. Win32 registry functions, rather than using this
  280. function repeatedly.
  281. Returns:
  282. Cond: --
  283. */
  284. STDAPI_(DWORD)
  285. SHSetValueA(
  286. IN HKEY hkey,
  287. IN OPTIONAL LPCSTR pszSubKey,
  288. IN LPCSTR pszValue,
  289. IN DWORD dwType,
  290. IN LPCVOID pvData,
  291. IN DWORD cbData)
  292. {
  293. DWORD dwRet = NO_ERROR;
  294. HKEY hkeyNew;
  295. DWORD dwDisp;
  296. if (pszSubKey && pszSubKey[0])
  297. dwRet = RegCreateKeyExA(hkey, pszSubKey, 0, "", 0, KEY_SET_VALUE, NULL, &hkeyNew, &dwDisp);
  298. else
  299. hkeyNew = hkey;
  300. if (NO_ERROR == dwRet)
  301. {
  302. dwRet = RegSetValueExA(hkeyNew, pszValue, 0, dwType, pvData, cbData);
  303. if (hkeyNew != hkey)
  304. RegCloseKey(hkeyNew);
  305. }
  306. return dwRet;
  307. }
  308. /*----------------------------------------------------------
  309. Purpose: Sets a registry value. This opens and closes the
  310. key in which the value resides.
  311. On Win95, this function thunks and calls the ansi
  312. version. On NT, this function calls the unicode
  313. registry APIs directly.
  314. Perf: if your code involves setting/getting a series
  315. of values in the same key, it is better to open
  316. the key once and set/get the values with the regular
  317. Win32 registry functions, rather than using this
  318. function repeatedly.
  319. Returns:
  320. Cond: --
  321. */
  322. STDAPI_(DWORD)
  323. SHSetValueW(
  324. IN HKEY hkey,
  325. IN OPTIONAL LPCWSTR pwszSubKey,
  326. IN LPCWSTR pwszValue,
  327. IN DWORD dwType,
  328. IN LPCVOID pvData,
  329. IN DWORD cbData)
  330. {
  331. DWORD dwRet = NO_ERROR;
  332. HKEY hkeyNew;
  333. DWORD dwDisp;
  334. if (pwszSubKey && pwszSubKey[0])
  335. {
  336. if (g_bRunningOnNT)
  337. {
  338. dwRet = RegCreateKeyExW(hkey, pwszSubKey, 0, TEXTW(""), 0, KEY_SET_VALUE,
  339. NULL, &hkeyNew, &dwDisp);
  340. }
  341. else
  342. {
  343. CHAR szSubKey[MAX_PATH];
  344. LPSTR pszSubKey = NULL;
  345. if (pwszSubKey)
  346. {
  347. WideCharToMultiByte(CP_ACP, 0, pwszSubKey, -1, szSubKey, SIZECHARS(szSubKey), NULL, NULL);
  348. pszSubKey = szSubKey;
  349. }
  350. dwRet = RegCreateKeyExA(hkey, pszSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_SET_VALUE,
  351. NULL, &hkeyNew, &dwDisp);
  352. }
  353. }
  354. else
  355. hkeyNew = hkey;
  356. if (NO_ERROR == dwRet)
  357. {
  358. // RegSetValueExW is not supported on Win95 but we have a thunking function.
  359. dwRet = RegSetValueExW(hkeyNew, pwszValue, 0, dwType, pvData, cbData);
  360. if (hkeyNew != hkey)
  361. RegCloseKey(hkeyNew);
  362. }
  363. return dwRet;
  364. }
  365. /*----------------------------------------------------------
  366. Purpose: Deletes a registry value. This opens and closes the
  367. key in which the value resides.
  368. Perf: if your code involves setting/getting a series
  369. of values in the same key, it is better to open
  370. the key once and set/get the values with the regular
  371. Win32 registry functions, rather than using this
  372. function repeatedly.
  373. Returns:
  374. Cond: --
  375. */
  376. STDAPI_(DWORD)
  377. SHDeleteValueA(
  378. IN HKEY hkey,
  379. IN LPCSTR pszSubKey,
  380. IN LPCSTR pszValue)
  381. {
  382. DWORD dwRet;
  383. HKEY hkeyNew;
  384. dwRet = RegOpenKeyExA(hkey, pszSubKey, 0, KEY_SET_VALUE, &hkeyNew);
  385. if (NO_ERROR == dwRet)
  386. {
  387. dwRet = RegDeleteValueA(hkeyNew, pszValue);
  388. RegCloseKey(hkeyNew);
  389. }
  390. return dwRet;
  391. }
  392. /*----------------------------------------------------------
  393. Purpose: Deletes a registry value. This opens and closes the
  394. key in which the value resides.
  395. On Win95, this function thunks and calls the ansi
  396. version. On NT, this function calls the unicode
  397. registry APIs directly.
  398. Perf: if your code involves setting/getting a series
  399. of values in the same key, it is better to open
  400. the key once and set/get the values with the regular
  401. Win32 registry functions, rather than using this
  402. function repeatedly.
  403. Returns:
  404. Cond: --
  405. */
  406. STDAPI_(DWORD)
  407. SHDeleteValueW(
  408. IN HKEY hkey,
  409. IN LPCWSTR pwszSubKey,
  410. IN LPCWSTR pwszValue)
  411. {
  412. DWORD dwRet;
  413. HKEY hkeyNew;
  414. if (g_bRunningOnNT)
  415. {
  416. dwRet = RegOpenKeyExW(hkey, pwszSubKey, 0, KEY_SET_VALUE, &hkeyNew);
  417. if (NO_ERROR == dwRet)
  418. {
  419. dwRet = RegDeleteValueW(hkeyNew, pwszValue);
  420. RegCloseKey(hkeyNew);
  421. }
  422. }
  423. else
  424. {
  425. CHAR szSubKey[MAX_PATH];
  426. CHAR szValue[MAX_PATH];
  427. LPSTR pszSubKey = NULL;
  428. LPSTR pszValue = NULL;
  429. if (pwszSubKey)
  430. {
  431. WideCharToMultiByte(CP_ACP, 0, pwszSubKey, -1, szSubKey, SIZECHARS(szSubKey), NULL, NULL);
  432. pszSubKey = szSubKey;
  433. }
  434. if (pwszValue)
  435. {
  436. WideCharToMultiByte(CP_ACP, 0, pwszValue, -1, szValue, SIZECHARS(szValue), NULL, NULL);
  437. pszValue = szValue;
  438. }
  439. dwRet = SHDeleteValueA(hkey, pszSubKey, pszValue);
  440. }
  441. return dwRet;
  442. }
  443. // purpose: recursively copy subkeys and values of hkeySrc\pszSrcSubKey to hkeyDest
  444. // e.g. hkeyExplorer = HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\
  445. // SHCopyKey(HKEY_CURRENT_USER, "Software\\Classes\\", hkeyExplorer, 0)
  446. // results in
  447. // ...\\CurrentVersion\\Explorer\\
  448. // Appid
  449. // CLSID\\
  450. // {xxxx yyyyy ...}
  451. // Interface
  452. // ...
  453. // TO DO: currently we are not copying the ACL's but in the future we should do that
  454. // upon request that's what fReserved is for
  455. // NOTE that there is no hkeyDest, pszDestSubKey pair like src one, because in case
  456. // pszDestSubKey did not exist we would have to create it and deal with Class name
  457. // which would just clober the parameter list
  458. STDAPI_(DWORD) SHCopyKeyA(HKEY hkeySrc, LPCSTR pszSrcSubKey, HKEY hkeyDest, DWORD fReserved)
  459. {
  460. HKEY hkeyFrom;
  461. DWORD dwRet;
  462. if (pszSrcSubKey)
  463. dwRet = RegOpenKeyExA(hkeySrc, pszSrcSubKey, 0, MAXIMUM_ALLOWED, &hkeyFrom);
  464. else if (hkeySrc)
  465. {
  466. dwRet = ERROR_SUCCESS;
  467. hkeyFrom = hkeySrc;
  468. }
  469. else
  470. dwRet = ERROR_INVALID_PARAMETER;
  471. if (dwRet == ERROR_SUCCESS)
  472. {
  473. DWORD dwIndex;
  474. DWORD cchValueSize;
  475. DWORD cchClassSize;
  476. DWORD dwType;
  477. CHAR szValue[MAX_PATH]; //NOTE:szValue is also used to store subkey name when enumerating keys
  478. CHAR szClass[MAX_PATH];
  479. cchValueSize = ARRAYSIZE(szValue);
  480. cchClassSize = ARRAYSIZE(szClass);
  481. for (dwIndex=0;
  482. dwRet == ERROR_SUCCESS && (dwRet = RegEnumKeyExA(hkeyFrom, dwIndex, szValue, &cchValueSize, NULL, szClass, &cchClassSize, NULL)) == ERROR_SUCCESS;
  483. dwIndex++, cchValueSize = ARRAYSIZE(szValue), cchClassSize = ARRAYSIZE(szClass))
  484. {
  485. HKEY hkeyTo;
  486. DWORD dwDisp;
  487. // create new key
  488. dwRet = RegCreateKeyExA(hkeyDest, szValue, 0, szClass, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &hkeyTo, &dwDisp);
  489. if (dwRet != ERROR_SUCCESS)
  490. break;
  491. dwRet = SHCopyKeyA(hkeyFrom, szValue, hkeyTo, fReserved); //if not error_success we break out
  492. RegCloseKey(hkeyTo);
  493. }
  494. // copied all the sub keys, now copy all the values
  495. if (dwRet == ERROR_NO_MORE_ITEMS)
  496. {
  497. DWORD cb, cbBufferSize;
  498. LPBYTE lpbyBuffer;
  499. // get the max value size
  500. dwRet = RegQueryInfoKey(hkeyFrom, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &cb, NULL, NULL);
  501. if (dwRet == ERROR_SUCCESS)
  502. {
  503. // allocate buffer
  504. cb++; // add 1 just in case of a string
  505. lpbyBuffer = (LPBYTE)LocalAlloc(LPTR, cb);
  506. if (lpbyBuffer)
  507. cbBufferSize = cb;
  508. else
  509. dwRet = ERROR_OUTOFMEMORY;
  510. cchValueSize = ARRAYSIZE(szValue);
  511. for (dwIndex=0;
  512. dwRet == ERROR_SUCCESS && (dwRet = RegEnumValueA(hkeyFrom, dwIndex, szValue, &cchValueSize, NULL, &dwType, lpbyBuffer, &cb)) == ERROR_SUCCESS;
  513. dwIndex++, cchValueSize = ARRAYSIZE(szValue), cb = cbBufferSize)
  514. {
  515. // cb has the size of the value so use it rather than cbBufferSize which is just max size
  516. dwRet = RegSetValueExA(hkeyDest, szValue, 0, dwType, lpbyBuffer, cb);
  517. if (dwRet != ERROR_SUCCESS)
  518. break;
  519. }
  520. if (lpbyBuffer != NULL)
  521. LocalFree(lpbyBuffer);
  522. }
  523. }
  524. if (dwRet == ERROR_NO_MORE_ITEMS)
  525. dwRet = ERROR_SUCCESS;
  526. if (pszSrcSubKey)
  527. RegCloseKey(hkeyFrom);
  528. }
  529. return dwRet;
  530. }
  531. STDAPI_(DWORD) SHCopyKeyW(HKEY hkeySrc, LPCWSTR pwszSrcSubKey, HKEY hkeyDest, DWORD fReserved)
  532. {
  533. CHAR sz[MAX_PATH];
  534. if (pwszSrcSubKey)
  535. WideCharToMultiByte(CP_ACP, 0, pwszSrcSubKey, -1, sz, SIZECHARS(sz), NULL, NULL);
  536. return SHCopyKeyA(hkeySrc, pwszSrcSubKey ? sz : NULL, hkeyDest, fReserved);
  537. }
  538. /*----------------------------------------------------------
  539. Purpose: Delete a key only if there are no subkeys or values.
  540. It comes close to mimicking the behavior of RegDeleteKey
  541. as it works on NT, except the NT version ignores values.
  542. */
  543. STDAPI_(DWORD)
  544. SHDeleteEmptyKeyA(
  545. IN HKEY hkey,
  546. IN LPCSTR pszSubKey)
  547. {
  548. return DeleteEmptyKey(hkey, pszSubKey);
  549. }
  550. /*----------------------------------------------------------
  551. Purpose: Delete a key only if there are no subkeys or values.
  552. It comes close to mimicking the behavior of RegDeleteKey
  553. as it works on NT, except the NT version ignores values.
  554. */
  555. STDAPI_(DWORD)
  556. SHDeleteEmptyKeyW(
  557. IN HKEY hkey,
  558. IN LPCWSTR pwszSubKey)
  559. {
  560. CHAR sz[MAX_PATH];
  561. WideCharToMultiByte(CP_ACP, 0, pwszSubKey, -1, sz, SIZECHARS(sz), NULL, NULL);
  562. return DeleteEmptyKey(hkey, sz);
  563. }
  564. /*----------------------------------------------------------
  565. Purpose: Recursively delete the key, including all child values
  566. and keys.
  567. Returns:
  568. Cond: --
  569. */
  570. STDAPI_(DWORD)
  571. SHDeleteKeyA(
  572. IN HKEY hkey,
  573. IN LPCSTR pszSubKey)
  574. {
  575. DWORD dwRet;
  576. if (g_bRunningOnNT || !pszSubKey)
  577. {
  578. dwRet = DeleteKeyRecursively(hkey, pszSubKey);
  579. }
  580. else
  581. {
  582. // On Win95, RegDeleteKey does what we want
  583. dwRet = RegDeleteKeyA(hkey, pszSubKey);
  584. }
  585. return dwRet;
  586. }
  587. /*----------------------------------------------------------
  588. Purpose: Recursively delete the key, including all child values
  589. and keys.
  590. Returns:
  591. Cond: --
  592. */
  593. STDAPI_(DWORD)
  594. SHDeleteKeyW(
  595. IN HKEY hkey,
  596. IN LPCWSTR pwszSubKey)
  597. {
  598. DWORD dwRet;
  599. CHAR sz[MAX_PATH];
  600. WideCharToMultiByte(CP_ACP, 0, pwszSubKey, -1, sz, SIZECHARS(sz), NULL, NULL);
  601. if (g_bRunningOnNT)
  602. {
  603. dwRet = DeleteKeyRecursively(hkey, sz);
  604. }
  605. else
  606. {
  607. // On Win95, RegDeleteKey does what we want
  608. dwRet = RegDeleteKeyA(hkey, sz);
  609. }
  610. return dwRet;
  611. }
  612. STDAPI_(DWORD) FixupRegStringA(HKEY hk, PCSTR pszValue, BOOL fExpand, DWORD err, void *pvData, DWORD *pcbData, DWORD *pcbSize);
  613. STDAPI_(DWORD) FixupRegStringW(HKEY hk, PCWSTR pszValue, BOOL fExpand, DWORD err, void *pvData, DWORD *pcbData, DWORD *pcbSize);
  614. /*----------------------------------------------------------
  615. Purpose: Behaves just like RegQueryValueEx, except if the
  616. data type is REG_EXPAND_SZ, then this goes ahead
  617. and expands out the string. *pdwType will always
  618. be massaged to REG_SZ if this happens.
  619. Returns:
  620. Cond: --
  621. */
  622. STDAPI_(DWORD)
  623. SHQueryValueExA(
  624. IN HKEY hkey,
  625. IN LPCSTR pszValue,
  626. IN LPDWORD lpReserved,
  627. OUT LPDWORD pdwType,
  628. OUT LPVOID pvData,
  629. IN OUT LPDWORD pcbData)
  630. {
  631. DWORD dwRet;
  632. DWORD cbSize = 0;
  633. DWORD dwType = REG_NONE;
  634. DWORD cbOriginal = 0;
  635. if (pvData)
  636. {
  637. RIPMSG(pcbData != NULL, "SHQueryValuegExW: caller passed pvData output buffer but not size of buffer (pcbData)!");
  638. }
  639. // Trying to get back data
  640. if (pcbData)
  641. {
  642. cbOriginal = cbSize = *pcbData; // Size of output buffer
  643. }
  644. dwRet = RegQueryValueExA(hkey, pszValue, lpReserved, &dwType,
  645. pvData, &cbSize);
  646. // Normally, we'd be done with this. But do some extra work
  647. // if this is an expandable string (something that has system
  648. // variables in it), or if we need to pad the buffer.
  649. if (REG_SZ == dwType || REG_EXPAND_SZ == dwType)
  650. {
  651. dwRet = FixupRegStringA(hkey, pszValue, REG_EXPAND_SZ == dwType, dwRet, pvData, pcbData, &cbSize);
  652. // Massage dwType so that callers always see REG_SZ
  653. dwType = REG_SZ;
  654. }
  655. if (pdwType)
  656. *pdwType = dwType;
  657. if (pcbData)
  658. *pcbData = cbSize;
  659. return dwRet;
  660. }
  661. /*----------------------------------------------------------
  662. Purpose: Behaves just like RegQueryValueEx, except if the
  663. data type is REG_EXPAND_SZ, then this goes ahead
  664. and expands out the string. *pdwType will always
  665. be massaged to REG_SZ if this happens.
  666. Returns:
  667. Cond: --
  668. */
  669. STDAPI_(DWORD)
  670. SHQueryValueExW(
  671. IN HKEY hkey,
  672. IN LPCWSTR pwszValue,
  673. IN LPDWORD lpReserved,
  674. OUT LPDWORD pdwType,
  675. OUT LPVOID pvData,
  676. IN OUT LPDWORD pcbData)
  677. {
  678. DWORD dwRet;
  679. DWORD cbSize = 0;
  680. DWORD dwType = REG_NONE;
  681. if (pvData)
  682. {
  683. RIPMSG(pcbData != NULL, "SHQueryValueExW: caller passed pvData output buffer but not size of buffer (pcbData)!");
  684. }
  685. if ( !g_bRunningOnNT )
  686. {
  687. CHAR szValue[MAX_PATH];
  688. LPSTR pszValue = NULL;
  689. DWORD dwOriginalSize = 0;
  690. if (pvData && pcbData)
  691. dwOriginalSize = *pcbData;
  692. if (pwszValue)
  693. {
  694. WideCharToMultiByte(CP_ACP, 0, pwszValue, -1, szValue, SIZECHARS(szValue), NULL, NULL);
  695. pszValue = szValue;
  696. }
  697. if (!pdwType)
  698. pdwType = &dwType;
  699. dwRet = SHQueryValueExA(hkey, pszValue, lpReserved, pdwType, pvData, pcbData);
  700. if (NO_ERROR == dwRet)
  701. dwRet = RegData_AtoW(pvData, dwOriginalSize, *pdwType, pcbData); // Thunk data from ANSI->UNICODE if needed.
  702. }
  703. else
  704. {
  705. // Running on NT
  706. // Trying to get back data
  707. if (pvData && pcbData)
  708. {
  709. cbSize = *pcbData;
  710. }
  711. dwRet = RegQueryValueExW(hkey, pwszValue, lpReserved, &dwType,
  712. pvData, &cbSize);
  713. // Normally, we'd be done with this. But do some extra work
  714. // if this is an expandable string (something that has system
  715. // variables in it), or if we need to pad the buffer.
  716. if (REG_SZ == dwType || REG_EXPAND_SZ == dwType)
  717. {
  718. dwRet = FixupRegStringW(hkey, pwszValue, REG_EXPAND_SZ == dwType, dwRet, pvData, pcbData, &cbSize);
  719. // Massage dwType so that callers always see REG_SZ
  720. dwType = REG_SZ;
  721. }
  722. if (pdwType)
  723. *pdwType = dwType;
  724. if (pcbData)
  725. *pcbData = cbSize;
  726. }
  727. return dwRet;
  728. }
  729. /*----------------------------------------------------------
  730. Purpose: Behaves just like RegEnumKeyExA, except it does not let
  731. you look at the class and timestamp of the sub-key. Written
  732. to provide equivalent for SHEnumKeyExW which is useful on
  733. Win95.
  734. Returns:
  735. Cond: --
  736. */
  737. STDAPI_(LONG)
  738. SHEnumKeyExA
  739. (
  740. IN HKEY hkey,
  741. IN DWORD dwIndex,
  742. OUT LPSTR pszName,
  743. IN OUT LPDWORD pcchName
  744. )
  745. {
  746. return RegEnumKeyExA(hkey, dwIndex, pszName, pcchName, NULL, NULL, NULL, NULL);
  747. }
  748. /*----------------------------------------------------------
  749. Purpose: Behaves just like RegEnumKeyExW, except it does not let
  750. you look at the class and timestamp of the sub-key.
  751. Wide char version supported under Win95.
  752. Returns:
  753. Cond: --
  754. */
  755. STDAPI_(LONG)
  756. SHEnumKeyExW
  757. (
  758. IN HKEY hkey,
  759. IN DWORD dwIndex,
  760. OUT LPWSTR pszName,
  761. IN OUT LPDWORD pcchName
  762. )
  763. {
  764. LONG lRet = NO_ERROR;
  765. if ( !g_bRunningOnNT )
  766. {
  767. // We are reading in sub-key names. regapix.h suggests MAXIMUM_SUB_KEY_LENGTH = 256,
  768. // so MAX_PATH should be enough. Is this the official limit.
  769. CHAR sz[MAX_PATH];
  770. DWORD dwSize = sizeof(sz);
  771. lRet = RegEnumKeyExA(hkey, dwIndex, sz, &dwSize, NULL, NULL, NULL, NULL);
  772. if (NO_ERROR != lRet)
  773. {
  774. ASSERT(ERROR_MORE_DATA != lRet);
  775. }
  776. else
  777. {
  778. int cch = MultiByteToWideChar(CP_ACP, 0, sz, -1, NULL, 0);
  779. if (NULL == pcchName)
  780. {
  781. lRet = ERROR_INVALID_PARAMETER;
  782. }
  783. else if (NULL == pszName || *pcchName < (DWORD)cch )
  784. {
  785. *pcchName = cch;
  786. lRet = (NULL == pszName) ? ERROR_SUCCESS : ERROR_MORE_DATA ;
  787. }
  788. else
  789. {
  790. // Not supposed to include null terminator in count if successful.
  791. *pcchName = cch - 1;
  792. MultiByteToWideChar(CP_ACP, 0, sz, -1, pszName, cch);
  793. ASSERT(NO_ERROR == lRet);
  794. }
  795. }
  796. }
  797. else
  798. {
  799. lRet = RegEnumKeyExW(hkey, dwIndex, pszName, pcchName, NULL, NULL, NULL, NULL);
  800. }
  801. return lRet;
  802. }
  803. /*----------------------------------------------------------
  804. Purpose: Behaves just like RegEnumValueA. Written to provide
  805. equivalent for SHEnumKeyExW which is useful on Win95.
  806. Environment vars in a string are NOT expanded.
  807. Returns:
  808. Cond: --
  809. */
  810. STDAPI_(LONG)
  811. SHEnumValueA
  812. (
  813. IN HKEY hkey,
  814. IN DWORD dwIndex,
  815. OUT LPSTR pszValueName, OPTIONAL
  816. IN OUT LPDWORD pcchValueName, OPTIONAL
  817. OUT LPDWORD pdwType, OPTIONAL
  818. OUT LPVOID pvData, OPTIONAL
  819. IN OUT LPDWORD pcbData OPTIONAL
  820. )
  821. {
  822. return RegEnumValueA(hkey, dwIndex, pszValueName, pcchValueName, NULL, pdwType, pvData, pcbData);
  823. }
  824. /*----------------------------------------------------------
  825. Purpose: Behaves just like RegEnumValueW. Wide char version
  826. works on Win95.
  827. Environment vars in a string are NOT expanded.
  828. Returns:
  829. Cond: --
  830. */
  831. STDAPI_(LONG)
  832. SHEnumValueW
  833. (
  834. IN HKEY hkey,
  835. IN DWORD dwIndex,
  836. OUT LPWSTR pszValueName, OPTIONAL
  837. IN OUT LPDWORD pcchValueName, OPTIONAL
  838. OUT LPDWORD pdwType, OPTIONAL
  839. OUT LPVOID pvData, OPTIONAL
  840. IN OUT LPDWORD pcbData OPTIONAL
  841. )
  842. {
  843. LONG lRet;
  844. if ( !g_bRunningOnNT )
  845. {
  846. CHAR sz[MAX_PATH]; // This should be sufficient to read the value name.
  847. DWORD dwSize = sizeof(sz);
  848. DWORD dwType;
  849. DWORD cbSizeSav = 0;
  850. if (pcbData)
  851. cbSizeSav = *pcbData;
  852. lRet = RegEnumValueA(hkey, dwIndex, sz, &dwSize, NULL, &dwType, pvData, pcbData);
  853. if (pdwType)
  854. *pdwType = dwType;
  855. if (NO_ERROR == lRet)
  856. {
  857. // Convert the ValueName to unicode.
  858. if (pcchValueName)
  859. {
  860. int cch = MultiByteToWideChar(CP_ACP, 0, sz, -1, NULL, 0);
  861. if (NULL == pszValueName || *pcchValueName < (DWORD)cch )
  862. {
  863. *pcchValueName = cch;
  864. lRet = (NULL == pszValueName) ? ERROR_SUCCESS : ERROR_MORE_DATA ;
  865. }
  866. else
  867. {
  868. // Not supposed to include null terminator in count if returning
  869. // back name succesfully.
  870. *pcchValueName = cch - 1;
  871. // cch should be sufficient
  872. MultiByteToWideChar(CP_ACP, 0, sz, -1, pszValueName, cch);
  873. }
  874. }
  875. // Next convert the data to unicode if it is a string.
  876. if ((NOERROR == lRet) && pcbData)
  877. lRet = RegData_AtoW(pvData, cbSizeSav, dwType, pcbData);
  878. }
  879. }
  880. else
  881. {
  882. lRet = RegEnumValueW(hkey, dwIndex, pszValueName, pcchValueName, NULL, pdwType, pvData, pcbData);
  883. }
  884. return lRet;
  885. }
  886. /*----------------------------------------------------------
  887. Purpose: Behaves just like RegQueryInfoKeyA. Written to provide
  888. equivalent for W version.
  889. Returns:
  890. Cond: --
  891. */
  892. STDAPI_(LONG)
  893. SHQueryInfoKeyA
  894. (
  895. IN HKEY hkey,
  896. OUT LPDWORD pcSubKeys, OPTIONAL
  897. OUT LPDWORD pcchMaxSubKeyLen, OPTIONAL
  898. OUT LPDWORD pcValues, OPTIONAL
  899. OUT LPDWORD pcchMaxValueNameLen OPTIONAL
  900. )
  901. {
  902. return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, pcSubKeys, pcchMaxSubKeyLen,
  903. NULL, pcValues, pcchMaxValueNameLen, NULL, NULL, NULL);
  904. }
  905. /*----------------------------------------------------------
  906. Purpose: Behaves just like RegQueryInfoKeyW. Works on Win95.
  907. Returns:
  908. Cond: --
  909. */
  910. STDAPI_(LONG)
  911. SHQueryInfoKeyW
  912. (
  913. IN HKEY hkey,
  914. OUT LPDWORD pcSubKeys, OPTIONAL
  915. OUT LPDWORD pcchMaxSubKeyLen, OPTIONAL
  916. OUT LPDWORD pcValues, OPTIONAL
  917. OUT LPDWORD pcchMaxValueNameLen OPTIONAL
  918. )
  919. {
  920. LONG lRet;
  921. if (!g_bRunningOnNT)
  922. {
  923. lRet = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, pcSubKeys, pcchMaxSubKeyLen,
  924. NULL, pcValues, pcchMaxValueNameLen, NULL, NULL, NULL);
  925. if (NO_ERROR == lRet)
  926. {
  927. // *pcchMaxSubKeyLen has the number of single byte chars reqd for the
  928. // KeyName. We return back the same value which is an upper limit on
  929. // the number of Unicode characters needed. We will ask for more
  930. // Unicode chars than required if the string has DBCS characters.
  931. // Without knowing the actual string this is the best guess we can take.
  932. }
  933. }
  934. else
  935. {
  936. lRet = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, pcSubKeys, pcchMaxSubKeyLen,
  937. NULL, pcValues, pcchMaxValueNameLen, NULL, NULL, NULL);
  938. }
  939. return lRet;
  940. }
  941. /*----------------------------------------------------------*\
  942. USER SPECIFC SETTINGS
  943. DESCRIPTION:
  944. These functions will be used to query User Specific settings
  945. correctly. The installer needs to populate HKLM
  946. with User specific settings, because that's the only part
  947. of the registry that is shared between all users. Code will
  948. then read values from HKCU, and if that's empty, it
  949. will look in HKLM. The only exception is that if
  950. TRUE is passed in for the fIgnore parameter, then the HKLM version
  951. will be used instead of HKCU. This is the way that an admin can
  952. specify that they doesn't want users to be able to use their
  953. User Specific values (HKCU).
  954. \*----------------------------------------------------------*/
  955. typedef struct tagUSKEY
  956. {
  957. HKEY hkeyCurrentUser;
  958. HKEY hkeyCurrentUserRelative;
  959. HKEY hkeyLocalMachine;
  960. HKEY hkeyLocalMachineRelative;
  961. CHAR szSubPath[MAXIMUM_SUB_KEY_LENGTH];
  962. REGSAM samDesired;
  963. } USKEY;
  964. typedef USKEY * PUSKEY;
  965. typedef PUSKEY * PPUSKEY;
  966. #define IS_HUSKEY_VALID(pUSKey) (((pUSKey) && IS_VALID_WRITE_PTR((pUSKey), USKEY) && ((pUSKey)->hkeyCurrentUser || (pUSKey)->hkeyLocalMachine)))
  967. // Private Helper Function
  968. // Bring the out of date key up to date.
  969. LONG PrivFullOpen(PUSKEY pUSKey)
  970. {
  971. LONG lRet = ERROR_SUCCESS;
  972. HKEY *phkey = NULL;
  973. HKEY *phkeyRel = NULL;
  974. ASSERT(IS_HUSKEY_VALID(pUSKey)); // Will always be true, but assert against maintainence mistakes
  975. if (!pUSKey->hkeyCurrentUser) // Do we need to open HKCU?
  976. {
  977. phkey = &(pUSKey->hkeyCurrentUser);
  978. phkeyRel = &(pUSKey->hkeyCurrentUserRelative);
  979. }
  980. if (!pUSKey->hkeyLocalMachine) // Do we need to open HKLM?
  981. {
  982. phkey = &(pUSKey->hkeyLocalMachine);
  983. phkeyRel = &(pUSKey->hkeyLocalMachineRelative);
  984. }
  985. if ((phkeyRel) && (*phkeyRel))
  986. {
  987. ASSERT(phkey); // Will always be true, but assert against maintainence mistakes
  988. lRet = RegOpenKeyExA(*phkeyRel, pUSKey->szSubPath, 0, pUSKey->samDesired, phkey);
  989. // If we need to bring the out of date key, up to date, we need to free the old one.
  990. if ((HKEY_CURRENT_USER != *phkeyRel) && (HKEY_LOCAL_MACHINE != *phkeyRel))
  991. RegCloseKey(*phkeyRel);
  992. *phkeyRel = NULL;
  993. pUSKey->szSubPath[0] = '\0';
  994. }
  995. return lRet;
  996. }
  997. // Private Helper Function
  998. // Bring the out of date key up to date.
  999. LONG PrivFullCreate(PUSKEY pUSKey)
  1000. {
  1001. LONG lRet = ERROR_SUCCESS;
  1002. HKEY *phkey = NULL;
  1003. HKEY *phkeyRel = NULL;
  1004. ASSERT(IS_HUSKEY_VALID(pUSKey)); // Will always be true, but assert against maintainence mistakes
  1005. if (!pUSKey->hkeyCurrentUser) // Do we need to open HKCU?
  1006. {
  1007. phkey = &(pUSKey->hkeyCurrentUser);
  1008. phkeyRel = &(pUSKey->hkeyCurrentUserRelative);
  1009. }
  1010. if (!pUSKey->hkeyLocalMachine) // Do we need to open HKLM?
  1011. {
  1012. phkey = &(pUSKey->hkeyLocalMachine);
  1013. phkeyRel = &(pUSKey->hkeyLocalMachineRelative);
  1014. }
  1015. if ((phkeyRel) && (*phkeyRel))
  1016. {
  1017. ASSERT(phkey); // Will always be true, but assert against maintainence mistakes
  1018. lRet = RegCreateKeyExA(*phkeyRel, pUSKey->szSubPath, 0, NULL, REG_OPTION_NON_VOLATILE, pUSKey->samDesired, NULL, phkey, NULL);
  1019. // If we need to bring the out of date key, up to date, we need to free the old one.
  1020. if ((HKEY_CURRENT_USER != *phkeyRel) && (HKEY_LOCAL_MACHINE != *phkeyRel))
  1021. RegCloseKey(*phkeyRel);
  1022. *phkeyRel = NULL;
  1023. pUSKey->szSubPath[0] = '\0';
  1024. }
  1025. return lRet;
  1026. }
  1027. // Private Helper Function
  1028. // Create one of the keys (Called for both HKLM and HKCU)
  1029. LONG PrivCreateKey(LPHKEY lphkey, LPHKEY lphkeyRelative, LPCSTR lpSubPath, REGSAM samDesired)
  1030. {
  1031. LONG lRet = ERROR_SUCCESS;
  1032. if (*lphkeyRelative)
  1033. {
  1034. lRet = RegCreateKeyExA(*lphkeyRelative, lpSubPath, 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, lphkey, NULL);
  1035. *lphkeyRelative = NULL;
  1036. }
  1037. else
  1038. {
  1039. // If the relative key == NULL, then we don't have enough of the path to
  1040. // create this key.
  1041. return(ERROR_INVALID_PARAMETER);
  1042. }
  1043. return(lRet);
  1044. }
  1045. // Private Helper Function
  1046. // Query for the specific value.
  1047. LONG PrivRegQueryValue(
  1048. IN PUSKEY pUSKey,
  1049. IN HKEY *phkey,
  1050. IN LPCWSTR pwzValue, // May have been an ANSI String type case. Use fWideChar to determine if so.
  1051. IN BOOL fWideChar,
  1052. OUT LPDWORD pdwType, OPTIONAL
  1053. OUT LPVOID pvData, OPTIONAL
  1054. OUT LPDWORD pcbData) OPTIONAL
  1055. {
  1056. LONG lRet = ERROR_SUCCESS;
  1057. ASSERT(IS_HUSKEY_VALID(pUSKey)); // Will always be true, but assert against maintainence mistakes
  1058. // It may be necessary to open the key
  1059. if (NULL == *phkey)
  1060. lRet = PrivFullOpen(pUSKey);
  1061. if ((ERROR_SUCCESS == lRet) && (*phkey))
  1062. {
  1063. if (fWideChar)
  1064. lRet = SHQueryValueExW(*phkey, pwzValue, NULL, pdwType, pvData, pcbData);
  1065. else
  1066. lRet = SHQueryValueExA(*phkey, (LPCSTR)pwzValue, NULL, pdwType, pvData, pcbData);
  1067. }
  1068. else
  1069. lRet = ERROR_INVALID_PARAMETER;
  1070. return lRet;
  1071. }
  1072. // Private Helper Function
  1073. // Query for the specific value.
  1074. LONG PrivRegWriteValue(
  1075. IN PUSKEY pUSKey,
  1076. IN HKEY *phkey,
  1077. IN LPCWSTR pwzValue, // May have been an ANSI String type case. Use fWideChar to determine if so.
  1078. IN BOOL bWideChar,
  1079. IN BOOL bForceWrite,
  1080. IN DWORD dwType, OPTIONAL
  1081. IN LPCVOID pvData, OPTIONAL
  1082. IN DWORD cbData) OPTIONAL
  1083. {
  1084. LONG lRet = ERROR_SUCCESS;
  1085. ASSERT(IS_HUSKEY_VALID(pUSKey)); // Will always be true, but assert against maintainence mistakes
  1086. // It may be necessary to open the key
  1087. if (NULL == *phkey)
  1088. lRet = PrivFullCreate(pUSKey);
  1089. // Check if the caller only want's to write value if it's empty
  1090. if (!bForceWrite)
  1091. { // Yes we need to check before we write.
  1092. if (bWideChar)
  1093. bForceWrite = !(ERROR_SUCCESS == SHQueryValueExW(*phkey, pwzValue, NULL, NULL, NULL, NULL));
  1094. else
  1095. bForceWrite = !(ERROR_SUCCESS == SHQueryValueExA(*phkey, (LPCSTR)pwzValue, NULL, NULL, NULL, NULL));
  1096. }
  1097. if ((ERROR_SUCCESS == lRet) && (*phkey) && bForceWrite)
  1098. {
  1099. if (bWideChar)
  1100. // RegSetValueExW is not supported on Win95 but we have a thunking function.
  1101. lRet = RegSetValueExW(*phkey, pwzValue, 0, dwType, pvData, cbData);
  1102. else
  1103. lRet = RegSetValueExA(*phkey, (LPCSTR)pwzValue, 0, dwType, pvData, cbData);
  1104. }
  1105. return lRet;
  1106. }
  1107. // Private helper function
  1108. // Enum sub-keys of a key.
  1109. LONG PrivRegEnumKey(
  1110. IN PUSKEY pUSKey,
  1111. IN HKEY *phkey,
  1112. IN DWORD dwIndex,
  1113. IN LPWSTR pwzName, // May have been an ANSI String type case. Use fWideChar to determine if so.
  1114. IN BOOL fWideChar,
  1115. IN OUT LPDWORD pcchName
  1116. )
  1117. {
  1118. LONG lRet = ERROR_SUCCESS;
  1119. ASSERT(IS_HUSKEY_VALID(pUSKey));
  1120. // It may be necessary to open the key
  1121. if (NULL == *phkey)
  1122. lRet = PrivFullOpen(pUSKey);
  1123. if ((ERROR_SUCCESS == lRet) && (*phkey))
  1124. {
  1125. if (fWideChar)
  1126. lRet = SHEnumKeyExW(*phkey, dwIndex, pwzName, pcchName);
  1127. else
  1128. lRet = SHEnumKeyExA(*phkey, dwIndex, (LPSTR)pwzName, pcchName);
  1129. }
  1130. else
  1131. lRet = ERROR_INVALID_PARAMETER;
  1132. return lRet;
  1133. }
  1134. // Private helper function
  1135. // Enum values of a key.
  1136. LONG PrivRegEnumValue(
  1137. IN PUSKEY pUSKey,
  1138. IN HKEY *phkey,
  1139. IN DWORD dwIndex,
  1140. IN LPWSTR pwzValueName, // May have been an ANSI String type case. Use fWideChar to determine if so.
  1141. IN BOOL fWideChar,
  1142. IN OUT LPDWORD pcchValueName,
  1143. OUT LPDWORD pdwType, OPTIONAL
  1144. OUT LPVOID pvData, OPTIONAL
  1145. IN OUT LPDWORD pcbData OPTIONAL
  1146. )
  1147. {
  1148. LONG lRet = ERROR_SUCCESS;
  1149. ASSERT(IS_HUSKEY_VALID(pUSKey));
  1150. // It may be necessary to open the key
  1151. if (NULL == *phkey)
  1152. lRet = PrivFullOpen(pUSKey);
  1153. if ((ERROR_SUCCESS == lRet) && (*phkey))
  1154. {
  1155. if (fWideChar)
  1156. lRet = SHEnumValueW(*phkey, dwIndex, pwzValueName, pcchValueName, pdwType, pvData, pcbData);
  1157. else
  1158. lRet = SHEnumValueA(*phkey, dwIndex, (LPSTR)pwzValueName, pcchValueName, pdwType, pvData, pcbData);
  1159. }
  1160. else
  1161. lRet = ERROR_INVALID_PARAMETER;
  1162. return lRet;
  1163. }
  1164. // Query the Key information.
  1165. LONG PrivRegQueryInfoKey(
  1166. IN PUSKEY pUSKey,
  1167. IN HKEY *phkey,
  1168. IN BOOL fWideChar,
  1169. OUT LPDWORD pcSubKeys, OPTIONAL
  1170. OUT LPDWORD pcchMaxSubKeyLen, OPTIONAL
  1171. OUT LPDWORD pcValues, OPTIONAL
  1172. OUT LPDWORD pcchMaxValueNameLen OPTIONAL
  1173. )
  1174. {
  1175. LONG lRet = ERROR_SUCCESS;
  1176. ASSERT(IS_HUSKEY_VALID(pUSKey));
  1177. if (NULL == *phkey)
  1178. lRet = PrivFullOpen(pUSKey);
  1179. if ((ERROR_SUCCESS == lRet) && (*phkey))
  1180. {
  1181. if (fWideChar)
  1182. lRet = SHQueryInfoKeyW(*phkey, pcSubKeys, pcchMaxSubKeyLen, pcValues, pcchMaxValueNameLen);
  1183. else
  1184. lRet = SHQueryInfoKeyA(*phkey, pcSubKeys, pcchMaxSubKeyLen, pcValues, pcchMaxValueNameLen);
  1185. }
  1186. else
  1187. lRet = ERROR_INVALID_PARAMETER;
  1188. return lRet;
  1189. }
  1190. /*----------------------------------------------------------
  1191. Purpose: Create or open a user specifc registry key (HUSKEY).
  1192. Description: This function will:
  1193. 1. Allocate a new USKEY structure.
  1194. 2. Initialize the structure.
  1195. 3. Create/Open HKLM if that flag is set.
  1196. 4. Create/Open HKCU if that flag is set.
  1197. Note that there is no difference between FORCE and
  1198. don't force in the dwFlags parameter.
  1199. The hUSKeyRelative parameter should have also been opened by
  1200. a call to SHRegCreateUSKey. If SHRegOpenUSKey was called,
  1201. it could have returned ERROR_SUCCESS but still be invalid
  1202. for calling this function. This will occur if: 1) the parameter
  1203. fIgnoreHKCU was FALSE, 2) it was a relative open, 3) the
  1204. HKCU branch could not be opened because it didn't exist, and
  1205. 4) HKLM opened successfully. This situation renders the
  1206. HUSKEY valid for reading but not writing.
  1207. Returns: LONG containing success or error code.
  1208. Cond: --
  1209. */
  1210. STDAPI_(LONG)
  1211. SHRegCreateUSKeyA(
  1212. IN LPCSTR pszPath,
  1213. IN REGSAM samDesired, // security access mask
  1214. IN HUSKEY hUSKeyRelative, OPTIONAL
  1215. OUT PHUSKEY phUSKey,
  1216. IN DWORD dwFlags) // Indicates whether to create/open HKCU, HKLM, or both
  1217. {
  1218. PUSKEY pUSKeyRelative = (PUSKEY) hUSKeyRelative;
  1219. PPUSKEY ppUSKey = (PPUSKEY) phUSKey;
  1220. PUSKEY pUSKey;
  1221. LONG lRet = ERROR_SUCCESS;
  1222. CHAR szTempPath[MAXIMUM_SUB_KEY_LENGTH] = "\0";
  1223. LPCSTR lpszHKLMPath = szTempPath;
  1224. LPCSTR lpszHKCUPath = szTempPath;
  1225. ASSERT(ppUSKey);
  1226. // The following are invalid parameters...
  1227. // 1. ppUSKey cannot be NULL
  1228. // 2. If this is a relative open, pUSKeyRelative needs to be a valid HUSKEY.
  1229. // 3. The user needs to have specified one of the following: SHREGSET_HKCU, SHREGSET_FORCE_HKCU, SHREGSET_HKLM, SHREGSET_FORCE_HKLM.
  1230. if ((!ppUSKey) || // 1.
  1231. (pUSKeyRelative && FALSE == IS_HUSKEY_VALID(pUSKeyRelative)) || // 2.
  1232. !(dwFlags & (SHREGSET_HKCU | SHREGSET_FORCE_HKCU | SHREGSET_HKLM | SHREGSET_FORCE_HKLM))) // 3.
  1233. {
  1234. return ERROR_INVALID_PARAMETER;
  1235. }
  1236. // The temp path will be used when bringing the keys
  1237. // up todate that was out of date in the Relative key.
  1238. if (pUSKeyRelative)
  1239. {
  1240. lstrcpyA(szTempPath, pUSKeyRelative->szSubPath);
  1241. PathAddBackslashA(szTempPath);
  1242. }
  1243. StrNCatA(szTempPath, pszPath, ARRAYSIZE(szTempPath) - lstrlenA(szTempPath) - 1);
  1244. ///// 1. Allocate a new USKEY structure.
  1245. pUSKey = *ppUSKey = (PUSKEY)LocalAlloc(LPTR, sizeof(USKEY));
  1246. if (!pUSKey)
  1247. return ERROR_NOT_ENOUGH_MEMORY;
  1248. ///// 2. Initialize the structure.
  1249. if (!pUSKeyRelative)
  1250. {
  1251. // Init a new (non-relative) open.
  1252. pUSKey->hkeyLocalMachineRelative = HKEY_LOCAL_MACHINE;
  1253. pUSKey->hkeyCurrentUserRelative = HKEY_CURRENT_USER;
  1254. }
  1255. else
  1256. {
  1257. // Init a new (relative) open.
  1258. *pUSKey = *pUSKeyRelative;
  1259. if (pUSKey->hkeyLocalMachine)
  1260. {
  1261. pUSKey->hkeyLocalMachineRelative = pUSKey->hkeyLocalMachine;
  1262. pUSKey->hkeyLocalMachine = NULL;
  1263. lpszHKLMPath = pszPath;
  1264. // This key is up to date in the Relative Key. If the
  1265. // user doesn't want it to be up todate in the new key,
  1266. // we don't need the path from the Relative key.
  1267. if (!(dwFlags & (SHREGSET_HKLM | SHREGSET_FORCE_HKLM)))
  1268. *(pUSKey->szSubPath) = '\0';
  1269. }
  1270. // We need to copy the key if:
  1271. // 1. It will not be created in this call, and
  1272. // 2. The relative key is not HKEY_LOCAL_MACHINE.
  1273. if (!(dwFlags & (SHREGSET_HKLM | SHREGSET_FORCE_HKLM)) &&
  1274. (pUSKey->hkeyLocalMachineRelative != HKEY_LOCAL_MACHINE))
  1275. {
  1276. // Make a duplicate of this key.
  1277. lRet = RegOpenKeyExA(pUSKey->hkeyLocalMachineRelative, NULL, 0, pUSKey->samDesired, &(pUSKey->hkeyLocalMachineRelative));
  1278. }
  1279. if (pUSKey->hkeyCurrentUser)
  1280. {
  1281. pUSKey->hkeyCurrentUserRelative = pUSKey->hkeyCurrentUser;
  1282. pUSKey->hkeyCurrentUser = NULL;
  1283. lpszHKCUPath = pszPath;
  1284. // This key is up to date in the Relative Key. If the
  1285. // user doesn't want it to be up todate in the new key,
  1286. // we don't need the path from the Relative key.
  1287. if (!(dwFlags & (SHREGSET_HKCU | SHREGSET_FORCE_HKCU)))
  1288. *(pUSKey->szSubPath) = '\0';
  1289. }
  1290. // We need to copy the key if:
  1291. // 1. It will not be created in this call, and
  1292. // 2. The relative key is not HKEY_CURRENT_USER.
  1293. if (!(dwFlags & (SHREGSET_HKCU | SHREGSET_FORCE_HKCU)) &&
  1294. (pUSKey->hkeyCurrentUserRelative != HKEY_CURRENT_USER))
  1295. {
  1296. // Make a duplicate of this key.
  1297. lRet = RegOpenKeyExA(pUSKey->hkeyCurrentUserRelative, NULL, 0, pUSKey->samDesired, &(pUSKey->hkeyCurrentUserRelative));
  1298. }
  1299. }
  1300. pUSKey->samDesired = samDesired;
  1301. ///// 3. Create/Open HKLM if that flag is set or fill in the structure as appropriate.
  1302. if ((ERROR_SUCCESS == lRet) && (dwFlags & (SHREGSET_HKLM | SHREGSET_FORCE_HKLM)))
  1303. lRet = PrivCreateKey(&(pUSKey->hkeyLocalMachine), &(pUSKey->hkeyLocalMachineRelative), lpszHKLMPath, pUSKey->samDesired);
  1304. ///// 4. Create/Open HKCU if that flag is set or fill in the structure as appropriate.
  1305. if ((ERROR_SUCCESS == lRet) && (dwFlags & (SHREGSET_HKCU | SHREGSET_FORCE_HKCU)))
  1306. lRet = PrivCreateKey(&(pUSKey->hkeyCurrentUser), &(pUSKey->hkeyCurrentUserRelative), lpszHKCUPath, pUSKey->samDesired);
  1307. if ((dwFlags & (SHREGSET_HKCU | SHREGSET_FORCE_HKCU)) &&
  1308. (dwFlags & (SHREGSET_HKLM | SHREGSET_FORCE_HKLM)))
  1309. {
  1310. // The caller wanted both to be opened.
  1311. *(pUSKey->szSubPath) = '\0'; // Both paths are open so Delta Path is empty.
  1312. }
  1313. else
  1314. {
  1315. // One of the paths is not open so set the Delta Path in case it needs to be opened later.
  1316. if (*(pUSKey->szSubPath))
  1317. PathAddBackslashA(pUSKey->szSubPath);
  1318. StrNCatA(pUSKey->szSubPath, pszPath, ARRAYSIZE(pUSKey->szSubPath) - lstrlenA(pUSKey->szSubPath) - 1);
  1319. }
  1320. // Free the memory if we are not successful.
  1321. if (ERROR_SUCCESS != lRet)
  1322. {
  1323. if (pUSKey->hkeyCurrentUser)
  1324. RegCloseKey(pUSKey->hkeyCurrentUser);
  1325. if (pUSKey->hkeyCurrentUserRelative && pUSKey->hkeyCurrentUserRelative != HKEY_CURRENT_USER)
  1326. RegCloseKey(pUSKey->hkeyCurrentUserRelative);
  1327. if (pUSKey->hkeyLocalMachine)
  1328. RegCloseKey(pUSKey->hkeyLocalMachine);
  1329. if (pUSKey->hkeyLocalMachineRelative && pUSKey->hkeyLocalMachineRelative != HKEY_LOCAL_MACHINE)
  1330. RegCloseKey(pUSKey->hkeyLocalMachineRelative);
  1331. LocalFree((HLOCAL)pUSKey);
  1332. *ppUSKey = NULL;
  1333. }
  1334. return lRet;
  1335. }
  1336. /*----------------------------------------------------------
  1337. Purpose: Create or open a user specifc registry key (HUSKEY).
  1338. Description: This function will:
  1339. 1. Allocate a new USKEY structure.
  1340. 2. Initialize the structure.
  1341. 3. Create/Open HKLM if that flag is set.
  1342. 4. Create/Open HKCU if that flag is set.
  1343. Note that there is no difference between FORCE and
  1344. don't force in the dwFlags parameter.
  1345. The hUSKeyRelative parameter should have also been opened by
  1346. a call to SHRegCreateUSKey. If SHRegOpenUSKey was called,
  1347. it could have returned ERROR_SUCCESS but still be invalid
  1348. for calling this function. This will occur if: 1) the parameter
  1349. fIgnoreHKCU was FALSE, 2) it was a relative open, 3) the
  1350. HKCU branch could not be opened because it didn't exist, and
  1351. 4) HKLM opened successfully. This situation renders the
  1352. HUSKEY valid for reading but not writing.
  1353. Returns: LONG containing success or error code.
  1354. Cond: --
  1355. */
  1356. STDAPI_(LONG)
  1357. SHRegCreateUSKeyW(
  1358. IN LPCWSTR pwzPath,
  1359. IN REGSAM samDesired, // security access mask
  1360. IN HUSKEY hUSKeyRelative, OPTIONAL
  1361. OUT PHUSKEY phUSKey,
  1362. IN DWORD dwFlags) // Indicates whether to create/open HKCU, HKLM, or both
  1363. {
  1364. CHAR szNewPath[MAXIMUM_SUB_KEY_LENGTH];
  1365. // Thunk Path to Wide chars.
  1366. if (FALSE == WideCharToMultiByte(CP_ACP, 0, pwzPath, -1, szNewPath, sizeof(szNewPath), NULL, 0))
  1367. return GetLastError();
  1368. return SHRegCreateUSKeyA(szNewPath, samDesired, hUSKeyRelative, phUSKey, dwFlags);
  1369. }
  1370. /*----------------------------------------------------------
  1371. Purpose: Open a user specifc registry key (HUSKEY).
  1372. Description: This function will:
  1373. 1. Allocate a new USKEY structure.
  1374. 2. Initialize the structure.
  1375. 3. Determine which key (HKLM or HKCU) will be the one brought up to date.
  1376. 4. Open the key that is going to be brought up to date.
  1377. If #4 Succeeded:
  1378. 5a. Copy the handle of the out of date key, so it can be opened later if needed.
  1379. If #4 Failed:
  1380. 5b. The other key will now be the one brought up to date, as long as it is HKLM.
  1381. 6b. Tag the out of date as INVALID. (Key == NULL; RelKey == NULL)
  1382. Returns: LONG containing success or error code.
  1383. Cond: --
  1384. */
  1385. STDAPI_(LONG)
  1386. SHRegOpenUSKeyA(
  1387. IN LPCSTR pszPath,
  1388. IN REGSAM samDesired, // security access mask
  1389. IN HUSKEY hUSKeyRelative, OPTIONAL
  1390. OUT PHUSKEY phUSKey,
  1391. IN BOOL fIgnoreHKCU)
  1392. {
  1393. PUSKEY pUSKeyRelative = (PUSKEY) hUSKeyRelative;
  1394. PPUSKEY ppUSKey = (PPUSKEY) phUSKey;
  1395. PUSKEY pUSKey;
  1396. LONG lRet = ERROR_SUCCESS;
  1397. HKEY * phkeyMaster;
  1398. HKEY * phkeyRelMaster;
  1399. HKEY * phkeyOld;
  1400. HKEY * phkeyRelOld;
  1401. ASSERT(ppUSKey);
  1402. // The following are invalid parameters...
  1403. // 1. ppUSKey cannot be NULL
  1404. // 2. If this is a relative open, pUSKeyRelative needs to be a valid HUSKEY.
  1405. if ((!ppUSKey) || // 1.
  1406. (pUSKeyRelative && FALSE == IS_HUSKEY_VALID(pUSKeyRelative))) // 2.
  1407. {
  1408. return ERROR_INVALID_PARAMETER;
  1409. }
  1410. ///// 1. Allocate a new USKEY structure.
  1411. pUSKey = *ppUSKey = (PUSKEY)LocalAlloc(LPTR, sizeof(USKEY));
  1412. if (!pUSKey)
  1413. return ERROR_NOT_ENOUGH_MEMORY;
  1414. ///// 2. Initialize the structure.
  1415. if (!pUSKeyRelative)
  1416. {
  1417. // Init a new (non-relative) open.
  1418. pUSKey->hkeyLocalMachineRelative = HKEY_LOCAL_MACHINE;
  1419. pUSKey->hkeyCurrentUserRelative = HKEY_CURRENT_USER;
  1420. }
  1421. else
  1422. {
  1423. // Init a new (relative) open.
  1424. *pUSKey = *pUSKeyRelative;
  1425. }
  1426. pUSKey->samDesired = samDesired;
  1427. ///// 3. Determine which key (HKLM or HKCU) will be the one brought up to date.
  1428. // The HUSKY struct will contain 4 HKEYs. HKCU, HKCU Relative, HKLM, and HKLM Relative.
  1429. // For efficiency, only one key will be up to date (HKCU or HKLM). The one that
  1430. // is out of date will be NULL to indicate out of date. The relative key for the
  1431. // out of date key, will be the last opened key. The string will be the delta between
  1432. // the last open key and the current open level.
  1433. // We will determine which key will be the new valid key (Master).
  1434. if (FALSE == fIgnoreHKCU)
  1435. {
  1436. phkeyMaster = &(pUSKey->hkeyCurrentUser);
  1437. phkeyRelMaster = &(pUSKey->hkeyCurrentUserRelative);
  1438. phkeyOld = &(pUSKey->hkeyLocalMachine);
  1439. phkeyRelOld = &(pUSKey->hkeyLocalMachineRelative);
  1440. }
  1441. else
  1442. {
  1443. phkeyMaster = &(pUSKey->hkeyLocalMachine);
  1444. phkeyRelMaster = &(pUSKey->hkeyLocalMachineRelative);
  1445. phkeyOld = &(pUSKey->hkeyCurrentUser);
  1446. phkeyRelOld = &(pUSKey->hkeyCurrentUserRelative);
  1447. }
  1448. // Add the new Path to the Total path.
  1449. if ('\0' != *(pUSKey->szSubPath))
  1450. PathAddBackslashA(pUSKey->szSubPath); // Add separator \ if reqd.
  1451. StrNCatA(pUSKey->szSubPath, pszPath, ARRAYSIZE(pUSKey->szSubPath) - lstrlenA(pUSKey->szSubPath) - 1);
  1452. ///// 4. Open the key that is going to be brought up to date.
  1453. if (*phkeyMaster)
  1454. {
  1455. // Masterkey is already up to date, so just do the relative open and add the string to szSubPath
  1456. // It's safe to write write (*phkeyMaster) because it will be freed by the HUSKEY used for the
  1457. // relative open.
  1458. lRet = RegOpenKeyExA(*phkeyMaster, pszPath, 0, pUSKey->samDesired, phkeyMaster);
  1459. }
  1460. else
  1461. {
  1462. // Open Masterkey with the full path (pUSKey->szSubPath + pszPath)
  1463. if (*phkeyRelMaster)
  1464. lRet = RegOpenKeyExA(*phkeyRelMaster, pUSKey->szSubPath, 0, pUSKey->samDesired, phkeyMaster);
  1465. else
  1466. lRet = ERROR_FILE_NOT_FOUND;
  1467. lstrcpyA(pUSKey->szSubPath, pszPath);
  1468. *phkeyRelMaster = NULL;
  1469. }
  1470. ///// Did #4 Succeeded?
  1471. if (ERROR_FILE_NOT_FOUND == lRet)
  1472. {
  1473. ///// #4 Failed, Now we can try to open HKLM if the previous attempt was to open HKCU.
  1474. if (!fIgnoreHKCU)
  1475. {
  1476. if (*phkeyRelOld) // Can HKLM be opened?
  1477. {
  1478. ASSERT(*phkeyOld == NULL); // *phkeyOld should never have a value if *phkeyRelOld does.
  1479. ///// 5b. The other key will now be the one brought up to date, as long as it is HKLM.
  1480. lRet = RegOpenKeyExA(*phkeyRelOld, pUSKey->szSubPath, 0, pUSKey->samDesired, phkeyOld);
  1481. *phkeyRelOld = NULL;
  1482. }
  1483. else if (*phkeyOld) // Can HKLM be opened?
  1484. {
  1485. ///// 5b. Attempt to bring the other key up to date.
  1486. lRet = RegOpenKeyExA(*phkeyOld, pUSKey->szSubPath, 0, pUSKey->samDesired, phkeyOld);
  1487. }
  1488. }
  1489. else
  1490. {
  1491. *phkeyOld = NULL; // Tag this as INVALID
  1492. *phkeyRelOld = NULL; // Tag this as INVALID
  1493. }
  1494. ///// 6b. Tag the out of date as INVALID. (Key == NULL; RelKey == NULL)
  1495. *phkeyMaster = NULL; // Tag this as INVALID
  1496. *phkeyRelMaster = NULL; // Tag this as INVALID
  1497. }
  1498. else
  1499. {
  1500. ///// #4 Succeeded:
  1501. ///// 5a. Does the out of date key need to be copied?
  1502. if (*phkeyOld)
  1503. {
  1504. // Copy the handle of the out of date key, so it can be opened later if needed.
  1505. // We can be assured that any NON-Relative HKEY will not be HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER
  1506. ASSERT(*phkeyOld != HKEY_LOCAL_MACHINE && *phkeyOld != HKEY_CURRENT_USER); // But let's assert anyway.
  1507. RegOpenKeyExA(*phkeyOld, NULL, 0, pUSKey->samDesired, phkeyOld);
  1508. }
  1509. else
  1510. {
  1511. if ((*phkeyRelOld) && (*phkeyRelOld != HKEY_LOCAL_MACHINE) && (*phkeyRelOld != HKEY_CURRENT_USER))
  1512. {
  1513. // Copy the handle of the out of date key, so it can be opened later if needed.
  1514. lRet = RegOpenKeyExA(*phkeyRelOld, NULL, 0, pUSKey->samDesired, phkeyRelOld);
  1515. }
  1516. }
  1517. if (*phkeyOld)
  1518. {
  1519. *phkeyRelOld = *phkeyOld;
  1520. *phkeyOld = NULL; // Mark this key as being out of date.
  1521. }
  1522. }
  1523. // Free the memory if we are not successful.
  1524. if (ERROR_SUCCESS != lRet)
  1525. {
  1526. pUSKey->hkeyCurrentUser = NULL; // Mark invalid.
  1527. pUSKey->hkeyLocalMachine = NULL;
  1528. LocalFree((HLOCAL)pUSKey);
  1529. *ppUSKey = NULL;
  1530. }
  1531. return lRet;
  1532. }
  1533. /*----------------------------------------------------------
  1534. Purpose: Open a user specifc registry key (HUSKEY).
  1535. Returns: LONG containing success or error code.
  1536. Cond: --
  1537. */
  1538. STDAPI_(LONG)
  1539. SHRegOpenUSKeyW(
  1540. IN LPCWSTR pwzPath,
  1541. IN REGSAM samDesired, // security access mask
  1542. IN HUSKEY hUSKeyRelative, OPTIONAL
  1543. OUT PHUSKEY phUSKey,
  1544. IN BOOL fIgnoreHKCU)
  1545. {
  1546. CHAR szNewPath[MAXIMUM_SUB_KEY_LENGTH];
  1547. // Thunk Path to Wide chars.
  1548. if (FALSE == WideCharToMultiByte(CP_ACP, 0, pwzPath, -1, szNewPath, sizeof(szNewPath), NULL, 0))
  1549. return GetLastError();
  1550. return SHRegOpenUSKeyA(szNewPath, samDesired, hUSKeyRelative, phUSKey, fIgnoreHKCU);
  1551. }
  1552. /*----------------------------------------------------------
  1553. Purpose: Query a user specific registry entry for it's value.
  1554. This will NOT
  1555. open and close the keys in which the value resides.
  1556. The caller needs to do this and it should be done
  1557. when several keys will be queried for a perf increase.
  1558. Callers that only call this once, will probably want
  1559. to call SHGetUSValue().
  1560. Returns: LONG containing success or error code.
  1561. Cond: --
  1562. */
  1563. STDAPI_(LONG)
  1564. SHRegQueryUSValueA(
  1565. IN HUSKEY hUSKey,
  1566. IN LPCSTR pszValue,
  1567. OUT LPDWORD pdwType, OPTIONAL
  1568. OUT LPVOID pvData, OPTIONAL
  1569. OUT LPDWORD pcbData, OPTIONAL
  1570. IN BOOL fIgnoreHKCU,
  1571. IN LPVOID pvDefaultData, OPTIONAL
  1572. IN DWORD dwDefaultDataSize) OPTIONAL
  1573. {
  1574. PUSKEY pUSKey = (PUSKEY) hUSKey;
  1575. LONG lRet = ERROR_SUCCESS;
  1576. DWORD dwSize = (pcbData ? *pcbData : 0);
  1577. DWORD dwType = (pdwType ? *pdwType : 0); // callers responsibility to set pdwType to the type of pvDefaultData (if they care)
  1578. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  1579. return ERROR_INVALID_PARAMETER;
  1580. if (!fIgnoreHKCU)
  1581. {
  1582. lRet = PrivRegQueryValue(pUSKey, &(pUSKey->hkeyCurrentUser), (LPWSTR)pszValue,
  1583. FALSE, pdwType, pvData, pcbData);
  1584. }
  1585. if (fIgnoreHKCU || ERROR_SUCCESS != lRet)
  1586. {
  1587. if (pcbData)
  1588. *pcbData = dwSize; // We may need to reset if previous open failed.
  1589. lRet = PrivRegQueryValue(pUSKey, &(pUSKey->hkeyLocalMachine), (LPWSTR)pszValue,
  1590. FALSE, pdwType, pvData, pcbData);
  1591. }
  1592. // if fail, use default value.
  1593. if ((ERROR_SUCCESS != lRet) && (pvDefaultData) && (dwDefaultDataSize) &&
  1594. (pvData) && (dwSize >= dwDefaultDataSize))
  1595. {
  1596. MoveMemory(pvData, pvDefaultData, dwDefaultDataSize);
  1597. if (pcbData)
  1598. {
  1599. *pcbData = dwDefaultDataSize;
  1600. }
  1601. if (pdwType)
  1602. {
  1603. *pdwType = dwType;
  1604. }
  1605. lRet = ERROR_SUCCESS; // Call will now use a default value.
  1606. }
  1607. return lRet;
  1608. }
  1609. /*----------------------------------------------------------
  1610. Purpose: Query a user specific registry entry for it's value.
  1611. This will NOT
  1612. open and close the keys in which the value resides.
  1613. The caller needs to do this and it should be done
  1614. when several keys will be queried for a perf increase.
  1615. Callers that only call this once, will probably want
  1616. to call SHGetUSValue().
  1617. Returns: LONG containing success or error code.
  1618. Cond: --
  1619. */
  1620. STDAPI_(LONG)
  1621. SHRegQueryUSValueW(
  1622. IN HUSKEY hUSKey,
  1623. IN LPCWSTR pwzValue,
  1624. OUT LPDWORD pdwType, OPTIONAL
  1625. OUT LPVOID pvData, OPTIONAL
  1626. OUT LPDWORD pcbData, OPTIONAL
  1627. IN BOOL fIgnoreHKCU,
  1628. IN LPVOID pvDefaultData, OPTIONAL
  1629. IN DWORD dwDefaultDataSize) OPTIONAL
  1630. {
  1631. PUSKEY pUSKey = (PUSKEY) hUSKey;
  1632. LONG lRet;
  1633. DWORD dwSize = (pcbData ? *pcbData : 0);
  1634. DWORD dwType = (pdwType ? *pdwType : 0); // callers responsibility to set pdwType to the type of pvDefaultData (if they care)
  1635. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  1636. return ERROR_INVALID_PARAMETER;
  1637. if (!fIgnoreHKCU)
  1638. {
  1639. lRet = PrivRegQueryValue(pUSKey, &(pUSKey->hkeyCurrentUser), pwzValue,
  1640. TRUE, pdwType, pvData, pcbData);
  1641. }
  1642. if (fIgnoreHKCU || ERROR_SUCCESS != lRet)
  1643. {
  1644. if (pcbData)
  1645. *pcbData = dwSize; // We may need to reset if previous open failed.
  1646. lRet = PrivRegQueryValue(pUSKey, &(pUSKey->hkeyLocalMachine), pwzValue,
  1647. TRUE, pdwType, pvData, pcbData);
  1648. }
  1649. // if fail, use default value.
  1650. if ((ERROR_SUCCESS != lRet) && (pvDefaultData) && (dwDefaultDataSize) &&
  1651. (pvData) && (dwSize >= dwDefaultDataSize))
  1652. {
  1653. MoveMemory(pvData, pvDefaultData, dwDefaultDataSize);
  1654. if (pcbData)
  1655. {
  1656. *pcbData = dwDefaultDataSize;
  1657. }
  1658. if (pdwType)
  1659. {
  1660. *pdwType = dwType;
  1661. }
  1662. lRet = ERROR_SUCCESS; // Call will now use a default value.
  1663. }
  1664. return lRet;
  1665. }
  1666. /*----------------------------------------------------------
  1667. Purpose: Write a user specific registry entry.
  1668. Parameters:
  1669. hUSKey - Needs to have been open with KEY_SET_VALUE permissions.
  1670. KEY_QUERY_VALUE also needs to have been used if this is
  1671. not a force write.
  1672. pszValue - Registry Key value to write to.
  1673. dwType - Type for the new registry key.
  1674. pvData - Pointer to data to store
  1675. cbData - Size of data to store.
  1676. dwFlags - Flags to determine if the registry entry should be written to
  1677. HKLM, HKCU, or both. Also determines if these are force or
  1678. non-force writes. (non-force means it will only write the value
  1679. if it's empty) Using FORCE is faster than non-force.
  1680. Decription:
  1681. This function will write the value to the
  1682. registry in either the HKLM or HKCU branches depending
  1683. on the flags set in the dwFlags parameter.
  1684. Returns: LONG containing success or error code.
  1685. Cond: --
  1686. */
  1687. STDAPI_(LONG)
  1688. SHRegWriteUSValueA(
  1689. IN HUSKEY hUSKey,
  1690. IN LPCSTR pszValue,
  1691. IN DWORD dwType,
  1692. IN LPCVOID pvData,
  1693. IN DWORD cbData,
  1694. IN DWORD dwFlags)
  1695. {
  1696. PUSKEY pUSKey = (PUSKEY) hUSKey;
  1697. LONG lRet = ERROR_SUCCESS;
  1698. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  1699. return ERROR_INVALID_PARAMETER;
  1700. // Assert if: 1) This is not a force open, and 2) they key was not
  1701. // opened with KEY_QUERY_VALUE permissions.
  1702. if (!(dwFlags & (SHREGSET_FORCE_HKCU|SHREGSET_FORCE_HKLM)) && !(pUSKey->samDesired & KEY_QUERY_VALUE))
  1703. {
  1704. ASSERT(NULL); // ERROR_INVALID_PARAMETER
  1705. return(ERROR_INVALID_PARAMETER);
  1706. }
  1707. if (dwFlags & (SHREGSET_HKCU | SHREGSET_FORCE_HKCU))
  1708. {
  1709. lRet = PrivRegWriteValue(pUSKey, &(pUSKey->hkeyCurrentUser), (LPWSTR)pszValue,
  1710. FALSE, dwFlags & SHREGSET_FORCE_HKCU, dwType, pvData, cbData);
  1711. }
  1712. if ((dwFlags & (SHREGSET_HKLM | SHREGSET_FORCE_HKLM)) && (ERROR_SUCCESS == lRet))
  1713. {
  1714. lRet = PrivRegWriteValue(pUSKey, &(pUSKey->hkeyLocalMachine), (LPWSTR)pszValue,
  1715. FALSE, dwFlags & SHREGSET_FORCE_HKLM, dwType, pvData, cbData);
  1716. }
  1717. return lRet;
  1718. }
  1719. /*----------------------------------------------------------
  1720. Purpose: Write a user specific registry entry.
  1721. Parameters:
  1722. hUSKey - Needs to have been open with KEY_SET_VALUE permissions.
  1723. KEY_QUERY_VALUE also needs to have been used if this is
  1724. not a force write.
  1725. pszValue - Registry Key value to write to.
  1726. dwType - Type for the new registry key.
  1727. pvData - Pointer to data to store
  1728. cbData - Size of data to store.
  1729. dwFlags - Flags to determine if the registry entry should be written to
  1730. HKLM, HKCU, or both. Also determines if these are force or
  1731. non-force writes. (non-force means it will only write the value
  1732. if it's empty) Using FORCE is faster than non-force.
  1733. Decription:
  1734. This function will write the value to the
  1735. registry in either the HKLM or HKCU branches depending
  1736. on the flags set in the dwFlags parameter.
  1737. Returns: LONG containing success or error code.
  1738. Cond: --
  1739. */
  1740. STDAPI_(LONG)
  1741. SHRegWriteUSValueW(
  1742. IN HUSKEY hUSKey,
  1743. IN LPCWSTR pwzValue,
  1744. IN DWORD dwType,
  1745. IN LPCVOID pvData,
  1746. IN DWORD cbData,
  1747. IN DWORD dwFlags)
  1748. {
  1749. PUSKEY pUSKey = (PUSKEY) hUSKey;
  1750. LONG lRet = ERROR_SUCCESS;
  1751. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  1752. return ERROR_INVALID_PARAMETER;
  1753. // Assert if: 1) This is not a force open, and 2) they key was not
  1754. // opened with access permissions.
  1755. if (!(dwFlags & (SHREGSET_FORCE_HKCU|SHREGSET_FORCE_HKLM)) && !(pUSKey->samDesired & KEY_QUERY_VALUE))
  1756. {
  1757. ASSERT(NULL); // ERROR_INVALID_PARAMETER
  1758. return(ERROR_INVALID_PARAMETER);
  1759. }
  1760. if (dwFlags & (SHREGSET_HKCU | SHREGSET_FORCE_HKCU))
  1761. {
  1762. lRet = PrivRegWriteValue(pUSKey, &(pUSKey->hkeyCurrentUser), (LPWSTR)pwzValue,
  1763. TRUE, dwFlags & SHREGSET_FORCE_HKCU, dwType, pvData, cbData);
  1764. }
  1765. if (dwFlags & (SHREGSET_HKLM | SHREGSET_FORCE_HKLM))
  1766. {
  1767. lRet = PrivRegWriteValue(pUSKey, &(pUSKey->hkeyLocalMachine), (LPWSTR)pwzValue,
  1768. TRUE, dwFlags & SHREGSET_FORCE_HKLM, dwType, pvData, cbData);
  1769. }
  1770. return lRet;
  1771. }
  1772. /*----------------------------------------------------------
  1773. Purpose: Deletes a registry value. This will delete HKLM,
  1774. HKCU, or both depending on the hkey parameter.
  1775. Returns: LONG containing success or error code.
  1776. Cond: --
  1777. */
  1778. STDAPI_(LONG)
  1779. SHRegDeleteUSValueA(
  1780. IN HUSKEY hUSKey,
  1781. IN LPCSTR pszValue,
  1782. IN SHREGDEL_FLAGS delRegFlags) // (HKLM, HKCU, or (HKLM | HKCU))
  1783. {
  1784. PUSKEY pUSKey = (PUSKEY) hUSKey;
  1785. LONG lRet = ERROR_INVALID_PARAMETER;
  1786. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  1787. return ERROR_INVALID_PARAMETER;
  1788. if (SHREGDEL_DEFAULT == delRegFlags) // Delete whatever keys are open
  1789. {
  1790. if (!pUSKey->hkeyCurrentUser) // Attempt to open HKCU if not currently open
  1791. lRet = PrivFullOpen(pUSKey);
  1792. if (pUSKey->hkeyCurrentUser)
  1793. delRegFlags = SHREGDEL_HKCU;
  1794. else
  1795. {
  1796. // We prefer to delete HKCU, but we got here, so we will delete HKLM
  1797. // if it is open.
  1798. if (pUSKey->hkeyLocalMachine)
  1799. delRegFlags = SHREGDEL_HKLM;
  1800. }
  1801. }
  1802. if (IsFlagSet(delRegFlags, SHREGDEL_HKCU)) // Check if the call wants to delete the HKLM value.
  1803. {
  1804. if (!pUSKey->hkeyCurrentUser)
  1805. PrivFullOpen(pUSKey);
  1806. if (pUSKey->hkeyCurrentUser)
  1807. {
  1808. lRet = RegDeleteValueA(pUSKey->hkeyCurrentUser, pszValue);
  1809. if (ERROR_FILE_NOT_FOUND == lRet)
  1810. delRegFlags = SHREGDEL_HKLM; // Delete the HKLM value if the HKCU value wasn't found.
  1811. }
  1812. }
  1813. if (IsFlagSet(delRegFlags, SHREGDEL_HKLM)) // Check if the call wants to delete the HKLM value.
  1814. {
  1815. if (!pUSKey->hkeyLocalMachine)
  1816. PrivFullOpen(pUSKey);
  1817. if (pUSKey->hkeyLocalMachine)
  1818. lRet = RegDeleteValueA(pUSKey->hkeyLocalMachine, pszValue);
  1819. }
  1820. return lRet;
  1821. }
  1822. /*----------------------------------------------------------
  1823. Purpose: Deletes a registry value. This will delete HKLM,
  1824. HKCU, or both depending on the hkey parameter.
  1825. Returns: LONG containing success or error code.
  1826. Cond: --
  1827. */
  1828. STDAPI_(LONG)
  1829. SHRegDeleteUSValueW(
  1830. IN HUSKEY hUSKey,
  1831. IN LPCWSTR pwzValue,
  1832. IN SHREGDEL_FLAGS delRegFlags) // (HKLM, HKCU, or (HKLM | HKCU))
  1833. {
  1834. CHAR szNewPath[MAXIMUM_VALUE_NAME_LENGTH];
  1835. // Thunk Path to Wide chars.
  1836. if (FALSE == WideCharToMultiByte(CP_ACP, 0, pwzValue, -1, szNewPath, sizeof(szNewPath), NULL, 0))
  1837. return GetLastError();
  1838. return SHRegDeleteUSValueA(hUSKey, szNewPath, delRegFlags);
  1839. }
  1840. /*----------------------------------------------------------
  1841. Purpose: Deletes a registry sub-key if empty. This will delete HKLM,
  1842. HKCU, or both depending on the delRegFlags parameter.
  1843. Returns: LONG containing success or error code.
  1844. Cond: --
  1845. */
  1846. STDAPI_(LONG)
  1847. SHRegDeleteEmptyUSKeyA(
  1848. IN HUSKEY hUSKey,
  1849. IN LPCSTR pszSubKey,
  1850. IN SHREGDEL_FLAGS delRegFlags) // (HKLM, HKCU, or (HKLM | HKCU))
  1851. {
  1852. PUSKEY pUSKey = (PUSKEY) hUSKey;
  1853. LONG lRet = ERROR_INVALID_PARAMETER;
  1854. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  1855. return ERROR_INVALID_PARAMETER;
  1856. if (SHREGDEL_DEFAULT == delRegFlags) // Delete whatever keys are open
  1857. {
  1858. if (!pUSKey->hkeyCurrentUser) // Attempt to open HKCU if not currently open
  1859. lRet = PrivFullOpen(pUSKey);
  1860. if (pUSKey->hkeyCurrentUser)
  1861. delRegFlags = SHREGDEL_HKCU;
  1862. else
  1863. {
  1864. // We prefer to delete HKCU, but we got here, so we will delete HKLM
  1865. // if it is open.
  1866. if (pUSKey->hkeyLocalMachine)
  1867. delRegFlags = SHREGDEL_HKLM;
  1868. }
  1869. }
  1870. if (IsFlagSet(delRegFlags, SHREGDEL_HKCU)) // Check if the call wants to delete the HKLM key.
  1871. {
  1872. if (!pUSKey->hkeyCurrentUser)
  1873. PrivFullOpen(pUSKey);
  1874. if (pUSKey->hkeyCurrentUser)
  1875. {
  1876. lRet = SHDeleteEmptyKeyA(pUSKey->hkeyCurrentUser, pszSubKey);
  1877. if (ERROR_FILE_NOT_FOUND == lRet)
  1878. delRegFlags = SHREGDEL_HKLM; // Delete the HKLM key if the HKCU key wasn't found.
  1879. }
  1880. }
  1881. if (IsFlagSet(delRegFlags, SHREGDEL_HKLM)) // Check if the call wants to delete the HKLM key.
  1882. {
  1883. if (!pUSKey->hkeyLocalMachine)
  1884. PrivFullOpen(pUSKey);
  1885. if (pUSKey->hkeyLocalMachine)
  1886. lRet = SHDeleteEmptyKeyA(pUSKey->hkeyLocalMachine, pszSubKey);
  1887. }
  1888. return lRet;
  1889. }
  1890. /*----------------------------------------------------------
  1891. Purpose: Deletes a registry key if empty. This will delete HKLM,
  1892. HKCU, or both depending on the delRegFlags parameter.
  1893. Returns: LONG containing success or error code.
  1894. Cond: --
  1895. */
  1896. STDAPI_(LONG)
  1897. SHRegDeleteEmptyUSKeyW(
  1898. IN HUSKEY hUSKey,
  1899. IN LPCWSTR pwzSubKey,
  1900. IN SHREGDEL_FLAGS delRegFlags) // (HKLM, HKCU, or (HKLM | HKCU))
  1901. {
  1902. CHAR szNewPath[MAXIMUM_SUB_KEY_LENGTH];
  1903. // Thunk Path to Wide chars.
  1904. if (FALSE == WideCharToMultiByte(CP_ACP, 0, pwzSubKey, -1, szNewPath, sizeof(szNewPath), NULL, 0))
  1905. return GetLastError();
  1906. return SHRegDeleteEmptyUSKeyA(hUSKey, szNewPath, delRegFlags);
  1907. }
  1908. /*----------------------------------------------------------
  1909. Purpose: Enumerates sub-keys under a given HUSKEY.
  1910. SHREGENUM_FLAGS specifies how to do the enumeration.
  1911. SHREGENUM_DEFAULT - Will look in HKCU followed by HKLM if not found.
  1912. SHREGENUM_HKCU - Enumerates HKCU only.
  1913. SHREGENUM_HKLM = Enumerates HKLM only.
  1914. SHREGENUM_BOTH - This is supposed to do a union of the HKLM and HKCU subkeys.
  1915. Returns: LONG containing success or error code.
  1916. Cond: --
  1917. */
  1918. STDAPI_(LONG)
  1919. SHRegEnumUSKeyA(
  1920. IN HUSKEY hUSKey,
  1921. IN DWORD dwIndex,
  1922. OUT LPSTR pszName,
  1923. IN LPDWORD pcchName,
  1924. IN SHREGENUM_FLAGS enumRegFlags) // (HKLM, HKCU, or (HKLM | HKCU))
  1925. {
  1926. PUSKEY pUSKey = (PUSKEY) hUSKey;
  1927. LONG lRet = ERROR_INVALID_PARAMETER;
  1928. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  1929. return ERROR_INVALID_PARAMETER;
  1930. if (SHREGENUM_BOTH == enumRegFlags)
  1931. {
  1932. // This is not supported yet.
  1933. ASSERT(FALSE);
  1934. return ERROR_CALL_NOT_IMPLEMENTED;
  1935. }
  1936. if (SHREGENUM_HKCU != enumRegFlags && SHREGENUM_HKLM != enumRegFlags && SHREGENUM_DEFAULT != enumRegFlags)
  1937. {
  1938. // check your arguments.
  1939. ASSERT(FALSE);
  1940. return ERROR_INVALID_PARAMETER;
  1941. }
  1942. // Default is to try HKCU first.
  1943. if (SHREGENUM_HKCU == enumRegFlags || SHREGENUM_DEFAULT == enumRegFlags)
  1944. {
  1945. lRet = PrivRegEnumKey(pUSKey, &(pUSKey->hkeyCurrentUser), dwIndex,
  1946. (LPWSTR)pszName, FALSE, pcchName);
  1947. }
  1948. if ((SHREGENUM_HKLM == enumRegFlags) ||
  1949. ((SHREGENUM_DEFAULT == enumRegFlags) && ((ERROR_SUCCESS != lRet) && (ERROR_MORE_DATA != lRet) && (ERROR_NO_MORE_ITEMS != lRet))))
  1950. {
  1951. lRet = PrivRegEnumKey(pUSKey, &(pUSKey->hkeyLocalMachine), dwIndex,
  1952. (LPWSTR)pszName, FALSE, pcchName);
  1953. }
  1954. return lRet;
  1955. }
  1956. /*----------------------------------------------------------
  1957. Purpose: Enumerates sub-keys under a given HUSKEY.
  1958. SHREGENUM_FLAGS specifies how to do the enumeration.
  1959. SHREGENUM_DEFAULT - Will look in HKCU followed by HKLM if not found.
  1960. SHREGENUM_HKCU - Enumerates HKCU only.
  1961. SHREGENUM_HKLM = Enumerates HKLM only.
  1962. SHREGENUM_BOTH - This is supposed to do a union of the HKLM and HKCU subkeys.
  1963. Returns: LONG containing success or error code.
  1964. Cond: --
  1965. */
  1966. STDAPI_(LONG)
  1967. SHRegEnumUSKeyW(
  1968. IN HUSKEY hUSKey,
  1969. IN DWORD dwIndex,
  1970. OUT LPWSTR pszName,
  1971. IN LPDWORD pcchName,
  1972. IN SHREGENUM_FLAGS enumRegFlags) // (HKLM, HKCU, or (HKLM | HKCU))
  1973. {
  1974. PUSKEY pUSKey = (PUSKEY) hUSKey;
  1975. LONG lRet = ERROR_INVALID_PARAMETER;
  1976. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  1977. return ERROR_INVALID_PARAMETER;
  1978. if (SHREGENUM_BOTH == enumRegFlags)
  1979. {
  1980. // This is not supported yet.
  1981. ASSERT(FALSE);
  1982. return ERROR_CALL_NOT_IMPLEMENTED;
  1983. }
  1984. if (SHREGENUM_HKCU != enumRegFlags && SHREGENUM_HKLM != enumRegFlags && SHREGENUM_DEFAULT != enumRegFlags)
  1985. {
  1986. // check your arguments.
  1987. ASSERT(FALSE);
  1988. return ERROR_INVALID_PARAMETER;
  1989. }
  1990. // Default is to try HKCU first.
  1991. if (SHREGENUM_HKCU == enumRegFlags || SHREGENUM_DEFAULT == enumRegFlags)
  1992. {
  1993. lRet = PrivRegEnumKey(pUSKey, &(pUSKey->hkeyCurrentUser), dwIndex,
  1994. pszName, TRUE, pcchName);
  1995. }
  1996. if ((SHREGENUM_HKLM == enumRegFlags) ||
  1997. ((SHREGENUM_DEFAULT == enumRegFlags) && ((ERROR_SUCCESS != lRet) && (ERROR_MORE_DATA != lRet) && (ERROR_NO_MORE_ITEMS != lRet))))
  1998. {
  1999. lRet = PrivRegEnumKey(pUSKey, &(pUSKey->hkeyLocalMachine), dwIndex,
  2000. pszName, TRUE, pcchName);
  2001. }
  2002. return lRet;
  2003. }
  2004. /*----------------------------------------------------------
  2005. Purpose: Enumerates Values under a given HUSKEY.
  2006. SHREGENUM_FLAGS specifies how to do the enumeration.
  2007. SHREGENUM_DEFAULT - Will look in HKCU followed by HKLM if not found.
  2008. SHREGENUM_HKCU - Enumerates HKCU only.
  2009. SHREGENUM_HKLM = Enumerates HKLM only.
  2010. SHREGENUM_BOTH - This is supposed to do a union of the HKLM and HKCU subkeys.
  2011. Returns: LONG containing success or error code.
  2012. Cond: --
  2013. */
  2014. STDAPI_(LONG)
  2015. SHRegEnumUSValueA(
  2016. IN HUSKEY hUSKey,
  2017. IN DWORD dwIndex,
  2018. OUT LPSTR pszValueName,
  2019. IN LPDWORD pcchValueNameLen,
  2020. OUT LPDWORD pdwType, OPTIONAL
  2021. OUT LPVOID pvData, OPTIONAL
  2022. OUT LPDWORD pcbData, OPTIONAL
  2023. IN SHREGENUM_FLAGS enumRegFlags) // (HKLM, HKCU, or (HKLM | HKCU))
  2024. {
  2025. PUSKEY pUSKey = (PUSKEY) hUSKey;
  2026. LONG lRet = ERROR_INVALID_PARAMETER;
  2027. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  2028. return ERROR_INVALID_PARAMETER;
  2029. if (SHREGENUM_BOTH == enumRegFlags)
  2030. {
  2031. // This is not supported yet.
  2032. ASSERT(FALSE);
  2033. return ERROR_CALL_NOT_IMPLEMENTED;
  2034. }
  2035. if (SHREGENUM_HKCU != enumRegFlags && SHREGENUM_HKLM != enumRegFlags && SHREGENUM_DEFAULT != enumRegFlags)
  2036. {
  2037. // check your arguments.
  2038. ASSERT(FALSE);
  2039. return ERROR_INVALID_PARAMETER;
  2040. }
  2041. // Default is to try HKCU first.
  2042. if (SHREGENUM_HKCU == enumRegFlags || SHREGENUM_DEFAULT == enumRegFlags)
  2043. {
  2044. lRet = PrivRegEnumValue(pUSKey, &(pUSKey->hkeyCurrentUser), dwIndex,
  2045. (LPWSTR)pszValueName, FALSE, pcchValueNameLen, pdwType, pvData, pcbData);
  2046. }
  2047. if ((SHREGENUM_HKLM == enumRegFlags) ||
  2048. ((SHREGENUM_DEFAULT == enumRegFlags) && ((ERROR_SUCCESS != lRet) && (ERROR_MORE_DATA != lRet) && (ERROR_NO_MORE_ITEMS != lRet))))
  2049. {
  2050. lRet = PrivRegEnumValue(pUSKey, &(pUSKey->hkeyLocalMachine), dwIndex,
  2051. (LPWSTR)pszValueName, FALSE, pcchValueNameLen, pdwType, pvData, pcbData);
  2052. }
  2053. return lRet;
  2054. }
  2055. /*----------------------------------------------------------
  2056. Purpose: Enumerates Values under a given HUSKEY.
  2057. SHREGENUM_FLAGS specifies how to do the enumeration.
  2058. SHREGENUM_DEFAULT - Will look in HKCU followed by HKLM if not found.
  2059. SHREGENUM_HKCU - Enumerates HKCU only.
  2060. SHREGENUM_HKLM = Enumerates HKLM only.
  2061. SHREGENUM_BOTH - This is supposed to do a union of the HKLM and HKCU subkeys.
  2062. Returns: LONG containing success or error code.
  2063. Cond: --
  2064. */
  2065. STDAPI_(LONG)
  2066. SHRegEnumUSValueW(
  2067. IN HUSKEY hUSKey,
  2068. IN DWORD dwIndex,
  2069. OUT LPWSTR pszValueName,
  2070. IN LPDWORD pcchValueNameLen,
  2071. OUT LPDWORD pdwType, OPTIONAL
  2072. OUT LPVOID pvData, OPTIONAL
  2073. OUT LPDWORD pcbData, OPTIONAL
  2074. IN SHREGENUM_FLAGS enumRegFlags) // (HKLM, HKCU, or (HKLM | HKCU))
  2075. {
  2076. PUSKEY pUSKey = (PUSKEY) hUSKey;
  2077. LONG lRet = ERROR_INVALID_PARAMETER;
  2078. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  2079. return ERROR_INVALID_PARAMETER;
  2080. if (SHREGENUM_BOTH == enumRegFlags)
  2081. {
  2082. // This is not supported yet.
  2083. ASSERT(FALSE);
  2084. return ERROR_CALL_NOT_IMPLEMENTED;
  2085. }
  2086. if (SHREGENUM_HKCU != enumRegFlags && SHREGENUM_HKLM != enumRegFlags && SHREGENUM_DEFAULT != enumRegFlags)
  2087. {
  2088. // check your arguments.
  2089. ASSERT(FALSE);
  2090. return ERROR_INVALID_PARAMETER;
  2091. }
  2092. // Default is to try HKCU first.
  2093. if (SHREGENUM_HKCU == enumRegFlags || SHREGENUM_DEFAULT == enumRegFlags)
  2094. {
  2095. lRet = PrivRegEnumValue(pUSKey, &(pUSKey->hkeyCurrentUser), dwIndex,
  2096. pszValueName, TRUE, pcchValueNameLen, pdwType, pvData, pcbData);
  2097. }
  2098. if ((SHREGENUM_HKLM == enumRegFlags) ||
  2099. ((SHREGENUM_DEFAULT == enumRegFlags) && ((ERROR_SUCCESS != lRet) && (ERROR_MORE_DATA != lRet) && (ERROR_NO_MORE_ITEMS != lRet))))
  2100. {
  2101. lRet = PrivRegEnumValue(pUSKey, &(pUSKey->hkeyLocalMachine), dwIndex,
  2102. pszValueName, TRUE, pcchValueNameLen, pdwType, pvData, pcbData);
  2103. }
  2104. return lRet;
  2105. }
  2106. /*----------------------------------------------------------
  2107. Purpose: Gets Info about a HUSKEY.
  2108. Re-uses same flags as enumeration functions.
  2109. Look at SHRegEnumKeyExA for an explanation of the flags.
  2110. Returns: LONG containing success or error code.
  2111. Cond: --
  2112. */
  2113. STDAPI_(LONG)
  2114. SHRegQueryInfoUSKeyA
  2115. (
  2116. IN HUSKEY hUSKey,
  2117. OUT LPDWORD pcSubKeys, OPTIONAL
  2118. OUT LPDWORD pcchMaxSubKeyLen, OPTIONAL
  2119. OUT LPDWORD pcValues, OPTIONAL
  2120. OUT LPDWORD pcchMaxValueNameLen, OPTIONAL
  2121. IN SHREGENUM_FLAGS enumRegFlags
  2122. )
  2123. {
  2124. PUSKEY pUSKey = (PUSKEY) hUSKey;
  2125. LONG lRet = ERROR_INVALID_PARAMETER;
  2126. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  2127. return ERROR_INVALID_PARAMETER;
  2128. if (SHREGENUM_BOTH == enumRegFlags)
  2129. {
  2130. // This is not supported yet.
  2131. ASSERT(FALSE);
  2132. return ERROR_CALL_NOT_IMPLEMENTED;
  2133. }
  2134. if (SHREGENUM_HKCU != enumRegFlags && SHREGENUM_HKLM != enumRegFlags && SHREGENUM_DEFAULT != enumRegFlags)
  2135. {
  2136. // check your arguments.
  2137. ASSERT(FALSE);
  2138. return ERROR_INVALID_PARAMETER;
  2139. }
  2140. // Default is to try HKCU first.
  2141. if (SHREGENUM_HKCU == enumRegFlags || SHREGENUM_DEFAULT == enumRegFlags)
  2142. {
  2143. lRet = PrivRegQueryInfoKey(pUSKey, &(pUSKey->hkeyCurrentUser), FALSE,
  2144. pcSubKeys, pcchMaxSubKeyLen, pcValues, pcchMaxValueNameLen);
  2145. }
  2146. if ((SHREGENUM_HKLM == enumRegFlags) ||
  2147. ((SHREGENUM_DEFAULT == enumRegFlags) && ((ERROR_SUCCESS != lRet) && (ERROR_MORE_DATA != lRet))))
  2148. {
  2149. lRet = PrivRegQueryInfoKey(pUSKey, &(pUSKey->hkeyLocalMachine), FALSE,
  2150. pcSubKeys, pcchMaxSubKeyLen, pcValues, pcchMaxValueNameLen);
  2151. }
  2152. return lRet;
  2153. }
  2154. /*----------------------------------------------------------
  2155. Purpose: Gets Info about a HUSKEY.
  2156. Re-uses same flags as enumeration functions.
  2157. Look at SHRegEnumKeyExA for an explanation of the flags.
  2158. Returns: LONG containing success or error code.
  2159. Cond: --
  2160. */
  2161. STDAPI_(LONG)
  2162. SHRegQueryInfoUSKeyW
  2163. (
  2164. IN HUSKEY hUSKey,
  2165. OUT LPDWORD pcSubKeys, OPTIONAL
  2166. OUT LPDWORD pcchMaxSubKeyLen, OPTIONAL
  2167. OUT LPDWORD pcValues, OPTIONAL
  2168. OUT LPDWORD pcchMaxValueNameLen, OPTIONAL
  2169. IN SHREGENUM_FLAGS enumRegFlags
  2170. )
  2171. {
  2172. PUSKEY pUSKey = (PUSKEY) hUSKey;
  2173. LONG lRet = ERROR_INVALID_PARAMETER;
  2174. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  2175. return ERROR_INVALID_PARAMETER;
  2176. if (SHREGENUM_BOTH == enumRegFlags)
  2177. {
  2178. // This is not supported yet.
  2179. ASSERT(FALSE);
  2180. return ERROR_CALL_NOT_IMPLEMENTED;
  2181. }
  2182. if (SHREGENUM_HKCU != enumRegFlags && SHREGENUM_HKLM != enumRegFlags && SHREGENUM_DEFAULT != enumRegFlags)
  2183. {
  2184. // check your arguments.
  2185. ASSERT(FALSE);
  2186. return ERROR_INVALID_PARAMETER;
  2187. }
  2188. // Default is to try HKCU first.
  2189. if (SHREGENUM_HKCU == enumRegFlags || SHREGENUM_DEFAULT == enumRegFlags)
  2190. {
  2191. lRet = PrivRegQueryInfoKey(pUSKey, &(pUSKey->hkeyCurrentUser), TRUE,
  2192. pcSubKeys, pcchMaxSubKeyLen, pcValues, pcchMaxValueNameLen);
  2193. }
  2194. if ((SHREGENUM_HKLM == enumRegFlags) ||
  2195. ((SHREGENUM_DEFAULT == enumRegFlags) && ((ERROR_SUCCESS != lRet) && (ERROR_MORE_DATA != lRet))))
  2196. {
  2197. lRet = PrivRegQueryInfoKey(pUSKey, &(pUSKey->hkeyLocalMachine), TRUE,
  2198. pcSubKeys, pcchMaxSubKeyLen, pcValues, pcchMaxValueNameLen);
  2199. }
  2200. return lRet;
  2201. }
  2202. /*----------------------------------------------------------
  2203. Purpose: Closes a HUSKEY (Handle to a User Specifc registry key).
  2204. Returns: LONG containing success or error code.
  2205. Cond: --
  2206. */
  2207. STDAPI_(LONG)
  2208. SHRegCloseUSKey(
  2209. OUT HUSKEY hUSKey)
  2210. {
  2211. PUSKEY pUSKey = (PUSKEY) hUSKey;
  2212. LONG lRet = ERROR_SUCCESS;
  2213. ASSERT(pUSKey);
  2214. if (FALSE == IS_HUSKEY_VALID(pUSKey))
  2215. return ERROR_INVALID_PARAMETER;
  2216. if (pUSKey->hkeyLocalMachine)
  2217. {
  2218. lRet = RegCloseKey(pUSKey->hkeyLocalMachine);
  2219. pUSKey->hkeyLocalMachine = NULL; // Used to indicate that it's invalid.
  2220. }
  2221. if (pUSKey->hkeyLocalMachineRelative && HKEY_LOCAL_MACHINE != pUSKey->hkeyLocalMachineRelative)
  2222. {
  2223. lRet = RegCloseKey(pUSKey->hkeyLocalMachineRelative);
  2224. }
  2225. if (pUSKey->hkeyCurrentUser)
  2226. {
  2227. lRet = RegCloseKey(pUSKey->hkeyCurrentUser);
  2228. pUSKey->hkeyCurrentUser = NULL; // Used to indicate that it's invalid.
  2229. }
  2230. if (pUSKey->hkeyCurrentUserRelative && HKEY_CURRENT_USER != pUSKey->hkeyCurrentUserRelative)
  2231. {
  2232. lRet = RegCloseKey(pUSKey->hkeyCurrentUserRelative);
  2233. }
  2234. LocalFree((HLOCAL)pUSKey);
  2235. return lRet;
  2236. }
  2237. /*----------------------------------------------------------
  2238. Purpose: Gets a registry value that is User Specifc.
  2239. This opens and closes the key in which the value resides.
  2240. Perf: if your code involves setting/getting a series
  2241. of values in the same key, it is better to open
  2242. the key once and then call SHRegQueryUSValue
  2243. rather than using this function repeatedly.
  2244. Returns: LONG containing success or error code.
  2245. Cond: --
  2246. */
  2247. STDAPI_(LONG)
  2248. SHRegGetUSValueA(
  2249. IN LPCSTR pszSubKey,
  2250. IN LPCSTR pszValue,
  2251. OUT LPDWORD pdwType, OPTIONAL
  2252. OUT LPVOID pvData, OPTIONAL
  2253. OUT LPDWORD pcbData, OPTIONAL
  2254. IN BOOL fIgnoreHKCU,
  2255. IN LPVOID pvDefaultData, OPTIONAL
  2256. IN DWORD dwDefaultDataSize)
  2257. {
  2258. LONG lRet;
  2259. HUSKEY hUSkeys;
  2260. DWORD dwInitialSize = (pcbData ? *pcbData : 0);
  2261. DWORD dwType = (pdwType ? *pdwType : 0); // callers responsibility to set pdwType to the type of pvDefaultData (if they care)
  2262. lRet = SHRegOpenUSKeyA(pszSubKey, KEY_QUERY_VALUE, NULL, &hUSkeys, fIgnoreHKCU);
  2263. if (ERROR_SUCCESS == lRet)
  2264. {
  2265. lRet = SHRegQueryUSValueA(hUSkeys, pszValue, pdwType, pvData, pcbData, fIgnoreHKCU, pvDefaultData, dwDefaultDataSize);
  2266. SHRegCloseUSKey(hUSkeys);
  2267. }
  2268. if (ERROR_SUCCESS != lRet)
  2269. {
  2270. // if fail on open OR on query, use default value as long as dwDefaultDataSize isn't 0. (So we return the error)
  2271. if ((pvDefaultData) && (dwDefaultDataSize) && (pvData) && (dwInitialSize >= dwDefaultDataSize))
  2272. {
  2273. MoveMemory(pvData, pvDefaultData, dwDefaultDataSize);
  2274. if (pcbData)
  2275. {
  2276. *pcbData = dwDefaultDataSize;
  2277. }
  2278. if (pdwType)
  2279. {
  2280. *pdwType = dwType;
  2281. }
  2282. lRet = ERROR_SUCCESS; // Call will now use a default value.
  2283. }
  2284. }
  2285. return lRet;
  2286. }
  2287. /*----------------------------------------------------------
  2288. Purpose: Gets a registry value that is User Specifc.
  2289. This opens and closes the key in which the value resides.
  2290. Perf: if your code involves setting/getting a series
  2291. of values in the same key, it is better to open
  2292. the key once and then call SHRegQueryUSValue
  2293. rather than using this function repeatedly.
  2294. Returns: LONG containing success or error code.
  2295. Cond: --
  2296. */
  2297. STDAPI_(LONG)
  2298. SHRegGetUSValueW(
  2299. IN LPCWSTR pwzSubKey,
  2300. IN LPCWSTR pwzValue,
  2301. OUT LPDWORD pdwType, OPTIONAL
  2302. OUT LPVOID pvData, OPTIONAL
  2303. OUT LPDWORD pcbData, OPTIONAL
  2304. IN BOOL fIgnoreHKCU,
  2305. IN LPVOID pvDefaultData, OPTIONAL
  2306. IN DWORD dwDefaultDataSize)
  2307. {
  2308. LONG lRet;
  2309. HUSKEY hUSkeys;
  2310. DWORD dwInitialSize = (pcbData ? *pcbData : 0);
  2311. DWORD dwType = (pdwType ? *pdwType : 0); // callers responsibility to set pdwType to the type of pvDefaultData (if they care)
  2312. lRet = SHRegOpenUSKeyW(pwzSubKey, KEY_QUERY_VALUE, NULL, &hUSkeys, fIgnoreHKCU);
  2313. if (ERROR_SUCCESS == lRet)
  2314. {
  2315. lRet = SHRegQueryUSValueW(hUSkeys, pwzValue, pdwType, pvData, pcbData, fIgnoreHKCU, pvDefaultData, dwDefaultDataSize);
  2316. SHRegCloseUSKey(hUSkeys);
  2317. }
  2318. if (ERROR_SUCCESS != lRet)
  2319. {
  2320. // if fail on open OR on query, use default value as long as dwDefaultDataSize isn't 0. (So we return the error)
  2321. if ((pvDefaultData) && (dwDefaultDataSize) && (pvData) && (dwInitialSize >= dwDefaultDataSize))
  2322. {
  2323. // if fail, use default value.
  2324. MoveMemory(pvData, pvDefaultData, dwDefaultDataSize);
  2325. if (pcbData)
  2326. {
  2327. *pcbData = dwDefaultDataSize;
  2328. }
  2329. if (pdwType)
  2330. {
  2331. *pdwType = dwType;
  2332. }
  2333. lRet = ERROR_SUCCESS; // Call will now use a default value.
  2334. }
  2335. }
  2336. return lRet;
  2337. }
  2338. /*----------------------------------------------------------
  2339. Purpose: Sets a registry value that is User Specifc.
  2340. This opens and closes the key in which the value resides.
  2341. Perf: if your code involves setting a series
  2342. of values in the same key, it is better to open
  2343. the key once and then call SHRegWriteUSValue
  2344. rather than using this function repeatedly.
  2345. Returns: LONG containing success or error code.
  2346. Cond: --
  2347. */
  2348. STDAPI_(LONG)
  2349. SHRegSetUSValueA(
  2350. IN LPCSTR pszSubKey,
  2351. IN LPCSTR pszValue,
  2352. IN DWORD dwType,
  2353. IN LPCVOID pvData, OPTIONAL
  2354. IN DWORD cbData, OPTIONAL
  2355. IN DWORD dwFlags) OPTIONAL
  2356. {
  2357. LONG lRet;
  2358. HUSKEY hUSkeys;
  2359. lRet = SHRegCreateUSKeyA(pszSubKey, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hUSkeys, dwFlags);
  2360. if (ERROR_SUCCESS == lRet)
  2361. {
  2362. lRet = SHRegWriteUSValueA(hUSkeys, pszValue, dwType, pvData, cbData, dwFlags);
  2363. SHRegCloseUSKey(hUSkeys);
  2364. }
  2365. return lRet;
  2366. }
  2367. /*----------------------------------------------------------
  2368. Purpose: Sets a registry value that is User Specifc.
  2369. This opens and closes the key in which the value resides.
  2370. Perf: if your code involves setting a series
  2371. of values in the same key, it is better to open
  2372. the key once and then call SHRegWriteUSValue
  2373. rather than using this function repeatedly.
  2374. Returns: LONG containing success or error code.
  2375. Cond: --
  2376. */
  2377. STDAPI_(LONG)
  2378. SHRegSetUSValueW(
  2379. IN LPCWSTR pwzSubKey,
  2380. IN LPCWSTR pwzValue,
  2381. IN DWORD dwType, OPTIONAL
  2382. IN LPCVOID pvData, OPTIONAL
  2383. IN DWORD cbData, OPTIONAL
  2384. IN DWORD dwFlags) OPTIONAL
  2385. {
  2386. LONG lRet;
  2387. HUSKEY hUSkeys;
  2388. lRet = SHRegCreateUSKeyW(pwzSubKey, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hUSkeys, dwFlags);
  2389. if (ERROR_SUCCESS == lRet)
  2390. {
  2391. lRet = SHRegWriteUSValueW(hUSkeys, pwzValue, dwType, pvData, cbData, dwFlags);
  2392. SHRegCloseUSKey(hUSkeys);
  2393. }
  2394. return lRet;
  2395. }
  2396. /*----------------------------------------------------------
  2397. Purpose: Gets a BOOL Setting from the registry. The default
  2398. parameter will be used if it's not found in the registry.
  2399. Cond: --
  2400. */
  2401. #define BOOLSETTING_BOOL_TRUE1W L"YES"
  2402. #define BOOLSETTING_BOOL_TRUE1A "YES"
  2403. #define BOOLSETTING_BOOL_TRUE2W L"TRUE"
  2404. #define BOOLSETTING_BOOL_TRUE2A "TRUE"
  2405. #define BOOLSETTING_BOOL_FALSE1W L"NO"
  2406. #define BOOLSETTING_BOOL_FALSE1A "NO"
  2407. #define BOOLSETTING_BOOL_FALSE2W L"FALSE"
  2408. #define BOOLSETTING_BOOL_FALSE2A "FALSE"
  2409. #define BOOLSETTING_BOOL_1W L"1"
  2410. #define BOOLSETTING_BOOL_1A "1"
  2411. #define BOOLSETTING_BOOL_0W L"0"
  2412. #define BOOLSETTING_BOOL_0A "0"
  2413. STDAPI_(BOOL)
  2414. SHRegGetBoolUSValueW(
  2415. IN LPCWSTR pwzSubKey,
  2416. IN LPCWSTR pwzValue,
  2417. IN BOOL fIgnoreHKCU,
  2418. IN BOOL fDefault)
  2419. {
  2420. LONG lRet;
  2421. WCHAR szData[MAX_PATH];
  2422. DWORD dwType = REG_SZ; //because the default value we pass in is a string.
  2423. DWORD dwSize = sizeof(szData);
  2424. LPCWSTR pszDefault = fDefault ? BOOLSETTING_BOOL_TRUE1W : BOOLSETTING_BOOL_FALSE1W;
  2425. DWORD dwDefaultSize = fDefault ? sizeof(BOOLSETTING_BOOL_TRUE1W) : sizeof(BOOLSETTING_BOOL_FALSE1W); // sizeof() includes terminating NULL
  2426. lRet = SHRegGetUSValueW(pwzSubKey, pwzValue, &dwType, (LPVOID) szData, &dwSize, fIgnoreHKCU, (LPVOID) pszDefault, dwDefaultSize);
  2427. if (ERROR_SUCCESS == lRet)
  2428. {
  2429. if (dwType == REG_BINARY || dwType == REG_DWORD)
  2430. {
  2431. fDefault = (*((DWORD*)szData) != 0);
  2432. }
  2433. else
  2434. {
  2435. if ((0 == lstrcmpiW(BOOLSETTING_BOOL_TRUE1W, szData)) ||
  2436. (0 == lstrcmpiW(BOOLSETTING_BOOL_TRUE2W, szData)) ||
  2437. (0 == lstrcmpiW(BOOLSETTING_BOOL_1W, szData)))
  2438. {
  2439. fDefault = TRUE; // We read TRUE from the registry.
  2440. }
  2441. else if ((0 == lstrcmpiW(BOOLSETTING_BOOL_FALSE1W, szData)) ||
  2442. (0 == lstrcmpiW(BOOLSETTING_BOOL_FALSE2W, szData)) ||
  2443. (0 == lstrcmpiW(BOOLSETTING_BOOL_0W, szData)))
  2444. {
  2445. fDefault = FALSE; // We read TRUE from the registry.
  2446. }
  2447. }
  2448. }
  2449. return fDefault;
  2450. }
  2451. /*----------------------------------------------------------
  2452. Purpose: Gets a BOOL Setting from the registry. The default
  2453. parameter will be used if it's not found in the registry.
  2454. Cond: --
  2455. */
  2456. STDAPI_(BOOL)
  2457. SHRegGetBoolUSValueA(
  2458. IN LPCSTR pszSubKey,
  2459. IN LPCSTR pszValue,
  2460. IN BOOL fIgnoreHKCU,
  2461. IN BOOL fDefault)
  2462. {
  2463. LONG lRet;
  2464. CHAR szData[MAX_PATH];
  2465. DWORD dwType = REG_SZ; //because the default value we pass in is a string.
  2466. DWORD dwSize = sizeof(szData);
  2467. LPCSTR pszDefault = fDefault ? BOOLSETTING_BOOL_TRUE1A : BOOLSETTING_BOOL_FALSE1A;
  2468. DWORD dwDefaultSize = (fDefault ? sizeof(BOOLSETTING_BOOL_TRUE1A) : sizeof(BOOLSETTING_BOOL_FALSE1A)) + sizeof(CHAR);
  2469. lRet = SHRegGetUSValueA(pszSubKey, pszValue, &dwType, (LPVOID) szData, &dwSize, fIgnoreHKCU, (LPVOID) pszDefault, dwDefaultSize);
  2470. if (ERROR_SUCCESS == lRet)
  2471. {
  2472. if (dwType == REG_BINARY || dwType == REG_DWORD)
  2473. {
  2474. fDefault = (*((DWORD*)szData) != 0);
  2475. }
  2476. else
  2477. {
  2478. if ((0 == lstrcmpiA(BOOLSETTING_BOOL_TRUE1A, szData)) ||
  2479. (0 == lstrcmpiA(BOOLSETTING_BOOL_TRUE2A, szData)) ||
  2480. (0 == lstrcmpiA(BOOLSETTING_BOOL_1A, szData)))
  2481. {
  2482. fDefault = TRUE; // We read TRUE from the registry.
  2483. }
  2484. else if ((0 == lstrcmpiA(BOOLSETTING_BOOL_FALSE1A, szData)) ||
  2485. (0 == lstrcmpiA(BOOLSETTING_BOOL_FALSE2A, szData)) ||
  2486. (0 == lstrcmpiA(BOOLSETTING_BOOL_0A, szData)) )
  2487. {
  2488. fDefault = FALSE; // We read TRUE from the registry.
  2489. }
  2490. }
  2491. }
  2492. return fDefault;
  2493. }
  2494. STDAPI_(DWORD)
  2495. SHGetValueGoodBootA(HKEY hkeyParent, LPCSTR pcszSubKey,
  2496. LPCSTR pcszValue, PDWORD pdwValueType,
  2497. PBYTE pbyteBuf, PDWORD pdwcbBufLen)
  2498. {
  2499. if (GetSystemMetrics(SM_CLEANBOOT))
  2500. return ERROR_GEN_FAILURE;
  2501. return SHGetValueA(hkeyParent, pcszSubKey, pcszValue, pdwValueType, pbyteBuf, pdwcbBufLen);
  2502. }
  2503. STDAPI_(DWORD)
  2504. SHGetValueGoodBootW(HKEY hkeyParent, LPCWSTR pcwzSubKey,
  2505. LPCWSTR pcwzValue, PDWORD pdwValueType,
  2506. PBYTE pbyteBuf, PDWORD pdwcbBufLen)
  2507. {
  2508. if (GetSystemMetrics(SM_CLEANBOOT))
  2509. return ERROR_GEN_FAILURE;
  2510. return SHGetValueW(hkeyParent, pcwzSubKey, pcwzValue, pdwValueType, pbyteBuf, pdwcbBufLen);
  2511. }
  2512. /*----------------------------------------------------------
  2513. Purpose: Given a CLSID open and return that key from HKCR, or
  2514. the user local version.
  2515. Cond: --
  2516. */
  2517. LWSTDAPI SHRegGetCLSIDKeyW(UNALIGNED REFGUID rguid, LPCWSTR pszSubKey, BOOL fUserSpecific, BOOL fCreate, HKEY *phkey)
  2518. {
  2519. HKEY hkeyRef;
  2520. WCHAR szThisCLSID[GUIDSTR_MAX];
  2521. WCHAR szPath[GUIDSTR_MAX+MAX_PATH+1]; // room for clsid + extra
  2522. ULONG err;
  2523. SHStringFromGUIDW(rguid, szThisCLSID, ARRAYSIZE(szThisCLSID));
  2524. if (fUserSpecific)
  2525. {
  2526. hkeyRef = HKEY_CURRENT_USER;
  2527. if (g_bRunningOnNT)
  2528. {
  2529. StrCpyW(szPath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\");
  2530. }
  2531. else
  2532. {
  2533. //
  2534. // On 9x we have to keep using the old location because Plus
  2535. // relies on that location. (Plus changes the DefaultIcon
  2536. // subkey to get custom regitem icons.)
  2537. //
  2538. StrCpyW(szPath, L"Software\\Classes\\CLSID\\");
  2539. }
  2540. }
  2541. else
  2542. {
  2543. hkeyRef = HKEY_CLASSES_ROOT;
  2544. StrCpyW(szPath, L"CLSID");
  2545. StrCatW(szPath, L"\\");
  2546. }
  2547. StrCatW(szPath, szThisCLSID);
  2548. if (pszSubKey)
  2549. {
  2550. StrCatW(szPath, L"\\");
  2551. StrCatBuffW(szPath, pszSubKey, ARRAYSIZE(szPath));
  2552. }
  2553. if (fCreate)
  2554. {
  2555. err = RegCreateKeyW(hkeyRef, szPath, phkey);
  2556. }
  2557. else
  2558. {
  2559. err = RegOpenKeyExW(hkeyRef, szPath, 0, MAXIMUM_ALLOWED, phkey);
  2560. }
  2561. return HRESULT_FROM_WIN32(err);
  2562. }
  2563. LWSTDAPI SHRegGetCLSIDKeyA(UNALIGNED REFGUID rguid, LPCSTR pszSubKey, BOOL fUserSpecific, BOOL fCreate, HKEY *phkey)
  2564. {
  2565. HKEY hkeyRef;
  2566. CHAR szThisCLSID[GUIDSTR_MAX];
  2567. CHAR szPath[GUIDSTR_MAX+MAX_PATH+1]; // room for clsid + extra
  2568. ULONG err;
  2569. SHStringFromGUIDA(rguid, szThisCLSID, ARRAYSIZE(szThisCLSID));
  2570. if (fUserSpecific)
  2571. {
  2572. hkeyRef = HKEY_CURRENT_USER;
  2573. if (g_bRunningOnNT)
  2574. {
  2575. StrCpyA(szPath, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\");
  2576. }
  2577. else
  2578. {
  2579. //
  2580. // On 9x we have to keep using the old location because Plus
  2581. // relies on that location. (Plus changes the DefaultIcon
  2582. // subkey to get custom regitem icons.)
  2583. //
  2584. StrCpyA(szPath, "Software\\Classes\\CLSID\\");
  2585. }
  2586. }
  2587. else
  2588. {
  2589. hkeyRef = HKEY_CLASSES_ROOT;
  2590. StrCpyA(szPath, "CLSID\\");
  2591. }
  2592. StrCatA(szPath, szThisCLSID);
  2593. if (pszSubKey)
  2594. {
  2595. StrCatA(szPath, "\\");
  2596. StrCatBuffA(szPath, pszSubKey, ARRAYSIZE(szPath));
  2597. }
  2598. if (fCreate)
  2599. err = RegCreateKeyA(hkeyRef, szPath, phkey);
  2600. else
  2601. err = RegOpenKeyExA(hkeyRef, szPath, 0, MAXIMUM_ALLOWED, phkey);
  2602. return HRESULT_FROM_WIN32(err);
  2603. }
  2604. /*----------------------------------------------------------
  2605. Purpose: Duplicate an hkey if an object wants to keep one open
  2606. //*** Reg_DupKey -- duplicate registry key (upping refcnt)
  2607. // NOTES
  2608. // REARCHITECT gotta fix this logic (now that i understand how bogus it is).
  2609. //
  2610. // what we're trying to do is dup the handle. sounds easy. it isn't.
  2611. // here's the deal.
  2612. // 1- RegOpenKeyEx(hkey, NULL, ..., &hkey2) is spec'ed as giving back the
  2613. // same handle. on win95 it ups the refcnt (good!).
  2614. // 2- but on winNT there is no refcnt associated w/ it. so it gives back
  2615. // the same handle but now *any* close will make *all* of the 'pseudo-dup'ed
  2616. // handles invalid.
  2617. // 3- (on winNT) if we add MAXIMUM_ALLOWED, we're asking for a new SAM.
  2618. // but the SAM is associated w/ the handle, so the only (or rather, closest)
  2619. // way to do that is to give a new handle. (presumably this only works
  2620. // if we're not dup'ing a handle that's already MAXIMUM_ALLOWED).
  2621. // 4- (on winNT) but wait! if we open HKEY_CURRENT_USER, we *always* get
  2622. // back 0x80000001 (or somesuch). but closes on that are ignored, so all
  2623. // works.
  2624. //
  2625. // so what we probably should do is:
  2626. // - win95: just do #1, w/ default security. win95 will give us the same
  2627. // handle w/ an *upped* refcnt and we'll be fine.
  2628. // - winNT: do a DuplicateHandle. this will correctly give us a *new*
  2629. // handle and we'll be fine.
  2630. //
  2631. */
  2632. HKEY SHRegDuplicateHKey(HKEY hkey)
  2633. {
  2634. HKEY hkeyDup = NULL; // in case incoming hkey is invalid
  2635. // NULL returns key to same place and ups refcnt
  2636. RegOpenKeyExA(hkey, NULL, 0, MAXIMUM_ALLOWED, &hkeyDup);
  2637. // This is a bogus assert on Win95, since they have reference counting on these hkeys...
  2638. if (g_bRunningOnNT)
  2639. {
  2640. ASSERT(hkeyDup != hkey ||
  2641. hkey == HKEY_CURRENT_USER ||
  2642. hkey == HKEY_CLASSES_ROOT ||
  2643. hkey == HKEY_LOCAL_MACHINE);
  2644. }
  2645. return hkeyDup;
  2646. }
  2647. /*----------------------------------------------------------
  2648. Purpose: Read a string value from the registry and convert it
  2649. to an integer.
  2650. */
  2651. LWSTDAPI_(int) SHRegGetIntW(HKEY hk, LPCWSTR szKey, int nDefault)
  2652. {
  2653. DWORD cb;
  2654. WCHAR ach[20];
  2655. if (hk == NULL)
  2656. return nDefault;
  2657. ach[0] = 0;
  2658. cb = sizeof(ach);
  2659. SHQueryValueExW(hk, szKey, NULL, NULL, (LPBYTE)ach, &cb);
  2660. if (ach[0] >= L'0' && ach[0] <= L'9')
  2661. return StrToIntW(ach);
  2662. else
  2663. return nDefault;
  2664. }
  2665. // Stores a file path in the registry but looks for a match with
  2666. // certain environment variables first. This is a FIXED list.
  2667. // Parameters:
  2668. // hKey - an open HKEY or registry root key
  2669. // pszSubKey - subkey in registry or NULL/zero length string
  2670. // pszValue - value name in registry
  2671. // pszPath - Win32 file path to write
  2672. // dwFlags - unused / future expansion
  2673. // Return value:
  2674. // Returns Win32 error code from ADVAPI32.DLL function calls.
  2675. //
  2676. // Match %USERPROFILE% - x:\WINNT\Profiles\<user>
  2677. // - x:\Documents And Settings\<user>
  2678. // %ALLUSERSPROFILES% - x:\WINNT\Profiles\<user>
  2679. // - x:\Documents And Settings\<user>
  2680. // %ProgramFiles% - x:\Program Files
  2681. // %SystemRoot% - x:\WINNT
  2682. //
  2683. // %ALLUSERSPROFILE% and %ProgramFiles% are dubious and can be
  2684. // removed.
  2685. //
  2686. // WARNING: DO NOT CHANGE THE MATCH ORDER OF %USERPROFILE% AND
  2687. // %SystemRoot%
  2688. //
  2689. // If %SystemRoot% is matched first then %USERPROFILE% will
  2690. // NEVER be matched if inside x:\WINNT\
  2691. //
  2692. DWORD SHRegSetPathW (HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, LPCWSTR pszPath, DWORD dwFlags)
  2693. {
  2694. DWORD dwType;
  2695. PCWSTR pszData;
  2696. WCHAR szTemp[MAX_PATH];
  2697. if (PathUnExpandEnvStringsW(pszPath, szTemp, ARRAYSIZE(szTemp)))
  2698. {
  2699. dwType = REG_EXPAND_SZ;
  2700. pszData = szTemp;
  2701. }
  2702. else
  2703. {
  2704. dwType = REG_SZ;
  2705. pszData = pszPath;
  2706. }
  2707. return SHSetValueW(hKey, pszSubKey, pszValue, dwType, pszData, (lstrlenW(pszData) + 1) * sizeof(pszData[0]));
  2708. }
  2709. DWORD SHRegSetPathA(HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue, LPCSTR pszPath, DWORD dwFlags)
  2710. {
  2711. DWORD dwType;
  2712. PCSTR pszData;
  2713. CHAR szTemp[MAX_PATH];
  2714. if (PathUnExpandEnvStringsA(pszPath, szTemp, ARRAYSIZE(szTemp)))
  2715. {
  2716. dwType = REG_EXPAND_SZ;
  2717. pszData = szTemp;
  2718. }
  2719. else
  2720. {
  2721. dwType = REG_SZ;
  2722. pszData = pszPath;
  2723. }
  2724. return SHSetValueA(hKey, pszSubKey, pszValue, dwType, pszData, (lstrlenA(pszData) + 1) * sizeof(pszData[0]));
  2725. }
  2726. // RegGetPath: Unicode implementation of function.
  2727. // Returns an expanded file path from the registry.
  2728. // Parameters:
  2729. // hKey - an open HKEY or registry root key
  2730. // pszSubKey - subkey in registry or NULL/zero length string
  2731. // pszValue - value name in registry
  2732. // pwszPath - string to place path in (assumed size of MAX_PATH chars)
  2733. // dwFlags - unused / future expansion
  2734. // Return value:
  2735. // Returns Win32 error code from ADVAPI32.DLL function calls.
  2736. DWORD SHRegGetPathA (HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue, LPSTR pszPath, DWORD dwFlags)
  2737. {
  2738. DWORD cb = MAX_PATH * sizeof(pszPath[0]);
  2739. return SHGetValueA(hKey, pszSubKey, pszValue, NULL, pszPath, &cb);
  2740. }
  2741. DWORD SHRegGetPathW (HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, LPWSTR pszPath, DWORD dwFlags)
  2742. {
  2743. DWORD cb = MAX_PATH * sizeof(pszPath[0]);
  2744. return SHGetValueW(hKey, pszSubKey, pszValue, NULL, pszPath, &cb);
  2745. }
  2746. BOOL Reg_GetCommand(HKEY hkey, LPCWSTR pszKey, LPCWSTR pszValue, LPWSTR pszCommand)
  2747. {
  2748. WCHAR szKey[1024];
  2749. LONG cbSize = sizeof(szKey);
  2750. int iLen;
  2751. ASSERT(pszKey);
  2752. StrCpyNW(szKey, pszKey, ARRAYSIZE(szKey));
  2753. iLen = lstrlenW(szKey);
  2754. pszCommand[0] = 0;
  2755. // a trailing backslash means no value key
  2756. if (szKey[iLen-1] == L'\\' ||
  2757. (pszValue && !pszValue[0])) {
  2758. if (!pszValue)
  2759. szKey[iLen-1] = 0;
  2760. RegQueryValueW(hkey, szKey, pszCommand, &cbSize);
  2761. } else {
  2762. if (!pszValue)
  2763. pszValue = PathFindFileNameW(szKey);
  2764. ASSERT(pszValue);
  2765. if (!pszValue)
  2766. return FALSE;
  2767. PathRemoveFileSpecW(szKey);
  2768. SHGetValueGoodBootW(hkey, szKey, pszValue, NULL, (LPBYTE)pszCommand, (DWORD*)&cbSize);
  2769. }
  2770. if (pszCommand[0]) {
  2771. LPWSTR pszNextKey;
  2772. // see if it's a registry spec
  2773. if (!StrCmpNIW(pszCommand, L"HKCU:", 5)) {
  2774. hkey = HKEY_CURRENT_USER;
  2775. pszNextKey = pszCommand + 5;
  2776. } else if (!StrCmpNIW(pszCommand, L"HKLM:", 5)) {
  2777. hkey = HKEY_LOCAL_MACHINE;
  2778. pszNextKey = pszCommand + 5;
  2779. } else if (!StrCmpNIW(pszCommand, L"HKCR:", 5)) {
  2780. hkey = HKEY_CLASSES_ROOT;
  2781. pszNextKey = pszCommand + 5;
  2782. } else {
  2783. return (BOOL)pszCommand[0];
  2784. }
  2785. StrCpyNW(szKey, pszNextKey, ARRAYSIZE(szKey));
  2786. return (Reg_GetCommand(hkey, szKey, NULL, pszCommand));
  2787. }
  2788. return (BOOL)pszCommand[0];
  2789. }
  2790. #define FillExecInfo(_info, _hwnd, _verb, _file, _params, _dir, _show) \
  2791. (_info).hwnd = _hwnd; \
  2792. (_info).lpVerb = _verb; \
  2793. (_info).lpFile = _file; \
  2794. (_info).lpParameters = _params; \
  2795. (_info).lpDirectory = _dir; \
  2796. (_info).nShow = _show; \
  2797. (_info).fMask = 0; \
  2798. (_info).cbSize = sizeof(SHELLEXECUTEINFOW);
  2799. HRESULT RunRegCommand(HWND hwnd, HKEY hkey, LPCWSTR pszKey)
  2800. {
  2801. HRESULT hr = E_FAIL;
  2802. WCHAR szCommand[1024];
  2803. if (Reg_GetCommand(hkey, pszKey, L"", szCommand))
  2804. {
  2805. LPWSTR pszArgs;
  2806. SHELLEXECUTEINFOW ExecInfo;
  2807. WCHAR szExpCommand[1024];
  2808. SHExpandEnvironmentStringsW(szCommand, szExpCommand, ARRAYSIZE(szExpCommand));
  2809. // Long filenames _should_ be surrounded by quote marks. However, some aren't.
  2810. // This causes problems because the registry entry might be of the form
  2811. // (c:\program files\Windows Messaging\[...]) instead of
  2812. // ("c:\program files\Windows Messaging\[...]"). Compare this with
  2813. // a reg value with (rundll32 C:\progra~1\etc)
  2814. // We end up parsing attempting to run C:\program, which of course doesn't exist.
  2815. // This is a hack for the benefit OSR2, which turns szExpCommand
  2816. // into a null string, rather than letting it be, if it can't be shortened.
  2817. GetShortPathNameW(szExpCommand, szExpCommand, ARRAYSIZE(szExpCommand));
  2818. if ((*szExpCommand==L'\0') && (*szCommand!=L'\0'))
  2819. {
  2820. SHExpandEnvironmentStringsW(szCommand, szExpCommand, ARRAYSIZE(szExpCommand));
  2821. }
  2822. pszArgs = PathGetArgsW(szExpCommand);
  2823. PathRemoveArgsW(szExpCommand);
  2824. PathUnquoteSpacesW(szExpCommand);
  2825. FillExecInfo(ExecInfo, hwnd, NULL, szExpCommand, pszArgs, NULL, SW_SHOWNORMAL);
  2826. if (IsOS(OS_WHISTLERORGREATER))
  2827. {
  2828. ExecInfo.fMask |= SEE_MASK_FLAG_LOG_USAGE;
  2829. }
  2830. hr = ShellExecuteExWrapW(&ExecInfo) ? S_OK : E_FAIL;
  2831. }
  2832. return hr;
  2833. }
  2834. // NOTE! RunIndirectRegCommand logs the action as user-initiated!
  2835. HRESULT RunIndirectRegCommand(HWND hwnd, HKEY hkey, LPCWSTR pszKey, LPCWSTR pszVerb)
  2836. {
  2837. HRESULT hr = E_FAIL;
  2838. WCHAR szDefApp[80];
  2839. LONG cbSize = sizeof(szDefApp);
  2840. if (RegQueryValueW(hkey, pszKey, szDefApp, &cbSize) == ERROR_SUCCESS)
  2841. {
  2842. WCHAR szFullKey[256];
  2843. // tack on shell\%verb%\command
  2844. wnsprintfW(szFullKey, ARRAYSIZE(szFullKey), L"%s\\%s\\shell\\%s\\command", pszKey, szDefApp, pszVerb);
  2845. hr = RunRegCommand(hwnd, hkey, szFullKey);
  2846. }
  2847. return hr;
  2848. }
  2849. HRESULT SHRunIndirectRegClientCommand(HWND hwnd, LPCWSTR pszClient)
  2850. {
  2851. WCHAR szKey[80];
  2852. wnsprintfW(szKey, ARRAYSIZE(szKey), L"Software\\Clients\\%s", pszClient);
  2853. return RunIndirectRegCommand(hwnd, HKEY_LOCAL_MACHINE, szKey, L"Open");
  2854. }