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.

1058 lines
27 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. ntreg.c
  5. Abstract:
  6. This source file contains the routines to to access the NT Registry for
  7. configuration info.
  8. Author:
  9. Mike Massa (mikemas) September 3, 1993
  10. (taken from routines by jballard)
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "internaldef.h"
  15. #define WORK_BUFFER_SIZE 512
  16. //
  17. // Local function prototypes
  18. //
  19. NTSTATUS
  20. OpenRegKey(
  21. PHANDLE HandlePtr,
  22. PWCHAR KeyName
  23. );
  24. NTSTATUS
  25. GetRegDWORDValue(
  26. HANDLE KeyHandle,
  27. PWCHAR ValueName,
  28. PULONG ValueData
  29. );
  30. NTSTATUS
  31. GetRegLARGEINTValue(
  32. HANDLE KeyHandle,
  33. PWCHAR ValueName,
  34. PLARGE_INTEGER ValueData
  35. );
  36. NTSTATUS
  37. SetRegDWORDValue(
  38. HANDLE KeyHandle,
  39. PWCHAR ValueName,
  40. PULONG ValueData
  41. );
  42. NTSTATUS
  43. SetRegMultiSZValue(
  44. HANDLE KeyHandle,
  45. PWCHAR ValueName,
  46. PUNICODE_STRING ValueData
  47. );
  48. NTSTATUS
  49. SetRegMultiSZValueNew(
  50. HANDLE KeyHandle,
  51. PWCHAR ValueName,
  52. PUNICODE_STRING_NEW ValueData
  53. );
  54. NTSTATUS
  55. GetRegStringValueNew(
  56. HANDLE KeyHandle,
  57. PWCHAR ValueName,
  58. PKEY_VALUE_PARTIAL_INFORMATION * ValueData,
  59. PULONG ValueSize
  60. );
  61. NTSTATUS
  62. GetRegStringValue(
  63. HANDLE KeyHandle,
  64. PWCHAR ValueName,
  65. PKEY_VALUE_PARTIAL_INFORMATION * ValueData,
  66. PUSHORT ValueSize
  67. );
  68. NTSTATUS
  69. GetRegSZValue(
  70. HANDLE KeyHandle,
  71. PWCHAR ValueName,
  72. PUNICODE_STRING ValueData,
  73. PULONG ValueType
  74. );
  75. NTSTATUS
  76. GetRegMultiSZValue(
  77. HANDLE KeyHandle,
  78. PWCHAR ValueName,
  79. PUNICODE_STRING ValueData
  80. );
  81. NTSTATUS
  82. GetRegMultiSZValueNew(
  83. HANDLE KeyHandle,
  84. PWCHAR ValueName,
  85. PUNICODE_STRING_NEW ValueData
  86. );
  87. NTSTATUS
  88. InitRegDWORDParameter(
  89. HANDLE RegKey,
  90. PWCHAR ValueName,
  91. ULONG * Value,
  92. ULONG DefaultValue
  93. );
  94. #if !MILLEN
  95. #ifdef ALLOC_PRAGMA
  96. //
  97. // All of the init code can be discarded
  98. //
  99. #pragma alloc_text(PAGE, GetRegDWORDValue)
  100. #pragma alloc_text(PAGE, GetRegLARGEINTValue)
  101. #pragma alloc_text(PAGE, SetRegDWORDValue)
  102. #pragma alloc_text(PAGE, InitRegDWORDParameter)
  103. //
  104. // This code is pagable.
  105. //
  106. #pragma alloc_text(PAGE, OpenRegKey)
  107. #pragma alloc_text(PAGE, GetRegStringValue)
  108. #pragma alloc_text(PAGE, GetRegStringValueNew)
  109. #pragma alloc_text(PAGE, GetRegSZValue)
  110. #pragma alloc_text(PAGE, GetRegMultiSZValue)
  111. #pragma alloc_text(PAGE, GetRegMultiSZValueNew)
  112. #endif // ALLOC_PRAGMA
  113. #endif // !MILLEN
  114. #if DBG
  115. ULONG IPDebug = 0;
  116. #endif
  117. //
  118. // Function definitions
  119. //
  120. NTSTATUS
  121. OpenRegKey(
  122. PHANDLE HandlePtr,
  123. PWCHAR KeyName
  124. )
  125. /*++
  126. Routine Description:
  127. Opens a Registry key and returns a handle to it.
  128. Arguments:
  129. HandlePtr - The varible into which to write the opened handle.
  130. KeyName - The name of the Registry key to open.
  131. Return Value:
  132. STATUS_SUCCESS or an appropriate failure code.
  133. --*/
  134. {
  135. NTSTATUS Status;
  136. OBJECT_ATTRIBUTES ObjectAttributes;
  137. UNICODE_STRING UKeyName;
  138. PAGED_CODE();
  139. RtlInitUnicodeString(&UKeyName, KeyName);
  140. memset(&ObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  141. InitializeObjectAttributes(&ObjectAttributes,
  142. &UKeyName,
  143. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  144. NULL,
  145. NULL);
  146. Status = ZwOpenKey(HandlePtr,
  147. KEY_READ,
  148. &ObjectAttributes);
  149. return Status;
  150. }
  151. #if MILLEN
  152. ulong
  153. ConvertDecimalString(PWCHAR pString)
  154. {
  155. ulong dwTemp = 0;
  156. while (*pString)
  157. {
  158. if (*pString >= L'0' && *pString <= L'9')
  159. dwTemp = dwTemp * 10 + (*pString - L'0');
  160. else
  161. break;
  162. pString++;
  163. }
  164. return(dwTemp);
  165. }
  166. #endif // MILLEN
  167. NTSTATUS
  168. GetRegDWORDValue(
  169. HANDLE KeyHandle,
  170. PWCHAR ValueName,
  171. PULONG ValueData
  172. )
  173. /*++
  174. Routine Description:
  175. Reads a REG_DWORD value from the registry into the supplied variable.
  176. Arguments:
  177. KeyHandle - Open handle to the parent key of the value to read.
  178. ValueName - The name of the value to read.
  179. ValueData - The variable into which to read the data.
  180. Return Value:
  181. STATUS_SUCCESS or an appropriate failure code.
  182. --*/
  183. {
  184. NTSTATUS status;
  185. ULONG resultLength;
  186. PKEY_VALUE_FULL_INFORMATION keyValueFullInformation;
  187. UCHAR keybuf[WORK_BUFFER_SIZE];
  188. UNICODE_STRING UValueName;
  189. PAGED_CODE();
  190. RtlInitUnicodeString(&UValueName, ValueName);
  191. keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION) keybuf;
  192. RtlZeroMemory(keyValueFullInformation, sizeof(keyValueFullInformation));
  193. status = ZwQueryValueKey(KeyHandle,
  194. &UValueName,
  195. KeyValueFullInformation,
  196. keyValueFullInformation,
  197. WORK_BUFFER_SIZE,
  198. &resultLength);
  199. if (NT_SUCCESS(status)) {
  200. if (keyValueFullInformation->Type == REG_DWORD) {
  201. *ValueData = *((ULONG UNALIGNED *) ((PCHAR) keyValueFullInformation +
  202. keyValueFullInformation->DataOffset));
  203. #if MILLEN
  204. } else if (keyValueFullInformation->Type == REG_SZ) {
  205. PWCHAR Data;
  206. Data = (PWCHAR) ((PCHAR) keyValueFullInformation +
  207. keyValueFullInformation->DataOffset);
  208. // On Millennium, we need to support legacy of reading registry
  209. // keys as strings and converting to a DWORD.
  210. *ValueData = ConvertDecimalString(Data);
  211. #endif // !MILLEN
  212. } else {
  213. status = STATUS_INVALID_PARAMETER_MIX;
  214. }
  215. }
  216. return status;
  217. }
  218. NTSTATUS
  219. GetRegLARGEINTValue(
  220. HANDLE KeyHandle,
  221. PWCHAR ValueName,
  222. PLARGE_INTEGER ValueData
  223. )
  224. /*++
  225. Routine Description:
  226. Reads a REG_DWORD value from the registry into the supplied variable.
  227. Arguments:
  228. KeyHandle - Open handle to the parent key of the value to read.
  229. ValueName - The name of the value to read.
  230. ValueData - The variable into which to read the data.
  231. Return Value:
  232. STATUS_SUCCESS or an appropriate failure code.
  233. --*/
  234. {
  235. NTSTATUS status;
  236. ULONG resultLength;
  237. PKEY_VALUE_FULL_INFORMATION keyValueFullInformation;
  238. UCHAR keybuf[WORK_BUFFER_SIZE];
  239. UNICODE_STRING UValueName;
  240. PAGED_CODE();
  241. RtlInitUnicodeString(&UValueName, ValueName);
  242. keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION) keybuf;
  243. RtlZeroMemory(keyValueFullInformation, sizeof(keyValueFullInformation));
  244. status = ZwQueryValueKey(KeyHandle,
  245. &UValueName,
  246. KeyValueFullInformation,
  247. keyValueFullInformation,
  248. WORK_BUFFER_SIZE,
  249. &resultLength);
  250. if (NT_SUCCESS(status)) {
  251. if (keyValueFullInformation->Type != REG_BINARY) {
  252. status = STATUS_INVALID_PARAMETER_MIX;
  253. } else {
  254. *ValueData = *((LARGE_INTEGER UNALIGNED *) ((PCHAR) keyValueFullInformation +
  255. keyValueFullInformation->DataOffset));
  256. }
  257. }
  258. return status;
  259. }
  260. NTSTATUS
  261. SetRegDWORDValue(
  262. HANDLE KeyHandle,
  263. PWCHAR ValueName,
  264. PULONG ValueData
  265. )
  266. /*++
  267. Routine Description:
  268. Writes the contents of a variable to a REG_DWORD value.
  269. Arguments:
  270. KeyHandle - Open handle to the parent key of the value to write.
  271. ValueName - The name of the value to write.
  272. ValueData - The variable from which to write the data.
  273. Return Value:
  274. STATUS_SUCCESS or an appropriate failure code.
  275. --*/
  276. {
  277. NTSTATUS status;
  278. UNICODE_STRING UValueName;
  279. PAGED_CODE();
  280. RtlInitUnicodeString(&UValueName, ValueName);
  281. status = ZwSetValueKey(KeyHandle,
  282. &UValueName,
  283. 0,
  284. REG_DWORD,
  285. ValueData,
  286. sizeof(ULONG));
  287. return status;
  288. }
  289. NTSTATUS
  290. SetRegMultiSZValue(
  291. HANDLE KeyHandle,
  292. PWCHAR ValueName,
  293. PUNICODE_STRING ValueData
  294. )
  295. /*++
  296. Routine Description:
  297. Writes the contents of a variable to a REG_DWORD value.
  298. Arguments:
  299. KeyHandle - Open handle to the parent key of the value to write.
  300. ValueName - The name of the value to write.
  301. ValueData - The variable from which to write the data.
  302. Return Value:
  303. STATUS_SUCCESS or an appropriate failure code.
  304. --*/
  305. {
  306. NTSTATUS status;
  307. UNICODE_STRING UValueName;
  308. #if MILLEN
  309. LONG i;
  310. PWCHAR Buf = ValueData->Buffer;
  311. #endif // MILLEN
  312. PAGED_CODE();
  313. #if MILLEN
  314. // Convert it to a SZ string
  315. while (*Buf != UNICODE_NULL) {
  316. while (*Buf++ != UNICODE_NULL);
  317. if (*Buf != UNICODE_NULL) {
  318. *(Buf-1) = L',';
  319. }
  320. }
  321. #endif // MILLEN
  322. RtlInitUnicodeString(&UValueName, ValueName);
  323. status = ZwSetValueKey(KeyHandle,
  324. &UValueName,
  325. 0,
  326. #if MILLEN
  327. REG_SZ,
  328. #else // MILLEN
  329. REG_MULTI_SZ,
  330. #endif // !MILLEN
  331. ValueData->Buffer,
  332. ValueData->Length);
  333. return status;
  334. }
  335. NTSTATUS
  336. SetRegMultiSZValueNew(
  337. HANDLE KeyHandle,
  338. PWCHAR ValueName,
  339. PUNICODE_STRING_NEW ValueData
  340. )
  341. /*++
  342. Routine Description:
  343. Writes the contents of a variable to a REG_DWORD value, using a structure
  344. which accommodates >64K bytes.
  345. Arguments:
  346. KeyHandle - Open handle to the parent key of the value to write.
  347. ValueName - The name of the value to write.
  348. ValueData - The variable from which to write the data.
  349. Return Value:
  350. STATUS_SUCCESS or an appropriate failure code.
  351. --*/
  352. {
  353. NTSTATUS status;
  354. UNICODE_STRING UValueName;
  355. #if MILLEN
  356. LONG i;
  357. PWCHAR Buf = ValueData->Buffer;
  358. #endif // MILLEN
  359. PAGED_CODE();
  360. #if MILLEN
  361. // Convert it to a SZ string
  362. while (*Buf != UNICODE_NULL) {
  363. while (*Buf++ != UNICODE_NULL);
  364. if (*Buf != UNICODE_NULL) {
  365. *(Buf-1) = L',';
  366. }
  367. }
  368. #endif // MILLEN
  369. RtlInitUnicodeString(&UValueName, ValueName);
  370. status = ZwSetValueKey(KeyHandle,
  371. &UValueName,
  372. 0,
  373. #if MILLEN
  374. REG_SZ,
  375. #else // MILLEN
  376. REG_MULTI_SZ,
  377. #endif // !MILLEN
  378. ValueData->Buffer,
  379. ValueData->Length);
  380. return status;
  381. }
  382. NTSTATUS
  383. GetRegStringValueNew(
  384. HANDLE KeyHandle,
  385. PWCHAR ValueName,
  386. PKEY_VALUE_PARTIAL_INFORMATION * ValueData,
  387. PULONG ValueSize
  388. )
  389. /*++
  390. Routine Description:
  391. Reads a REG_*_SZ string value from the Registry into the supplied
  392. key value buffer. If the buffer string buffer is not large enough,
  393. it is reallocated.
  394. Arguments:
  395. KeyHandle - Open handle to the parent key of the value to read.
  396. ValueName - The name of the value to read.
  397. ValueData - Destination for the read data.
  398. ValueSize - Size of the ValueData buffer. Updated on output.
  399. Return Value:
  400. STATUS_SUCCESS or an appropriate failure code.
  401. --*/
  402. {
  403. NTSTATUS status;
  404. ULONG resultLength;
  405. UNICODE_STRING UValueName;
  406. PAGED_CODE();
  407. RtlInitUnicodeString(&UValueName, ValueName);
  408. status = ZwQueryValueKey(
  409. KeyHandle,
  410. &UValueName,
  411. KeyValuePartialInformation,
  412. *ValueData,
  413. (ULONG) * ValueSize,
  414. &resultLength
  415. );
  416. if ((status == STATUS_BUFFER_OVERFLOW) ||
  417. (status == STATUS_BUFFER_TOO_SMALL)
  418. ) {
  419. PVOID temp;
  420. //
  421. // Free the old buffer and allocate a new one of the
  422. // appropriate size.
  423. //
  424. ASSERT(resultLength > *ValueSize);
  425. temp = ExAllocatePoolWithTag(NonPagedPool, resultLength, 'iPCT');
  426. if (temp != NULL) {
  427. if (*ValueData != NULL) {
  428. CTEFreeMem(*ValueData);
  429. }
  430. *ValueData = temp;
  431. *ValueSize = resultLength;
  432. status = ZwQueryValueKey(KeyHandle,
  433. &UValueName,
  434. KeyValuePartialInformation,
  435. *ValueData,
  436. *ValueSize,
  437. &resultLength
  438. );
  439. ASSERT((status != STATUS_BUFFER_OVERFLOW) &&
  440. (status != STATUS_BUFFER_TOO_SMALL)
  441. );
  442. } else {
  443. status = STATUS_INSUFFICIENT_RESOURCES;
  444. }
  445. }
  446. return (status);
  447. }
  448. NTSTATUS
  449. GetRegStringValue(
  450. HANDLE KeyHandle,
  451. PWCHAR ValueName,
  452. PKEY_VALUE_PARTIAL_INFORMATION * ValueData,
  453. PUSHORT ValueSize
  454. )
  455. /*++
  456. Routine Description:
  457. Reads a REG_*_SZ string value from the Registry into the supplied
  458. key value buffer. If the buffer string buffer is not large enough,
  459. it is reallocated.
  460. Arguments:
  461. KeyHandle - Open handle to the parent key of the value to read.
  462. ValueName - The name of the value to read.
  463. ValueData - Destination for the read data.
  464. ValueSize - Size of the ValueData buffer. Updated on output.
  465. Return Value:
  466. STATUS_SUCCESS or an appropriate failure code.
  467. --*/
  468. {
  469. NTSTATUS status;
  470. ULONG resultLength;
  471. UNICODE_STRING UValueName;
  472. PAGED_CODE();
  473. RtlInitUnicodeString(&UValueName, ValueName);
  474. status = ZwQueryValueKey(
  475. KeyHandle,
  476. &UValueName,
  477. KeyValuePartialInformation,
  478. *ValueData,
  479. (ULONG) * ValueSize,
  480. &resultLength
  481. );
  482. if ((status == STATUS_BUFFER_OVERFLOW) ||
  483. (status == STATUS_BUFFER_TOO_SMALL)
  484. ) {
  485. PVOID temp;
  486. //
  487. // Free the old buffer and allocate a new one of the
  488. // appropriate size.
  489. //
  490. ASSERT(resultLength > (ULONG) * ValueSize);
  491. if (resultLength <= 0xFFFF) {
  492. //temp = CTEAllocMem(resultLength);
  493. temp = ExAllocatePoolWithTag(NonPagedPool, resultLength, 'iPCT');
  494. if (temp != NULL) {
  495. if (*ValueData != NULL) {
  496. CTEFreeMem(*ValueData);
  497. }
  498. *ValueData = temp;
  499. *ValueSize = (USHORT) resultLength;
  500. status = ZwQueryValueKey(KeyHandle,
  501. &UValueName,
  502. KeyValuePartialInformation,
  503. *ValueData,
  504. resultLength,
  505. &resultLength
  506. );
  507. ASSERT((status != STATUS_BUFFER_OVERFLOW) &&
  508. (status != STATUS_BUFFER_TOO_SMALL)
  509. );
  510. } else {
  511. status = STATUS_INSUFFICIENT_RESOURCES;
  512. }
  513. } else {
  514. status = STATUS_BUFFER_TOO_SMALL;
  515. }
  516. }
  517. return (status);
  518. }
  519. NTSTATUS
  520. GetRegMultiSZValueNew(
  521. HANDLE KeyHandle,
  522. PWCHAR ValueName,
  523. PUNICODE_STRING_NEW ValueData
  524. )
  525. /*++
  526. Routine Description:
  527. Reads a REG_MULTI_SZ string value from the Registry into the supplied
  528. Unicode string. If the Unicode string buffer is not large enough,
  529. it is reallocated.
  530. Arguments:
  531. KeyHandle - Open handle to the parent key of the value to read.
  532. ValueName - The name of the value to read.
  533. ValueData - Destination Unicode string for the value data.
  534. Return Value:
  535. STATUS_SUCCESS or an appropriate failure code.
  536. --*/
  537. {
  538. NTSTATUS status;
  539. PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
  540. PAGED_CODE();
  541. ValueData->Length = 0;
  542. status = GetRegStringValueNew(
  543. KeyHandle,
  544. ValueName,
  545. (PKEY_VALUE_PARTIAL_INFORMATION *) & (ValueData->Buffer),
  546. &(ValueData->MaximumLength)
  547. );
  548. DEBUGMSG(DBG_ERROR && !NT_SUCCESS(status),
  549. (DTEXT("GetRegStringValueNew failure %x\n"), status));
  550. if (NT_SUCCESS(status)) {
  551. keyValuePartialInformation =
  552. (PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
  553. DEBUGMSG(DBG_INFO && DBG_REG,
  554. (DTEXT("GetRegMultiSZValueNew - retrieved string -- type %x = %s\n"),
  555. keyValuePartialInformation->Type,
  556. keyValuePartialInformation->Type == REG_MULTI_SZ ? TEXT("MULTI-SZ") :
  557. keyValuePartialInformation->Type == REG_SZ ? TEXT("SZ") :
  558. TEXT("OTHER")));
  559. if (keyValuePartialInformation->Type == REG_MULTI_SZ) {
  560. ValueData->Length = keyValuePartialInformation->DataLength;
  561. RtlMoveMemory(
  562. ValueData->Buffer,
  563. &(keyValuePartialInformation->Data),
  564. ValueData->Length
  565. );
  566. #if MILLEN
  567. } else if (keyValuePartialInformation->Type == REG_SZ) {
  568. // Convert it to a MULTI-SZ string
  569. LONG i;
  570. PWCHAR Buf = ValueData->Buffer;
  571. ValueData->Length = keyValuePartialInformation->DataLength;
  572. RtlMoveMemory(
  573. ValueData->Buffer,
  574. &(keyValuePartialInformation->Data),
  575. ValueData->Length
  576. );
  577. for (i = 0; Buf[i] != L'\0'; i++) {
  578. if (L',' == Buf[i]) {
  579. Buf[i] = L'\0';
  580. }
  581. }
  582. // Need an extra NULL at the end.
  583. Buf[++i] = L'\0';
  584. #endif // MILLEN
  585. } else {
  586. status = STATUS_INVALID_PARAMETER_MIX;
  587. }
  588. }
  589. return status;
  590. } // GetRegMultiSZValueNew
  591. NTSTATUS
  592. GetRegMultiSZValue(
  593. HANDLE KeyHandle,
  594. PWCHAR ValueName,
  595. PUNICODE_STRING ValueData
  596. )
  597. /*++
  598. Routine Description:
  599. Reads a REG_MULTI_SZ string value from the Registry into the supplied
  600. Unicode string. If the Unicode string buffer is not large enough,
  601. it is reallocated.
  602. Arguments:
  603. KeyHandle - Open handle to the parent key of the value to read.
  604. ValueName - The name of the value to read.
  605. ValueData - Destination Unicode string for the value data.
  606. Return Value:
  607. STATUS_SUCCESS or an appropriate failure code.
  608. --*/
  609. {
  610. NTSTATUS status;
  611. PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
  612. PAGED_CODE();
  613. ValueData->Length = 0;
  614. status = GetRegStringValue(
  615. KeyHandle,
  616. ValueName,
  617. (PKEY_VALUE_PARTIAL_INFORMATION *) & (ValueData->Buffer),
  618. &(ValueData->MaximumLength)
  619. );
  620. if (NT_SUCCESS(status)) {
  621. keyValuePartialInformation =
  622. (PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
  623. if (keyValuePartialInformation->Type == REG_MULTI_SZ) {
  624. ValueData->Length = (USHORT)
  625. keyValuePartialInformation->DataLength;
  626. RtlMoveMemory(
  627. ValueData->Buffer,
  628. &(keyValuePartialInformation->Data),
  629. ValueData->Length
  630. );
  631. #if MILLEN
  632. } else if (keyValuePartialInformation->Type == REG_SZ) {
  633. // Convert it to a MULTI-SZ string
  634. LONG i;
  635. PWCHAR Buf = ValueData->Buffer;
  636. ValueData->Length = (USHORT) keyValuePartialInformation->DataLength;
  637. RtlMoveMemory(
  638. ValueData->Buffer,
  639. &(keyValuePartialInformation->Data),
  640. ValueData->Length
  641. );
  642. for (i = 0; Buf[i] != L'\0'; i++) {
  643. if (L',' == Buf[i]) {
  644. Buf[i] = L'\0';
  645. }
  646. }
  647. // Need an extra NULL at the end.
  648. Buf[++i] = L'\0';
  649. #endif // MILLEN
  650. } else {
  651. status = STATUS_INVALID_PARAMETER_MIX;
  652. }
  653. }
  654. return status;
  655. } // GetRegMultiSZValue
  656. NTSTATUS
  657. GetRegSZValue(
  658. HANDLE KeyHandle,
  659. PWCHAR ValueName,
  660. PUNICODE_STRING ValueData,
  661. PULONG ValueType
  662. )
  663. /*++
  664. Routine Description:
  665. Reads a REG_SZ string value from the Registry into the supplied
  666. Unicode string. If the Unicode string buffer is not large enough,
  667. it is reallocated.
  668. Arguments:
  669. KeyHandle - Open handle to the parent key of the value to read.
  670. ValueName - The name of the value to read.
  671. ValueData - Destination Unicode string for the value data.
  672. ValueType - On return, contains the Registry type of the value read.
  673. Return Value:
  674. STATUS_SUCCESS or an appropriate failure code.
  675. --*/
  676. {
  677. NTSTATUS status;
  678. PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
  679. PAGED_CODE();
  680. ValueData->Length = 0;
  681. status = GetRegStringValue(
  682. KeyHandle,
  683. ValueName,
  684. (PKEY_VALUE_PARTIAL_INFORMATION *) & (ValueData->Buffer),
  685. &(ValueData->MaximumLength)
  686. );
  687. if (NT_SUCCESS(status)) {
  688. keyValuePartialInformation =
  689. (PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
  690. if ((keyValuePartialInformation->Type == REG_SZ) ||
  691. (keyValuePartialInformation->Type == REG_EXPAND_SZ)
  692. ) {
  693. WCHAR *src;
  694. WCHAR *dst;
  695. ULONG dataLength;
  696. *ValueType = keyValuePartialInformation->Type;
  697. dataLength = keyValuePartialInformation->DataLength;
  698. ASSERT(dataLength <= ValueData->MaximumLength);
  699. dst = ValueData->Buffer;
  700. src = (PWCHAR) & (keyValuePartialInformation->Data);
  701. while (ValueData->Length <= dataLength) {
  702. if ((*dst++ = *src++) == UNICODE_NULL) {
  703. break;
  704. }
  705. ValueData->Length += sizeof(WCHAR);
  706. }
  707. if (ValueData->Length < (ValueData->MaximumLength - 1)) {
  708. ValueData->Buffer[ValueData->Length / sizeof(WCHAR)] =
  709. UNICODE_NULL;
  710. }
  711. } else {
  712. status = STATUS_INVALID_PARAMETER_MIX;
  713. }
  714. }
  715. return status;
  716. }
  717. NTSTATUS
  718. InitRegDWORDParameter(
  719. HANDLE RegKey,
  720. PWCHAR ValueName,
  721. ULONG * Value,
  722. ULONG DefaultValue
  723. )
  724. /*++
  725. Routine Description:
  726. Reads a REG_DWORD parameter from the Registry into a variable. If the
  727. read fails, the variable is initialized to a default.
  728. Arguments:
  729. RegKey - Open handle to the parent key of the value to read.
  730. ValueName - The name of the value to read.
  731. Value - Destination variable into which to read the data.
  732. DefaultValue - Default to assign if the read fails.
  733. Return Value:
  734. STATUS_SUCCESS or an appropriate failure code.
  735. --*/
  736. {
  737. NTSTATUS status;
  738. PAGED_CODE();
  739. status = GetRegDWORDValue(
  740. RegKey,
  741. ValueName,
  742. Value
  743. );
  744. if (!NT_SUCCESS(status)) {
  745. //
  746. // These registry parameters override the defaults, so their
  747. // absence is not an error.
  748. //
  749. *Value = DefaultValue;
  750. }
  751. return (status);
  752. }
  753. PWCHAR
  754. EnumRegMultiSz(
  755. IN PWCHAR MszString,
  756. IN ULONG MszStringLength,
  757. IN ULONG StringIndex
  758. )
  759. /*++
  760. Routine Description:
  761. Parses a REG_MULTI_SZ string and returns the specified substring.
  762. Arguments:
  763. MszString - A pointer to the REG_MULTI_SZ string.
  764. MszStringLength - The length of the REG_MULTI_SZ string, including the
  765. terminating null character.
  766. StringIndex - Index number of the substring to return. Specifiying
  767. index 0 retrieves the first substring.
  768. Return Value:
  769. A pointer to the specified substring.
  770. Notes:
  771. This code is called at raised IRQL. It is not pageable.
  772. --*/
  773. {
  774. PWCHAR string = MszString;
  775. if (MszStringLength < (2 * sizeof(WCHAR))) {
  776. return (NULL);
  777. }
  778. //
  779. // Find the start of the desired string.
  780. //
  781. while (StringIndex) {
  782. while (MszStringLength >= sizeof(WCHAR)) {
  783. MszStringLength -= sizeof(WCHAR);
  784. if (*string++ == UNICODE_NULL) {
  785. break;
  786. }
  787. }
  788. //
  789. // Check for index out of range.
  790. //
  791. if (MszStringLength < (2 * sizeof(UNICODE_NULL))) {
  792. return (NULL);
  793. }
  794. StringIndex--;
  795. }
  796. if (MszStringLength < (2 * sizeof(UNICODE_NULL))) {
  797. return (NULL);
  798. }
  799. return (string);
  800. }
  801.