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.

988 lines
27 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation
  4. //
  5. // File: registry.c
  6. //
  7. // Contents: Module to read in registry parameters.
  8. //
  9. // This module is intended as a simple, reusable, interface to the
  10. // registry. Among its features are:
  11. //
  12. // o Kernel Callable.
  13. //
  14. // o Intuitive (it is to me!) - To read the value for /a/b/c/d,
  15. // you say KRegGetValue("/a/b/c/d"), instead of calling at
  16. // least 3 different Nt APIs. Any and all strings returned are
  17. // guaranteed to be NULL terminated.
  18. //
  19. // o Allocates memory on behalf of caller - so we don't waste any
  20. // by allocating max amounts.
  21. //
  22. // o Completely non-reentrant - 'cause it maintains state across
  23. // calls. (It would be simple to make it multi-threaded tho)
  24. //
  25. //
  26. // Classes:
  27. //
  28. // Functions: KRegSetRoot
  29. // KRegCloseRoot
  30. // KRegGetValue
  31. // KRegGetNumValuesAndSubKeys
  32. // KRegEnumValueSet
  33. // KRegEnumSubKeySet
  34. //
  35. //
  36. // History: 18 Sep 92 Milans created
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include "registry.h"
  40. #include "regsups.h"
  41. //
  42. // If we ever needed to go multithreaded, we should return HKEY_ROOT to caller
  43. // instead of keeping it here.
  44. //
  45. static HKEY HKEY_ROOT = NULL; // Handle to root key
  46. #define KREG_SIZE_THRESHOLD 5 // For allocation optimization
  47. //
  48. // Some commonly used error format strings.
  49. //
  50. #if DBG == 1
  51. static char *szErrorOpen = "Error opening %ws section.\n";
  52. static char *szErrorRead = "Error reading %ws section.\n";
  53. #endif
  54. #ifdef ALLOC_PRAGMA
  55. #pragma alloc_text( PAGE, KRegInit )
  56. #pragma alloc_text( PAGE, KRegCloseRoot )
  57. #pragma alloc_text( PAGE, KRegSetRoot )
  58. #pragma alloc_text( PAGE, KRegCreateKey )
  59. #pragma alloc_text( PAGE, KRegGetValue )
  60. #pragma alloc_text( PAGE, KRegSetValue )
  61. #pragma alloc_text( PAGE, KRegDeleteValue )
  62. #pragma alloc_text( PAGE, KRegGetNumValuesAndSubKeys )
  63. #pragma alloc_text( PAGE, KRegEnumValueSet )
  64. #pragma alloc_text( PAGE, KRegEnumSubKeySet )
  65. #pragma alloc_text( PAGE, KRegFreeArray )
  66. #endif // ALLOC_PRAGMA
  67. //+----------------------------------------------------------------------------
  68. //
  69. // Function: KREG_CHECK_HARD_STATUS, macro
  70. //
  71. // Synopsis: If Status is not STATUS_SUCCESS, print out debug msg and return.
  72. //
  73. // Arguments:
  74. //
  75. // Returns:
  76. //
  77. //-----------------------------------------------------------------------------
  78. #define KREG_CHECK_HARD_STATUS(Status, M1, M2) \
  79. if (!NT_SUCCESS(Status)) { \
  80. kreg_debug_out(M1, M2); \
  81. return(Status); \
  82. }
  83. //+----------------------------------------------------------------------------
  84. //
  85. // Function: KRegInit
  86. //
  87. // Synopsis:
  88. //
  89. // Arguments: None
  90. //
  91. // Returns: STATUS_SUCCESS
  92. //
  93. //-----------------------------------------------------------------------------
  94. NTSTATUS
  95. KRegInit(void)
  96. {
  97. return(STATUS_SUCCESS);
  98. }
  99. //+----------------------------------------------------------------------------void
  100. //
  101. // Function: KRegCloseRoot
  102. //
  103. // Synopsis: Close the Root opened by KRegSetRoot.
  104. //
  105. // Arguments: None
  106. //
  107. // Returns: Nothing
  108. //
  109. //-----------------------------------------------------------------------------
  110. void
  111. KRegCloseRoot()
  112. {
  113. if (HKEY_ROOT) {
  114. NtClose(HKEY_ROOT);
  115. HKEY_ROOT = NULL;
  116. }
  117. }
  118. //+----------------------------------------------------------------------------
  119. //
  120. // Function: KRegSetRoot
  121. //
  122. // Synopsis: Sets a particular key as the "root" key for subsequent calls
  123. // to registry routines.
  124. //
  125. // Arguments: wszRootName - Name of root key
  126. //
  127. // Returns: Result of opening the key.
  128. //
  129. //-----------------------------------------------------------------------------
  130. NTSTATUS
  131. KRegSetRoot(
  132. IN PWSTR wszRootName
  133. )
  134. {
  135. NTSTATUS Status;
  136. if (HKEY_ROOT != NULL) {
  137. NtClose(HKEY_ROOT);
  138. }
  139. Status = NtOpenKey(
  140. &HKEY_ROOT, // Handle to DFS root key
  141. KEY_READ | KEY_WRITE, // Only need to read
  142. KRegpAttributes( // Name of Key
  143. NULL,
  144. wszRootName
  145. )
  146. );
  147. return(Status);
  148. }
  149. //+----------------------------------------------------------------------------
  150. //
  151. // Function: KRegDeleteKey
  152. //
  153. // Synopsis: Deletes a key from the registry.
  154. //
  155. // Arguments: [wszKey] -- name of key relative to the current root.
  156. //
  157. // Returns: Status from deleting the key.
  158. //
  159. //-----------------------------------------------------------------------------
  160. NTSTATUS
  161. KRegDeleteKey(
  162. IN PWSTR wszKey)
  163. {
  164. NTSTATUS Status;
  165. APWSTR awszSubKeys;
  166. ULONG cSubKeys, i;
  167. HKEY hkey;
  168. //
  169. // NtDeleteKey won't delete key's which have subkeys. So, we first
  170. // enumerate all the subkeys and delete them, before deleting the key.
  171. //
  172. Status = KRegEnumSubKeySet(wszKey, &cSubKeys, &awszSubKeys);
  173. if (!NT_SUCCESS(Status)) {
  174. return( Status );
  175. }
  176. for (i = 0; i < cSubKeys && NT_SUCCESS(Status); i++) {
  177. Status = NtOpenKey(
  178. &hkey,
  179. KEY_ALL_ACCESS,
  180. KRegpAttributes(HKEY_ROOT, awszSubKeys[i])
  181. );
  182. if (NT_SUCCESS(Status)) {
  183. Status = NtDeleteKey( hkey );
  184. NtClose(hkey);
  185. }
  186. }
  187. //
  188. // If we were able to delete all the subkeys, we can delete the
  189. // key itself.
  190. //
  191. if (NT_SUCCESS(Status)) {
  192. Status = NtOpenKey(
  193. &hkey,
  194. KEY_ALL_ACCESS,
  195. KRegpAttributes(HKEY_ROOT, wszKey)
  196. );
  197. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  198. Status = STATUS_SUCCESS;
  199. } else if (NT_SUCCESS(Status)) {
  200. Status = NtDeleteKey( hkey );
  201. NtClose(hkey);
  202. }
  203. }
  204. KRegFreeArray( cSubKeys, (APBYTE) awszSubKeys );
  205. return(Status);
  206. }
  207. //+----------------------------------------------------------------------------
  208. //
  209. // Function: KRegCreateKey
  210. //
  211. // Synopsis: Creates a new key in the registry under the subkey given
  212. // in wszSubKey. wszSubKey may be NULL, in which case the
  213. // new key is created directly under the current root.
  214. //
  215. // Arguments: [wszSubKey] -- Name of subkey relative to root key under
  216. // which new key will be created.
  217. // [wszNewKey] -- Name of new key to be created.
  218. //
  219. // Returns:
  220. //
  221. //-----------------------------------------------------------------------------
  222. NTSTATUS
  223. KRegCreateKey(
  224. IN PWSTR wszSubKey,
  225. IN PWSTR wszNewKey)
  226. {
  227. HKEY hkeySubKey, hkeyNewKey;
  228. NTSTATUS Status;
  229. UNICODE_STRING ustrValueName;
  230. if (wszSubKey != NULL) {
  231. Status = NtOpenKey(
  232. &hkeySubKey,
  233. KEY_WRITE,
  234. KRegpAttributes(HKEY_ROOT, wszSubKey)
  235. );
  236. KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
  237. } else {
  238. hkeySubKey = HKEY_ROOT;
  239. }
  240. Status = NtCreateKey(
  241. &hkeyNewKey,
  242. KEY_WRITE,
  243. KRegpAttributes(hkeySubKey, wszNewKey),
  244. 0L, // TitleIndex
  245. NULL, // Class
  246. REG_OPTION_NON_VOLATILE, // Create option
  247. NULL); // Create disposition
  248. if (wszSubKey != NULL) {
  249. NtClose(hkeySubKey);
  250. }
  251. if (!NT_SUCCESS(Status)) {
  252. kreg_debug_out(szErrorOpen, wszNewKey);
  253. NtClose(hkeyNewKey);
  254. return(Status);
  255. }
  256. NtClose(hkeyNewKey);
  257. return( Status );
  258. }
  259. //+----------------------------------------------------------------------------
  260. //
  261. // Function: KRegGetValue
  262. //
  263. // Synopsis: Given a Value Name and a handle, will allocate memory for the
  264. // handle and fill it with the Value Data for the value name.
  265. //
  266. // Arguments: [wszSubKey] - Name of subkey relative to root key
  267. // [wszValueName] - name of value data
  268. // [ppValueData] - pointer to pointer to byte data.
  269. //
  270. // Returns: STATUS_SUCCESS, STATUS_NO_MEMORY, Status from NtReg api.
  271. //
  272. // Notes: It will allocate memory for the data, and return a pointer to
  273. // it in ppValueData. Caller must free it.
  274. //
  275. //-----------------------------------------------------------------------------
  276. NTSTATUS
  277. KRegGetValue(
  278. IN PWSTR wszSubKey,
  279. IN PWSTR wszValueName,
  280. OUT PBYTE *ppValueData
  281. )
  282. {
  283. HKEY hkeySubKey;
  284. ULONG dwUnused, cbMaxDataSize;
  285. ULONG cbActualSize;
  286. PBYTE pbData = NULL;
  287. NTSTATUS Status;
  288. Status = NtOpenKey(
  289. &hkeySubKey,
  290. KEY_READ,
  291. KRegpAttributes(HKEY_ROOT, wszSubKey)
  292. );
  293. KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
  294. Status = KRegpGetKeyInfo(
  295. hkeySubKey,
  296. &dwUnused, // Number of Subkeys
  297. &dwUnused, // Max size of subkey length
  298. &dwUnused, // # of Values
  299. &dwUnused, // Max size of value Name
  300. &cbMaxDataSize // Max size of value Data
  301. );
  302. if (!NT_SUCCESS(Status)) {
  303. kreg_debug_out(szErrorRead, wszSubKey);
  304. NtClose(hkeySubKey);
  305. return(Status);
  306. }
  307. //
  308. // Just in case the value is of type REG_SZ, provide for inserting a
  309. // UNICODE_NULL at the end.
  310. //
  311. cbMaxDataSize += sizeof(UNICODE_NULL);
  312. pbData = kreg_alloc(cbMaxDataSize);
  313. if (pbData == NULL) {
  314. Status = STATUS_NO_MEMORY;
  315. goto Cleanup;
  316. }
  317. cbActualSize = cbMaxDataSize;
  318. Status = KRegpGetValueByName(
  319. hkeySubKey,
  320. wszValueName,
  321. pbData,
  322. &cbActualSize);
  323. if (NT_SUCCESS(Status)) {
  324. if ((cbMaxDataSize - cbActualSize) < KREG_SIZE_THRESHOLD) {
  325. //
  326. // Optimization - no need to double allocate if actual size and max
  327. // size are pretty close.
  328. //
  329. *ppValueData = pbData;
  330. pbData = NULL; // "deallocate" pbData
  331. } else {
  332. //
  333. // Big enough difference between actual and max size, warrants
  334. // allocating a smaller buffer.
  335. //
  336. *ppValueData = (PBYTE) kreg_alloc(cbActualSize);
  337. if (*ppValueData == NULL) {
  338. //
  339. // Well, we couldn't "reallocate" a smaller chunk, we'll just
  340. // live on the edge and return the original buffer.
  341. //
  342. *ppValueData = pbData;
  343. pbData = NULL;
  344. } else {
  345. RtlMoveMemory(*ppValueData, pbData, cbActualSize);
  346. }
  347. }
  348. }
  349. Cleanup:
  350. NtClose(hkeySubKey);
  351. if (pbData != NULL) {
  352. kreg_free(pbData);
  353. }
  354. return(Status);
  355. }
  356. //+----------------------------------------------------------------------------
  357. //
  358. // Function: KRegSetValue
  359. //
  360. // Synopsis: Given a Key Name, Value Name, and type, size and data, this
  361. // routine will update the registry's value to the type and data.
  362. // The valuename will be created if it doesn't exist. The key
  363. // must already exist.
  364. //
  365. // Arguments: [wszSubKey] - Name of subkey relative to root key
  366. // [wszValueName] - name of value data
  367. // [ulType] - as in REG_DWORD, REG_SZ, REG_MULTI_SZ, etc.
  368. // [cbSize] - size in bytes of data. If type == REG_SZ, data need
  369. // !not! include the terminating NULL. One will be
  370. // appended as needed.
  371. // [pValueData] - pointer to pointer to byte data.
  372. //
  373. // Returns: STATUS_SUCCESS, STATUS_NO_MEMORY, Status from NtReg api.
  374. //
  375. // Notes: It will allocate memory for the data, and return a pointer to
  376. // it in ppValueData. Caller must free it.
  377. //
  378. //-----------------------------------------------------------------------------
  379. NTSTATUS
  380. KRegSetValue(
  381. IN PWSTR wszSubKey,
  382. IN PWSTR wszValueName,
  383. IN ULONG ulType,
  384. IN ULONG cbSize,
  385. IN PBYTE pValueData
  386. )
  387. {
  388. HKEY hkeySubKey;
  389. NTSTATUS Status;
  390. UNICODE_STRING ustrValueName;
  391. PWSTR pwszValueData;
  392. Status = NtOpenKey(
  393. &hkeySubKey,
  394. KEY_WRITE,
  395. KRegpAttributes(HKEY_ROOT, wszSubKey)
  396. );
  397. KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
  398. RtlInitUnicodeString(&ustrValueName, wszValueName);
  399. if (ulType == REG_SZ) {
  400. pwszValueData = (PWSTR) kreg_alloc(cbSize+sizeof(UNICODE_NULL));
  401. if (pwszValueData == NULL) {
  402. NtClose(hkeySubKey);
  403. return(STATUS_INSUFFICIENT_RESOURCES);
  404. }
  405. RtlMoveMemory((PVOID) pwszValueData, (PVOID) pValueData, cbSize);
  406. pwszValueData[cbSize/sizeof(WCHAR)] = UNICODE_NULL;
  407. cbSize += sizeof(UNICODE_NULL);
  408. } else {
  409. pwszValueData = (PWSTR) pValueData;
  410. }
  411. Status = NtSetValueKey(
  412. hkeySubKey,
  413. &ustrValueName,
  414. 0L, // TitleIndex
  415. ulType,
  416. pwszValueData,
  417. cbSize);
  418. if (ulType == REG_SZ) {
  419. kreg_free(pwszValueData);
  420. }
  421. if (NT_SUCCESS(Status)) {
  422. NtFlushKey(hkeySubKey);
  423. }
  424. NtClose(hkeySubKey);
  425. return(Status);
  426. }
  427. //+----------------------------------------------------------------------------
  428. //
  429. // Function: KRegDeleteValue
  430. //
  431. // Synopsis: Deletes a value name
  432. //
  433. // Arguments: [wszSubKey] -- Name of subkey under which wszValueName exists.
  434. // [wszValueName] -- Name of Value to delete.
  435. //
  436. // Returns:
  437. //
  438. //-----------------------------------------------------------------------------
  439. NTSTATUS KRegDeleteValue(
  440. IN PWSTR wszSubKey,
  441. IN PWSTR wszValueName)
  442. {
  443. HKEY hkeySubKey;
  444. NTSTATUS Status;
  445. UNICODE_STRING ustrValueName;
  446. Status = NtOpenKey(
  447. &hkeySubKey,
  448. KEY_WRITE,
  449. KRegpAttributes(HKEY_ROOT, wszSubKey)
  450. );
  451. KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
  452. RtlInitUnicodeString(&ustrValueName, wszValueName);
  453. Status = NtDeleteValueKey(
  454. hkeySubKey,
  455. &ustrValueName);
  456. if (NT_SUCCESS(Status)) {
  457. NtFlushKey(hkeySubKey);
  458. }
  459. NtClose(hkeySubKey);
  460. return(Status);
  461. }
  462. //+----------------------------------------------------------------------------
  463. //
  464. // Function: KRegGetNumValuesAndSubKeys
  465. //
  466. // Synopsis: Given a Subkey, return how many subkeys and values it has.
  467. //
  468. // Arguments: [wszSubKey] - for which info is required.
  469. // [plNumValues] - receives number of values this subkey has.
  470. // [plNumSubKeys] - receives number of subkeys under this subkey.
  471. //
  472. // Returns: STATUS_SUCCESS, or Status from NtRegAPI.
  473. //
  474. //-----------------------------------------------------------------------------
  475. NTSTATUS
  476. KRegGetNumValuesAndSubKeys(
  477. IN PWSTR wszSubKey,
  478. OUT PULONG pcNumValues,
  479. OUT PULONG pcNumSubKeys
  480. )
  481. {
  482. HKEY hKeySubKey;
  483. ULONG dwUnused;
  484. NTSTATUS Status;
  485. Status = NtOpenKey(
  486. &hKeySubKey,
  487. KEY_READ,
  488. KRegpAttributes(HKEY_ROOT, wszSubKey)
  489. );
  490. KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
  491. Status = KRegpGetKeyInfo(
  492. hKeySubKey,
  493. pcNumSubKeys, // Number of Subkeys
  494. &dwUnused, // Max size of subkey length
  495. pcNumValues, // # of Values
  496. &dwUnused, // Max size of value Name
  497. &dwUnused // Max size of value Data
  498. );
  499. if (!NT_SUCCESS(Status)) {
  500. kreg_debug_out(szErrorRead, wszSubKey);
  501. NtClose(hKeySubKey);
  502. return(Status);
  503. }
  504. NtClose(hKeySubKey);
  505. return(Status);
  506. }
  507. //+----------------------------------------------------------------------------
  508. //
  509. // Function: KRegEnumValueSet
  510. //
  511. // Synopsis: Given a subkey, return the names and data for all its values.
  512. //
  513. // Arguments: [wszSubKey] - Name of subkey to read.
  514. // [pcMaxElements] - On return, contains number of names and
  515. // data actually read.
  516. // [pawszValueNames] - Pointer to array of PWSTRS. This routine
  517. // will allocate memory for the array and the
  518. // strings.
  519. // [papbValueData] - pointer to array of PBYTES. This routine
  520. // will allocate the array and the memory for the
  521. // data, stuffing the pointers to data into this
  522. // array.
  523. // [paValueStatus] - Status of reading the corresponding Value. The
  524. // array will be allocated here.
  525. //
  526. // Returns: STATUS_SUCCESS, STATUS_NO_MEMORY, or Status from NtRegAPI.
  527. //
  528. // Notes: Returned Value Names are always NULL terminated.
  529. // If the Value Data is of type REG_SZ, it, too, is NULL terminated
  530. // Caller frees the last three OUT params (and the contents of
  531. // awszValueNames and apbValueData!) only on SUCCESSFUL return.
  532. //
  533. //-----------------------------------------------------------------------------
  534. NTSTATUS
  535. KRegEnumValueSet(
  536. IN PWSTR wszSubKey,
  537. OUT PULONG pcMaxElements,
  538. OUT APWSTR *pawszValueNames,
  539. OUT APBYTE *papbValueData,
  540. OUT ANTSTATUS *paValueStatus
  541. )
  542. {
  543. ULONG i = 0;
  544. HKEY hKeySubKey;
  545. ULONG dwUnused, cbMaxNameSize, cbMaxDataSize;
  546. PWSTR wszName = NULL;
  547. PBYTE pbData = NULL;
  548. NTSTATUS Status;
  549. APWSTR awszValueNames;
  550. APBYTE apbValueData;
  551. ANTSTATUS aValueStatus;
  552. ULONG cMaxElements;
  553. awszValueNames = *pawszValueNames = NULL;
  554. apbValueData = *papbValueData = NULL;
  555. aValueStatus = *paValueStatus = NULL;
  556. Status = NtOpenKey(
  557. &hKeySubKey,
  558. KEY_READ,
  559. KRegpAttributes(HKEY_ROOT, wszSubKey)
  560. );
  561. KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
  562. Status = KRegpGetKeyInfo(
  563. hKeySubKey,
  564. &dwUnused, // Number of Subkeys
  565. &dwUnused, // Max size of subkey length
  566. &cMaxElements, // # of Values
  567. &cbMaxNameSize, // Max size of value Name
  568. &cbMaxDataSize // Max size of value Data
  569. );
  570. if (!NT_SUCCESS(Status)) {
  571. kreg_debug_out(szErrorRead, wszSubKey);
  572. NtClose(hKeySubKey);
  573. return(Status);
  574. }
  575. //
  576. // Allocate memory for the arrays.
  577. //
  578. awszValueNames = *pawszValueNames = kreg_alloc(cMaxElements * sizeof(PWSTR));
  579. apbValueData = *papbValueData = kreg_alloc(cMaxElements * sizeof(PBYTE));
  580. aValueStatus = *paValueStatus = kreg_alloc(cMaxElements * sizeof(NTSTATUS));
  581. if (awszValueNames == NULL || apbValueData == NULL || aValueStatus == NULL) {
  582. Status = STATUS_NO_MEMORY;
  583. goto Cleanup;
  584. }
  585. //
  586. // Initialize the arrays
  587. //
  588. RtlZeroMemory(awszValueNames, cMaxElements * sizeof(PWSTR));
  589. RtlZeroMemory(apbValueData, cMaxElements * sizeof(PBYTE));
  590. RtlZeroMemory(aValueStatus, cMaxElements * sizeof(NTSTATUS));
  591. //
  592. // For name, we need an extra spot for the terminating NULL
  593. //
  594. wszName = kreg_alloc(cbMaxNameSize + sizeof(WCHAR));
  595. pbData = kreg_alloc(cbMaxDataSize);
  596. if (pbData == NULL || wszName == NULL) {
  597. Status = STATUS_NO_MEMORY;
  598. goto Cleanup;
  599. }
  600. for (i = 0; i < cMaxElements; i++) {
  601. ULONG cbActualNameSize, cbActualDataSize;
  602. cbActualNameSize = cbMaxNameSize;
  603. cbActualDataSize = cbMaxDataSize;
  604. Status = KRegpEnumKeyValues(
  605. hKeySubKey,
  606. i,
  607. wszName,
  608. &cbActualNameSize,
  609. pbData,
  610. &cbActualDataSize
  611. );
  612. if (Status == STATUS_NO_MORE_ENTRIES) {
  613. Status = STATUS_SUCCESS;
  614. break;
  615. } else if (!NT_SUCCESS(Status)) {
  616. aValueStatus[i] = Status;
  617. continue;
  618. } else {
  619. aValueStatus[i] = Status;
  620. }
  621. cbActualNameSize += sizeof(WCHAR); // For terminating NULL
  622. awszValueNames[i] = (PWSTR) kreg_alloc(cbActualNameSize);
  623. apbValueData[i] = (PBYTE) kreg_alloc(cbActualDataSize);
  624. if (apbValueData[i] == NULL || awszValueNames[i] == NULL) {
  625. Status = aValueStatus[i] = STATUS_NO_MEMORY;
  626. goto Cleanup;
  627. }
  628. RtlMoveMemory(awszValueNames[i], wszName, cbActualNameSize);
  629. RtlMoveMemory(apbValueData[i], pbData, cbActualDataSize);
  630. }
  631. Cleanup:
  632. NtClose(hKeySubKey);
  633. if (wszName != NULL) {
  634. kreg_free(wszName);
  635. }
  636. if (pbData != NULL) {
  637. kreg_free(pbData);
  638. }
  639. if (!NT_SUCCESS(Status)) {
  640. *pcMaxElements = 0;
  641. KRegFreeArray(i+1, (APBYTE) awszValueNames);
  642. KRegFreeArray(i+1, apbValueData);
  643. if (aValueStatus != NULL) {
  644. kreg_free(aValueStatus);
  645. }
  646. } else { // Status success
  647. *pcMaxElements = i;
  648. }
  649. return(Status);
  650. }
  651. //+----------------------------------------------------------------------------
  652. //
  653. // Function: KRegEnumSubKeySet
  654. //
  655. // Synopsis: This one's slightly trick. Given a Subkey, it returns an array
  656. // of its subkey-names. The following is true - say the root is
  657. // /a/b/c. Say wszSubKey is d. Say d has subkeys s1, s2, and s3.
  658. // Then the array of subkey-names returned will contain the names
  659. // d/s1, d/s2, d/s3.
  660. //
  661. // Arguments: [wszSubKey] - the Subkey relative to the root.
  662. // [pcMaxElements] - On return, # subkeys actually being returned.
  663. // [awszValueNames] - Unitialized array of PWSTR (room for at least
  664. // *plMaxElements). This routine will allocate
  665. // memory for the subkey names, and fill in this
  666. // array with pointers to them.
  667. //
  668. // Returns:
  669. //
  670. // Notes: Caller must free at most *plMaxElements members of
  671. // awszSubKeyNames. See synopsis above for form of subkey names.
  672. //
  673. //-----------------------------------------------------------------------------
  674. NTSTATUS
  675. KRegEnumSubKeySet(
  676. IN PWSTR wszSubKey,
  677. IN OUT PULONG pcMaxElements,
  678. OUT APWSTR *pawszSubKeyNames
  679. )
  680. {
  681. ULONG i, j = 0;
  682. APWSTR awszSubKeyNames = NULL;
  683. PWSTR wszBuffer = NULL;
  684. HKEY hKeySubKey;
  685. ULONG dwUnused, cbMaxNameSize, cwszSubKey;
  686. NTSTATUS Status;
  687. cwszSubKey = wcslen(wszSubKey);
  688. *pawszSubKeyNames = NULL;
  689. Status = NtOpenKey(
  690. &hKeySubKey,
  691. KEY_READ,
  692. KRegpAttributes(HKEY_ROOT, wszSubKey)
  693. );
  694. KREG_CHECK_HARD_STATUS(Status, szErrorOpen, wszSubKey);
  695. Status = KRegpGetKeyInfo(
  696. hKeySubKey,
  697. pcMaxElements, // Number of Subkeys
  698. &cbMaxNameSize, // Max size of subkey name
  699. &dwUnused, // # of Values
  700. &dwUnused, // Max size of value Name
  701. &dwUnused // Max size of value Data
  702. );
  703. if (pcMaxElements == 0) {
  704. NtClose(hKeySubKey);
  705. *pawszSubKeyNames = NULL;
  706. return(STATUS_SUCCESS);
  707. }
  708. if (!NT_SUCCESS(Status)) {
  709. kreg_debug_out(szErrorRead, wszSubKey);
  710. goto Cleanup;
  711. }
  712. *pawszSubKeyNames = kreg_alloc(
  713. (*pcMaxElements + 1) * sizeof(PWSTR)
  714. );
  715. awszSubKeyNames = *pawszSubKeyNames;
  716. wszBuffer = kreg_alloc(cbMaxNameSize + sizeof(WCHAR));
  717. if (wszBuffer == NULL || awszSubKeyNames == NULL) {
  718. Status = STATUS_NO_MEMORY;
  719. goto Cleanup;
  720. } else {
  721. RtlZeroMemory(awszSubKeyNames, (*pcMaxElements + 1) * sizeof(PWSTR));
  722. }
  723. for (i = j = 0; j < *pcMaxElements; i++) {
  724. ULONG cbActualNameSize, cNameIndex;
  725. cbActualNameSize = cbMaxNameSize;
  726. Status = KRegpEnumSubKeys(
  727. hKeySubKey,
  728. i,
  729. wszBuffer,
  730. &cbActualNameSize
  731. );
  732. if (Status == STATUS_NO_MORE_ENTRIES) {
  733. Status = STATUS_SUCCESS;
  734. break;
  735. } else if (!NT_SUCCESS(Status)) {
  736. continue;
  737. }
  738. cbActualNameSize += sizeof(WCHAR); // for terminating NULL
  739. awszSubKeyNames[j] = (PWSTR) kreg_alloc(
  740. cwszSubKey * sizeof(WCHAR) +
  741. sizeof(WCHAR) + // for backslash
  742. cbActualNameSize
  743. );
  744. if (awszSubKeyNames[j] == NULL) {
  745. Status = STATUS_NO_MEMORY;
  746. goto Cleanup;
  747. } else {
  748. RtlZeroMemory(
  749. awszSubKeyNames[j],
  750. cwszSubKey * sizeof(WCHAR) +
  751. sizeof(WCHAR) + // for backslash
  752. cbActualNameSize);
  753. if (wszSubKey[0] != UNICODE_NULL) {
  754. wcscpy(awszSubKeyNames[j], wszSubKey);
  755. wcscat(awszSubKeyNames[j], UNICODE_PATH_SEP_STR);
  756. cNameIndex = cwszSubKey + 1;
  757. } else {
  758. cNameIndex = 0;
  759. }
  760. RtlMoveMemory(
  761. &awszSubKeyNames[j][cNameIndex],
  762. wszBuffer,
  763. cbActualNameSize);
  764. j++;
  765. }
  766. }
  767. Cleanup:
  768. NtClose(hKeySubKey);
  769. if (wszBuffer != NULL) {
  770. kreg_free(wszBuffer);
  771. }
  772. if (!NT_SUCCESS(Status)) {
  773. *pcMaxElements = 0;
  774. KRegFreeArray(j, (APBYTE) awszSubKeyNames);
  775. } else { // status success
  776. *pcMaxElements = j;
  777. }
  778. return(Status);
  779. }
  780. //+----------------------------------------------------------------------------
  781. //
  782. // Function: KRegFreeArray
  783. //
  784. // Synopsis: Given an array of pointers, frees the pointers and the array.
  785. //
  786. // Arguments: [cElements] - Number of elements to free. Some elements can be
  787. // NULL.
  788. // [pa] - pointer to the array.
  789. //
  790. // Returns: Nothing
  791. //
  792. //-----------------------------------------------------------------------------
  793. VOID
  794. KRegFreeArray(
  795. IN ULONG cElements,
  796. IN APBYTE pa)
  797. {
  798. ULONG i;
  799. if (pa != NULL) {
  800. for (i = 0; i < cElements; i++) {
  801. if (pa[i] != NULL) {
  802. kreg_free(pa[i]);
  803. }
  804. }
  805. kreg_free(pa);
  806. }
  807. }