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.

1063 lines
26 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,
  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. ULONG resultLength;
  540. PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
  541. UNICODE_STRING UValueName;
  542. PAGED_CODE();
  543. ValueData->Length = 0;
  544. status = GetRegStringValueNew(
  545. KeyHandle,
  546. ValueName,
  547. (PKEY_VALUE_PARTIAL_INFORMATION *) & (ValueData->Buffer),
  548. &(ValueData->MaximumLength)
  549. );
  550. DEBUGMSG(DBG_ERROR && !NT_SUCCESS(status),
  551. (DTEXT("GetRegStringValueNew failure %x\n"), status));
  552. if (NT_SUCCESS(status)) {
  553. keyValuePartialInformation =
  554. (PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
  555. DEBUGMSG(DBG_INFO && DBG_REG,
  556. (DTEXT("GetRegMultiSZValueNew - retrieved string -- type %x = %s\n"),
  557. keyValuePartialInformation->Type,
  558. keyValuePartialInformation->Type == REG_MULTI_SZ ? TEXT("MULTI-SZ") :
  559. keyValuePartialInformation->Type == REG_SZ ? TEXT("SZ") :
  560. TEXT("OTHER")));
  561. if (keyValuePartialInformation->Type == REG_MULTI_SZ) {
  562. ValueData->Length = keyValuePartialInformation->DataLength;
  563. RtlCopyMemory(
  564. ValueData->Buffer,
  565. &(keyValuePartialInformation->Data),
  566. ValueData->Length
  567. );
  568. #if MILLEN
  569. } else if (keyValuePartialInformation->Type == REG_SZ) {
  570. // Convert it to a MULTI-SZ string
  571. LONG i;
  572. PWCHAR Buf = ValueData->Buffer;
  573. ValueData->Length = keyValuePartialInformation->DataLength;
  574. RtlCopyMemory(
  575. ValueData->Buffer,
  576. &(keyValuePartialInformation->Data),
  577. ValueData->Length
  578. );
  579. for (i = 0; Buf[i] != L'\0'; i++) {
  580. if (L',' == Buf[i]) {
  581. Buf[i] = L'\0';
  582. }
  583. }
  584. // Need an extra NULL at the end.
  585. Buf[++i] = L'\0';
  586. #endif // MILLEN
  587. } else {
  588. status = STATUS_INVALID_PARAMETER_MIX;
  589. }
  590. }
  591. return status;
  592. } // GetRegMultiSZValueNew
  593. NTSTATUS
  594. GetRegMultiSZValue(
  595. HANDLE KeyHandle,
  596. PWCHAR ValueName,
  597. PUNICODE_STRING ValueData
  598. )
  599. /*++
  600. Routine Description:
  601. Reads a REG_MULTI_SZ string value from the Registry into the supplied
  602. Unicode string. If the Unicode string buffer is not large enough,
  603. it is reallocated.
  604. Arguments:
  605. KeyHandle - Open handle to the parent key of the value to read.
  606. ValueName - The name of the value to read.
  607. ValueData - Destination Unicode string for the value data.
  608. Return Value:
  609. STATUS_SUCCESS or an appropriate failure code.
  610. --*/
  611. {
  612. NTSTATUS status;
  613. ULONG resultLength;
  614. PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
  615. UNICODE_STRING UValueName;
  616. PAGED_CODE();
  617. ValueData->Length = 0;
  618. status = GetRegStringValue(
  619. KeyHandle,
  620. ValueName,
  621. (PKEY_VALUE_PARTIAL_INFORMATION *) & (ValueData->Buffer),
  622. &(ValueData->MaximumLength)
  623. );
  624. if (NT_SUCCESS(status)) {
  625. keyValuePartialInformation =
  626. (PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
  627. if (keyValuePartialInformation->Type == REG_MULTI_SZ) {
  628. ValueData->Length = (USHORT)
  629. keyValuePartialInformation->DataLength;
  630. RtlCopyMemory(
  631. ValueData->Buffer,
  632. &(keyValuePartialInformation->Data),
  633. ValueData->Length
  634. );
  635. #if MILLEN
  636. } else if (keyValuePartialInformation->Type == REG_SZ) {
  637. // Convert it to a MULTI-SZ string
  638. LONG i;
  639. PWCHAR Buf = ValueData->Buffer;
  640. ValueData->Length = (USHORT) keyValuePartialInformation->DataLength;
  641. RtlCopyMemory(
  642. ValueData->Buffer,
  643. &(keyValuePartialInformation->Data),
  644. ValueData->Length
  645. );
  646. for (i = 0; Buf[i] != L'\0'; i++) {
  647. if (L',' == Buf[i]) {
  648. Buf[i] = L'\0';
  649. }
  650. }
  651. // Need an extra NULL at the end.
  652. Buf[++i] = L'\0';
  653. #endif // MILLEN
  654. } else {
  655. status = STATUS_INVALID_PARAMETER_MIX;
  656. }
  657. }
  658. return status;
  659. } // GetRegMultiSZValue
  660. NTSTATUS
  661. GetRegSZValue(
  662. HANDLE KeyHandle,
  663. PWCHAR ValueName,
  664. PUNICODE_STRING ValueData,
  665. PULONG ValueType
  666. )
  667. /*++
  668. Routine Description:
  669. Reads a REG_SZ string value from the Registry into the supplied
  670. Unicode string. If the Unicode string buffer is not large enough,
  671. it is reallocated.
  672. Arguments:
  673. KeyHandle - Open handle to the parent key of the value to read.
  674. ValueName - The name of the value to read.
  675. ValueData - Destination Unicode string for the value data.
  676. ValueType - On return, contains the Registry type of the value read.
  677. Return Value:
  678. STATUS_SUCCESS or an appropriate failure code.
  679. --*/
  680. {
  681. NTSTATUS status;
  682. ULONG resultLength;
  683. PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
  684. UNICODE_STRING UValueName;
  685. PAGED_CODE();
  686. ValueData->Length = 0;
  687. status = GetRegStringValue(
  688. KeyHandle,
  689. ValueName,
  690. (PKEY_VALUE_PARTIAL_INFORMATION *) & (ValueData->Buffer),
  691. &(ValueData->MaximumLength)
  692. );
  693. if (NT_SUCCESS(status)) {
  694. keyValuePartialInformation =
  695. (PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
  696. if ((keyValuePartialInformation->Type == REG_SZ) ||
  697. (keyValuePartialInformation->Type == REG_EXPAND_SZ)
  698. ) {
  699. WCHAR *src;
  700. WCHAR *dst;
  701. ULONG dataLength;
  702. *ValueType = keyValuePartialInformation->Type;
  703. dataLength = keyValuePartialInformation->DataLength;
  704. ASSERT(dataLength <= ValueData->MaximumLength);
  705. dst = ValueData->Buffer;
  706. src = (PWCHAR) & (keyValuePartialInformation->Data);
  707. while (ValueData->Length <= dataLength) {
  708. if ((*dst++ = *src++) == UNICODE_NULL) {
  709. break;
  710. }
  711. ValueData->Length += sizeof(WCHAR);
  712. }
  713. if (ValueData->Length < (ValueData->MaximumLength - 1)) {
  714. ValueData->Buffer[ValueData->Length / sizeof(WCHAR)] =
  715. UNICODE_NULL;
  716. }
  717. } else {
  718. status = STATUS_INVALID_PARAMETER_MIX;
  719. }
  720. }
  721. return status;
  722. }
  723. NTSTATUS
  724. InitRegDWORDParameter(
  725. HANDLE RegKey,
  726. PWCHAR ValueName,
  727. ULONG * Value,
  728. ULONG DefaultValue
  729. )
  730. /*++
  731. Routine Description:
  732. Reads a REG_DWORD parameter from the Registry into a variable. If the
  733. read fails, the variable is initialized to a default.
  734. Arguments:
  735. RegKey - Open handle to the parent key of the value to read.
  736. ValueName - The name of the value to read.
  737. Value - Destination variable into which to read the data.
  738. DefaultValue - Default to assign if the read fails.
  739. Return Value:
  740. STATUS_SUCCESS or an appropriate failure code.
  741. --*/
  742. {
  743. NTSTATUS status;
  744. PAGED_CODE();
  745. status = GetRegDWORDValue(
  746. RegKey,
  747. ValueName,
  748. Value
  749. );
  750. if (!NT_SUCCESS(status)) {
  751. //
  752. // These registry parameters override the defaults, so their
  753. // absence is not an error.
  754. //
  755. *Value = DefaultValue;
  756. }
  757. return (status);
  758. }
  759. PWCHAR
  760. EnumRegMultiSz(
  761. IN PWCHAR MszString,
  762. IN ULONG MszStringLength,
  763. IN ULONG StringIndex
  764. )
  765. /*++
  766. Routine Description:
  767. Parses a REG_MULTI_SZ string and returns the specified substring.
  768. Arguments:
  769. MszString - A pointer to the REG_MULTI_SZ string.
  770. MszStringLength - The length of the REG_MULTI_SZ string, including the
  771. terminating null character.
  772. StringIndex - Index number of the substring to return. Specifiying
  773. index 0 retrieves the first substring.
  774. Return Value:
  775. A pointer to the specified substring.
  776. Notes:
  777. This code is called at raised IRQL. It is not pageable.
  778. --*/
  779. {
  780. PWCHAR string = MszString;
  781. if (MszStringLength < (2 * sizeof(WCHAR))) {
  782. return (NULL);
  783. }
  784. //
  785. // Find the start of the desired string.
  786. //
  787. while (StringIndex) {
  788. while (MszStringLength >= sizeof(WCHAR)) {
  789. MszStringLength -= sizeof(WCHAR);
  790. if (*string++ == UNICODE_NULL) {
  791. break;
  792. }
  793. }
  794. //
  795. // Check for index out of range.
  796. //
  797. if (MszStringLength < (2 * sizeof(UNICODE_NULL))) {
  798. return (NULL);
  799. }
  800. StringIndex--;
  801. }
  802. if (MszStringLength < (2 * sizeof(UNICODE_NULL))) {
  803. return (NULL);
  804. }
  805. return (string);
  806. }
  807.