Leaked source code of windows server 2003
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.

3315 lines
111 KiB

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