Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

587 lines
17 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: N C R E G Q . C P P
  7. //
  8. // Contents: HrRegQuery functions.
  9. //
  10. // Notes:
  11. //
  12. // Author: shaunco 5 Jun 1998
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.h>
  16. #pragma hdrstop
  17. #include "ncdebug.h"
  18. #include "ncreg.h"
  19. //+---------------------------------------------------------------------------
  20. //
  21. // Function: HrRegQueryDword
  22. //
  23. // Purpose: Gets a DWORD from the registry. Checks that its type and
  24. // size are correct. Easier to understand than HrRegQueryValueEx
  25. // with 5 parameters. Type safe (no LPBYTE stuff).
  26. //
  27. // Arguments:
  28. // hkey [in] The registry key.
  29. // pszValueName [in] The name of the value to get.
  30. // pdwValue [out] The returned DWORD value if successful. Zero
  31. // if not.
  32. //
  33. // Returns: S_OK or HRESULT_FROM_WIN32.
  34. //
  35. // Author: shaunco 27 Mar 1997
  36. //
  37. // Side Effects: On error, the output DWORD is set to zero to line-up
  38. // with the rules of COM in this regard.
  39. //
  40. HRESULT
  41. HrRegQueryDword (
  42. HKEY hkey,
  43. PCTSTR pszValueName,
  44. LPDWORD pdwValue)
  45. {
  46. Assert (hkey);
  47. Assert (pszValueName);
  48. Assert (pdwValue);
  49. // Get the value.
  50. DWORD dwType;
  51. DWORD cbData = sizeof(DWORD);
  52. HRESULT hr = HrRegQueryValueEx (hkey, pszValueName, &dwType,
  53. (LPBYTE)pdwValue, &cbData);
  54. // It's type should be REG_DWORD. (duh).
  55. //
  56. if ((S_OK == hr) && (REG_DWORD != dwType))
  57. {
  58. TraceTag (ttidError, "Expected a type of REG_DWORD for %S.",
  59. pszValueName);
  60. hr = HRESULT_FROM_WIN32 (ERROR_INVALID_DATATYPE);
  61. }
  62. // It's size should be correct too.
  63. //
  64. AssertSz (FImplies(S_OK == hr, sizeof(DWORD) == cbData),
  65. "Expected sizeof(DWORD) bytes to be returned.");
  66. // Make sure we initialize the output value on error.
  67. // (We don't know for sure that RegQueryValueEx does this.)
  68. //
  69. if (S_OK != hr)
  70. {
  71. *pdwValue = 0;
  72. }
  73. TraceHr (ttidError, FAL, hr,
  74. (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr),
  75. "HrRegQueryDword");
  76. return hr;
  77. }
  78. #if 0
  79. //+---------------------------------------------------------------------------
  80. //
  81. // Function: HrRegQueryExpandString
  82. //
  83. // Purpose: Query a REG_EXPAND_SZ value from the registry and
  84. // expand it using ExpandEnvironmentStrings. Return the
  85. // result in a tstring.
  86. //
  87. // Arguments:
  88. // hkey [in] The parent HKEY of szValueName
  89. // pszValueName [in] The name of the value to query.
  90. // pstrValue [out] The returned (expanded) value.
  91. //
  92. // Returns: S_OK or an error code.
  93. //
  94. // Author: shaunco 6 Jun 1998
  95. //
  96. // Notes:
  97. //
  98. HRESULT
  99. HrRegQueryExpandString (
  100. HKEY hkey,
  101. PCTSTR pszValueName,
  102. tstring* pstrValue)
  103. {
  104. Assert (hkey);
  105. Assert (pszValueName);
  106. Assert (pstrValue);
  107. tstring strToExpand;
  108. HRESULT hr = HrRegQueryTypeString (hkey, pszValueName,
  109. REG_EXPAND_SZ, &strToExpand);
  110. if (S_OK == hr)
  111. {
  112. ExpandEnvironmentStringsIntoTstring (strToExpand.c_str(), pstrValue);
  113. }
  114. TraceHr (ttidError, FAL, hr,
  115. (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) ||
  116. (HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE) == hr),
  117. "HrRegQueryExpandString");
  118. return hr;
  119. }
  120. //+---------------------------------------------------------------------------
  121. //
  122. // Function: HrRegQueryInfoKey
  123. //
  124. // Purpose: Retrieves information about a registry key by calling
  125. // RegQueryInfoKey.
  126. //
  127. // Arguments:
  128. // hkey [in]
  129. // pszClass [out]
  130. // pcbClass [inout]
  131. // pcSubKeys [out]
  132. // pcbMaxSubKeyLen [out] See the Win32 documentation for the
  133. // pcbMaxClassLen [out] RegQueryInfoKey function.
  134. // pcValues [out]
  135. // pcbMaxValueNameLen [out]
  136. // pcbMaxValueLen [out]
  137. // pcbSecurityDescriptor [out]
  138. // pftLastWriteTime [out]
  139. //
  140. // Returns: S_OK or an HRESULT_FROM_WIN32 error code.
  141. //
  142. // Author: BillBe 28 Aug 1998
  143. //
  144. // Notes: Note that pcbClass is an *in/out* param. Set this to the size
  145. // of the buffer pointed to by pszClass *before* calling this
  146. // function!
  147. //
  148. HRESULT
  149. HrRegQueryInfoKey (
  150. IN HKEY hkey,
  151. OUT PWSTR pszClass,
  152. IN OUT LPDWORD pcbClass,
  153. OUT LPDWORD pcSubKeys,
  154. OUT LPDWORD pcbMaxSubKeyLen,
  155. OUT LPDWORD pcbMaxClassLen,
  156. OUT LPDWORD pcValues,
  157. OUT LPDWORD pcbMaxValueNameLen,
  158. OUT LPDWORD pcbMaxValueLen,
  159. OUT LPDWORD pcbSecurityDescriptor,
  160. OUT PFILETIME pftLastWriteTime)
  161. {
  162. Assert(hkey);
  163. LONG lr = RegQueryInfoKeyW(hkey, pszClass, pcbClass, NULL,pcSubKeys,
  164. pcbMaxSubKeyLen, pcbMaxClassLen, pcValues, pcbMaxValueNameLen,
  165. pcbMaxValueLen, pcbSecurityDescriptor, pftLastWriteTime);
  166. HRESULT hr = HRESULT_FROM_WIN32 (lr);
  167. TraceHr (ttidError, FAL, hr, FALSE, "HrRegQueryInfoKey");
  168. return hr;
  169. }
  170. //+---------------------------------------------------------------------------
  171. //
  172. // Function: HrRegQueryStringAsUlong
  173. //
  174. // Purpose: Reads a REG_SZ from the registry and converts it to a ulong
  175. // before returning
  176. //
  177. // Arguments:
  178. // hkey [in] The registry key.
  179. // pszValueName [in] The name of the value to get.
  180. // nBase [in] The numeric base to convert to
  181. // pulValue [out] The returned converted string if successful.
  182. //
  183. // Returns: S_OK or an HRESULT_FROM_WIN32 error code.
  184. //
  185. // Author: billbe 13 Jun 1997
  186. //
  187. // Notes:
  188. //
  189. //
  190. HRESULT
  191. HrRegQueryStringAsUlong (
  192. IN HKEY hkey,
  193. IN PCTSTR pszValueName,
  194. IN int nBase,
  195. OUT ULONG* pulValue)
  196. {
  197. Assert (hkey);
  198. Assert (pszValueName);
  199. Assert (nBase);
  200. Assert (pulValue);
  201. // Get the value.
  202. //
  203. tstring strValue;
  204. HRESULT hr = HrRegQueryString (hkey, pszValueName, &strValue);
  205. if (S_OK == hr)
  206. {
  207. // Convert and assign the output parameters.
  208. PWSTR pszStopString;
  209. *pulValue = wcstoul (strValue.c_str(), &pszStopString, nBase);
  210. }
  211. else
  212. {
  213. *pulValue = 0;
  214. }
  215. TraceHr (ttidError, FAL, hr,
  216. (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr),
  217. "HrRegQueryStringAsUlong");
  218. return hr;
  219. }
  220. //+---------------------------------------------------------------------------
  221. //
  222. // Function: HrRegQueryTypeString
  223. //
  224. // Purpose: Query a REG_SZ or REG_EXPAND_SZ value and returns it
  225. // in a tstring.
  226. //
  227. // Arguments:
  228. // hkey [in] The parent HKEY of szValueName
  229. // pszValueName [in] The name of the value to query.
  230. // dwType [in] REG_SZ or REG_EXPAND_SZ
  231. // pstr [out] The returned value.
  232. //
  233. // Returns: S_OK or an error code.
  234. //
  235. // Author: shaunco 6 Jun 1998
  236. //
  237. // Notes: REG_EXPAND_SZ values ARE NOT expanded using
  238. // ExpandEnvironentStrings. Use HrRegQueryExpandString instead.
  239. //
  240. HRESULT
  241. HrRegQueryTypeString (
  242. IN HKEY hkey,
  243. IN PCTSTR pszValueName,
  244. IN DWORD dwType,
  245. OUT tstring* pstr)
  246. {
  247. Assert (hkey);
  248. Assert (pszValueName);
  249. Assert (pstr);
  250. AssertSz ((REG_SZ == dwType) ||
  251. (REG_EXPAND_SZ == dwType), "Only REG_SZ or REG_EXPAND_SZ "
  252. "types accepted.");
  253. BOOL fErase = TRUE;
  254. // Get size of the data.
  255. //
  256. DWORD dwTypeRet;
  257. DWORD cbData = 0;
  258. HRESULT hr = HrRegQueryValueEx (hkey, pszValueName, &dwTypeRet,
  259. NULL, &cbData);
  260. // Make sure it has the correct type.
  261. //
  262. if ((S_OK == hr) && (dwTypeRet != dwType))
  263. {
  264. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
  265. }
  266. if (S_OK == hr)
  267. {
  268. // Compute the number of characters in the data including the
  269. // NULL terminator. After dividing the number of bytes by
  270. // the sizeof a TCHAR, add 1 if there is a remainder. If we didn't,
  271. // and the number of bytes was not a multiple of the sizeof a TCHAR,
  272. // we'd come up short because integer division rounds down.
  273. // (The only time I can think of cbData would not be a multiple
  274. // of sizeof(TCHAR) is if the registry data were somehow corrupted.
  275. // It's not that I think corruption deserves a special case, but
  276. // we shouldn't AV in light of it.)
  277. //
  278. DWORD cchIncludingNull;
  279. cchIncludingNull = cbData / sizeof(TCHAR);
  280. if (cbData % sizeof(TCHAR))
  281. {
  282. cchIncludingNull++;
  283. }
  284. // If we have more than just the terminator, allocate and
  285. // get the string. Otherwise, we want it empty.
  286. //
  287. if (cchIncludingNull > 1)
  288. {
  289. // Reserve room for the correct number of characters.
  290. // cch is the count of characters without the terminator
  291. // since that is what tstring operates with.
  292. //
  293. DWORD cch = cchIncludingNull - 1;
  294. Assert (cch > 0);
  295. // assign will reserve cch characters and set them all to 0.
  296. // checking capacity afterwards ensures the allocation made
  297. // internally didn't fail.
  298. //
  299. pstr->assign (cch, 0);
  300. if (cch <= pstr->capacity ())
  301. {
  302. hr = HrRegQueryValueEx (hkey, pszValueName, &dwType,
  303. (LPBYTE)pstr->data (), &cbData);
  304. if (S_OK == hr)
  305. {
  306. // If everything went according to plan, the length
  307. // of the string should now match what wcslen
  308. // returns on the string itself. The reason it will
  309. // match is because we passed cch to assign.
  310. //
  311. Assert (pstr->length() == (size_t)wcslen (pstr->c_str()));
  312. fErase = FALSE;
  313. }
  314. }
  315. else
  316. {
  317. hr = E_OUTOFMEMORY;
  318. }
  319. }
  320. }
  321. // Empty the output string on failure or if we think it should be
  322. // empty.
  323. //
  324. if (FAILED(hr) || fErase)
  325. {
  326. pstr->erase();
  327. }
  328. TraceHr (ttidError, FAL, hr,
  329. (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) ||
  330. (HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE) == hr),
  331. "HrRegQueryTypeString");
  332. return hr;
  333. }
  334. //+---------------------------------------------------------------------------
  335. //
  336. // Function: HrRegQueryTypeSzBuffer
  337. //
  338. // Purpose: Gets a string from the registry using the given buffer. Checks
  339. // that its type is correct. Type safe (no LPBYTE stuff).
  340. //
  341. // Arguments:
  342. // hkey [in] The registry key.
  343. // pszValueName [in] The name of the value to get.
  344. // dwType [in] Desired type. (REG_SZ, REG_EXPAND_SZ, etc.)
  345. // szData [out] String buffer to hold the data.
  346. // pcbData [in,out] IN: Number of *bytes* in buffer pointed to by
  347. // szData. OUT: Number of bytes actually copied
  348. // into the buffer.
  349. //
  350. // Returns: S_OK or an HRESULT_FROM_WIN32 error code.
  351. //
  352. // Author: danielwe 3 Apr 1997
  353. //
  354. // Notes: If the function fails, the buffer passed in is guaranteed to
  355. // be an empty string.
  356. //
  357. HRESULT
  358. HrRegQueryTypeSzBuffer (
  359. IN HKEY hkey,
  360. IN PCTSTR pszValueName,
  361. IN DWORD dwType,
  362. OUT PWSTR pszData,
  363. OUT DWORD* pcbData)
  364. {
  365. Assert (hkey);
  366. Assert (pszValueName);
  367. Assert (pcbData);
  368. DWORD dwTypeRet;
  369. HRESULT hr = HrRegQueryValueEx (hkey, pszValueName, &dwTypeRet,
  370. (LPBYTE)pszData, pcbData);
  371. if ((S_OK == hr) && (dwTypeRet != dwType))
  372. {
  373. TraceTag (ttidError, "Expected a type of 0x%x for %S.",
  374. dwType, pszValueName);
  375. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
  376. }
  377. if (FAILED(hr) && pszData)
  378. {
  379. // Make sure empty string is returned on failure.
  380. //
  381. *pszData = 0;
  382. }
  383. TraceHr (ttidError, FAL, hr,
  384. (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr),
  385. "HrRegQueryTypeSzBuffer");
  386. return hr;
  387. }
  388. #endif
  389. //+---------------------------------------------------------------------------
  390. //
  391. // Function: HrRegQueryValueEx
  392. //
  393. // Purpose: Retrieves the data from the given registry value by calling
  394. // RegQueryValueEx.
  395. //
  396. // Arguments:
  397. // hkey [in]
  398. // pszValueName [in]
  399. // pdwType [out] See the Win32 documentation for the
  400. // pbData [out] RegQueryValueEx function.
  401. // pcbData [in,out]
  402. //
  403. // Returns: S_OK or an HRESULT_FROM_WIN32 error code.
  404. //
  405. // Author: shaunco 25 Feb 1997
  406. //
  407. // Notes: Note that pcbData is an *in/out* param. Set this to the size
  408. // of the buffer pointed to by pbData *before* calling this
  409. // function!
  410. //
  411. HRESULT
  412. HrRegQueryValueEx (
  413. IN HKEY hkey,
  414. IN PCTSTR pszValueName,
  415. OUT LPDWORD pdwType,
  416. OUT LPBYTE pbData,
  417. OUT LPDWORD pcbData)
  418. {
  419. Assert (hkey);
  420. AssertSz (FImplies(pbData && pcbData, pdwType),
  421. "pdwType not provided to HrRegQueryValueEx. You should be "
  422. "retrieving the type as well so you can make sure it is "
  423. "correct.");
  424. LONG lr = RegQueryValueEx (hkey, pszValueName, NULL, pdwType,
  425. pbData, pcbData);
  426. HRESULT hr = HRESULT_FROM_WIN32 (lr);
  427. TraceHr (ttidError, FAL, hr,
  428. (ERROR_MORE_DATA == lr) || (ERROR_FILE_NOT_FOUND == lr),
  429. "HrRegQueryValueEx (%S)", pszValueName);
  430. return hr;
  431. }
  432. //+---------------------------------------------------------------------------
  433. //
  434. // Function: HrRegQueryValueWithAlloc
  435. //
  436. // Purpose: Retrieve a registry value in a buffer allocated by this
  437. // function. This goes through the mess of checking the value
  438. // size, allocating the buffer, and then calling back to get the
  439. // actual value. Returns the buffer to the user.
  440. //
  441. // Arguments:
  442. // hkey [in] An open HKEY (the one that contains the value
  443. // to be read)
  444. // pszValueName [in] Name of the registry value
  445. // pdwType [in/out] The REG_ type that we plan to be reading
  446. // ppbBuffer [out] Pointer to an LPBYTE buffer that will contain
  447. // the registry value
  448. // pdwSize [out] Pointer to a DWORD that will contain the size
  449. // of the ppbBuffer.
  450. //
  451. // Returns: S_OK or an HRESULT_FROM_WIN32 error code.
  452. //
  453. // Author: jeffspr 27 Mar 1997
  454. //
  455. HRESULT
  456. HrRegQueryValueWithAlloc (
  457. IN HKEY hkey,
  458. IN PCTSTR pszValueName,
  459. LPDWORD pdwType,
  460. LPBYTE* ppbBuffer,
  461. LPDWORD pdwSize)
  462. {
  463. HRESULT hr;
  464. BYTE abData [256];
  465. DWORD cbData;
  466. BOOL fReQuery = FALSE;
  467. Assert (hkey);
  468. Assert (pdwType);
  469. Assert (ppbBuffer);
  470. // Initialize the output parameters.
  471. //
  472. *ppbBuffer = NULL;
  473. if (pdwSize)
  474. {
  475. *pdwSize = 0;
  476. }
  477. // Get the size of the data, and if it will fit, the data too.
  478. //
  479. cbData = sizeof(abData);
  480. hr = HrRegQueryValueEx (
  481. hkey,
  482. pszValueName,
  483. pdwType,
  484. abData,
  485. &cbData);
  486. if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr)
  487. {
  488. // The data didn't fit, so we'll have to requery for it after
  489. // we allocate our buffer.
  490. //
  491. fReQuery = TRUE;
  492. hr = S_OK;
  493. }
  494. if (S_OK == hr)
  495. {
  496. // Allocate the buffer for the required size.
  497. //
  498. BYTE* pbBuffer = (BYTE*)MemAlloc (cbData);
  499. if (pbBuffer)
  500. {
  501. if (fReQuery)
  502. {
  503. hr = HrRegQueryValueEx (
  504. hkey,
  505. pszValueName,
  506. pdwType,
  507. pbBuffer,
  508. &cbData);
  509. }
  510. else
  511. {
  512. CopyMemory (pbBuffer, abData, cbData);
  513. }
  514. if (S_OK == hr)
  515. {
  516. // Fill in the return values.
  517. //
  518. *ppbBuffer = pbBuffer;
  519. if (pdwSize)
  520. {
  521. *pdwSize = cbData;
  522. }
  523. }
  524. else
  525. {
  526. MemFree (pbBuffer);
  527. }
  528. }
  529. else
  530. {
  531. hr = E_OUTOFMEMORY;
  532. }
  533. }
  534. TraceHr (ttidError, FAL, hr,
  535. (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr),
  536. "HrRegQueryValueWithAlloc");
  537. return hr;
  538. }