Sync with trunk.
[reactos.git] / dll / win32 / advapi32 / reg / reg.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 * 19990309 EA Stubs
11 * 20050502 Fireball imported some stuff from WINE
12 */
13
14 /* INCLUDES *****************************************************************/
15
16 #include <advapi32.h>
17
18 #include <ndk/cmfuncs.h>
19 #include <pseh/pseh2.h>
20
21 WINE_DEFAULT_DEBUG_CHANNEL(reg);
22
23 /* DEFINES ******************************************************************/
24
25 #define MAX_DEFAULT_HANDLES 6
26 #define REG_MAX_NAME_SIZE 256
27 #define REG_MAX_DATA_SIZE 2048
28
29 /* GLOBALS ******************************************************************/
30
31 static RTL_CRITICAL_SECTION HandleTableCS;
32 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
33 static HANDLE ProcessHeap;
34 static BOOLEAN DefaultHandlesDisabled = FALSE;
35 static BOOLEAN DefaultHandleHKUDisabled = FALSE;
36 static BOOLEAN DllInitialized = FALSE; /* HACK */
37
38 /* PROTOTYPES ***************************************************************/
39
40 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
41 static VOID CloseDefaultKeys(VOID);
42 #define ClosePredefKey(Handle) \
43 if ((ULONG_PTR)Handle & 0x1) { \
44 NtClose(Handle); \
45 }
46 #define IsPredefKey(HKey) \
47 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
48 #define GetPredefKeyIndex(HKey) \
49 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
50
51 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
52 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
53 static NTSTATUS OpenUsersKey (PHANDLE KeyHandle);
54 static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
55
56
57 /* FUNCTIONS ****************************************************************/
58 /* check if value type needs string conversion (Ansi<->Unicode) */
59 __inline static int is_string( DWORD type )
60 {
61 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
62 }
63
64 /************************************************************************
65 * RegInitDefaultHandles
66 */
67 BOOL
68 RegInitialize(VOID)
69 {
70 TRACE("RegInitialize()\n");
71
72 /* Lazy init hack */
73 if (!DllInitialized)
74 {
75 ProcessHeap = RtlGetProcessHeap();
76 RtlZeroMemory(DefaultHandleTable,
77 MAX_DEFAULT_HANDLES * sizeof(HANDLE));
78 RtlInitializeCriticalSection(&HandleTableCS);
79
80 DllInitialized = TRUE;
81 }
82
83 return TRUE;
84 }
85
86
87 /************************************************************************
88 * RegInit
89 */
90 BOOL
91 RegCleanup(VOID)
92 {
93 TRACE("RegCleanup()\n");
94
95 CloseDefaultKeys();
96 RtlDeleteCriticalSection(&HandleTableCS);
97
98 return TRUE;
99 }
100
101
102 static NTSTATUS
103 OpenPredefinedKey(IN ULONG Index,
104 OUT HANDLE Handle)
105 {
106 NTSTATUS Status;
107
108 switch (Index)
109 {
110 case 0: /* HKEY_CLASSES_ROOT */
111 Status = OpenClassesRootKey (Handle);
112 break;
113
114 case 1: /* HKEY_CURRENT_USER */
115 Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
116 Handle);
117 break;
118
119 case 2: /* HKEY_LOCAL_MACHINE */
120 Status = OpenLocalMachineKey (Handle);
121 break;
122
123 case 3: /* HKEY_USERS */
124 Status = OpenUsersKey (Handle);
125 break;
126 #if 0
127 case 4: /* HKEY_PERFORMANCE_DATA */
128 Status = OpenPerformanceDataKey (Handle);
129 break;
130 #endif
131
132 case 5: /* HKEY_CURRENT_CONFIG */
133 Status = OpenCurrentConfigKey (Handle);
134 break;
135
136 case 6: /* HKEY_DYN_DATA */
137 Status = STATUS_NOT_IMPLEMENTED;
138 break;
139
140 default:
141 WARN("MapDefaultHandle() no handle creator\n");
142 Status = STATUS_INVALID_PARAMETER;
143 break;
144 }
145
146 return Status;
147 }
148
149
150 static NTSTATUS
151 MapDefaultKey(OUT PHANDLE RealKey,
152 IN HKEY Key)
153 {
154 PHANDLE Handle;
155 ULONG Index;
156 BOOLEAN DoOpen, DefDisabled;
157 NTSTATUS Status = STATUS_SUCCESS;
158
159 TRACE("MapDefaultKey (Key %x)\n", Key);
160
161 if (!IsPredefKey(Key))
162 {
163 *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
164 return STATUS_SUCCESS;
165 }
166
167 /* Handle special cases here */
168 Index = GetPredefKeyIndex(Key);
169 if (Index >= MAX_DEFAULT_HANDLES)
170 {
171 return STATUS_INVALID_PARAMETER;
172 }
173 RegInitialize(); /* HACK until delay-loading is implemented */
174 RtlEnterCriticalSection (&HandleTableCS);
175
176 if (Key == HKEY_CURRENT_USER)
177 DefDisabled = DefaultHandleHKUDisabled;
178 else
179 DefDisabled = DefaultHandlesDisabled;
180
181 if (!DefDisabled)
182 {
183 Handle = &DefaultHandleTable[Index];
184 DoOpen = (*Handle == NULL);
185 }
186 else
187 {
188 Handle = RealKey;
189 DoOpen = TRUE;
190 }
191
192 if (DoOpen)
193 {
194 /* create/open the default handle */
195 Status = OpenPredefinedKey(Index,
196 Handle);
197 }
198
199 if (NT_SUCCESS(Status))
200 {
201 if (!DefDisabled)
202 *RealKey = *Handle;
203 else
204 *(PULONG_PTR)Handle |= 0x1;
205 }
206
207 RtlLeaveCriticalSection (&HandleTableCS);
208
209 return Status;
210 }
211
212
213 static VOID
214 CloseDefaultKeys(VOID)
215 {
216 ULONG i;
217 RegInitialize(); /* HACK until delay-loading is implemented */
218 RtlEnterCriticalSection(&HandleTableCS);
219
220 for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
221 {
222 if (DefaultHandleTable[i] != NULL)
223 {
224 NtClose(DefaultHandleTable[i]);
225 DefaultHandleTable[i] = NULL;
226 }
227 }
228
229 RtlLeaveCriticalSection(&HandleTableCS);
230 }
231
232
233 static NTSTATUS
234 OpenClassesRootKey(PHANDLE KeyHandle)
235 {
236 OBJECT_ATTRIBUTES Attributes;
237 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
238
239 TRACE("OpenClassesRootKey()\n");
240
241 InitializeObjectAttributes(&Attributes,
242 &KeyName,
243 OBJ_CASE_INSENSITIVE,
244 NULL,
245 NULL);
246 return NtOpenKey(KeyHandle,
247 MAXIMUM_ALLOWED,
248 &Attributes);
249 }
250
251
252 static NTSTATUS
253 OpenLocalMachineKey(PHANDLE KeyHandle)
254 {
255 OBJECT_ATTRIBUTES Attributes;
256 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
257 NTSTATUS Status;
258
259 TRACE("OpenLocalMachineKey()\n");
260
261 InitializeObjectAttributes(&Attributes,
262 &KeyName,
263 OBJ_CASE_INSENSITIVE,
264 NULL,
265 NULL);
266 Status = NtOpenKey(KeyHandle,
267 MAXIMUM_ALLOWED,
268 &Attributes);
269
270 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
271
272 return Status;
273 }
274
275
276 static NTSTATUS
277 OpenUsersKey(PHANDLE KeyHandle)
278 {
279 OBJECT_ATTRIBUTES Attributes;
280 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User");
281
282 TRACE("OpenUsersKey()\n");
283
284 InitializeObjectAttributes(&Attributes,
285 &KeyName,
286 OBJ_CASE_INSENSITIVE,
287 NULL,
288 NULL);
289 return NtOpenKey(KeyHandle,
290 MAXIMUM_ALLOWED,
291 &Attributes);
292 }
293
294
295 static NTSTATUS
296 OpenCurrentConfigKey (PHANDLE KeyHandle)
297 {
298 OBJECT_ATTRIBUTES Attributes;
299 UNICODE_STRING KeyName =
300 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
301
302 TRACE("OpenCurrentConfigKey()\n");
303
304 InitializeObjectAttributes(&Attributes,
305 &KeyName,
306 OBJ_CASE_INSENSITIVE,
307 NULL,
308 NULL);
309 return NtOpenKey(KeyHandle,
310 MAXIMUM_ALLOWED,
311 &Attributes);
312 }
313
314
315 /************************************************************************
316 * RegDisablePredefinedCache
317 *
318 * @implemented
319 */
320 LONG WINAPI
321 RegDisablePredefinedCache(VOID)
322 {
323 RegInitialize(); /* HACK until delay-loading is implemented */
324 RtlEnterCriticalSection(&HandleTableCS);
325 DefaultHandleHKUDisabled = TRUE;
326 RtlLeaveCriticalSection(&HandleTableCS);
327 return ERROR_SUCCESS;
328 }
329
330
331 /************************************************************************
332 * RegDisablePredefinedCacheEx
333 *
334 * @implemented
335 */
336 LONG WINAPI
337 RegDisablePredefinedCacheEx(VOID)
338 {
339 RegInitialize(); /* HACK until delay-loading is implemented */
340 RtlEnterCriticalSection(&HandleTableCS);
341 DefaultHandlesDisabled = TRUE;
342 DefaultHandleHKUDisabled = TRUE;
343 RtlLeaveCriticalSection(&HandleTableCS);
344 return ERROR_SUCCESS;
345 }
346
347
348 /************************************************************************
349 * RegOverridePredefKey
350 *
351 * @implemented
352 */
353 LONG WINAPI
354 RegOverridePredefKey(IN HKEY hKey,
355 IN HKEY hNewHKey OPTIONAL)
356 {
357 LONG ErrorCode = ERROR_SUCCESS;
358
359 if ((hKey == HKEY_CLASSES_ROOT ||
360 hKey == HKEY_CURRENT_CONFIG ||
361 hKey == HKEY_CURRENT_USER ||
362 hKey == HKEY_LOCAL_MACHINE ||
363 hKey == HKEY_PERFORMANCE_DATA ||
364 hKey == HKEY_USERS) &&
365 !IsPredefKey(hNewHKey))
366 {
367 PHANDLE Handle;
368 ULONG Index;
369
370 Index = GetPredefKeyIndex(hKey);
371 Handle = &DefaultHandleTable[Index];
372
373 if (hNewHKey == NULL)
374 {
375 /* restore the default mapping */
376 NTSTATUS Status = OpenPredefinedKey(Index,
377 &hNewHKey);
378 if (!NT_SUCCESS(Status))
379 {
380 return RtlNtStatusToDosError(Status);
381 }
382
383 ASSERT(hNewHKey != NULL);
384 }
385 RegInitialize(); /* HACK until delay-loading is implemented */
386 RtlEnterCriticalSection(&HandleTableCS);
387
388 /* close the currently mapped handle if existing */
389 if (*Handle != NULL)
390 {
391 NtClose(*Handle);
392 }
393
394 /* update the mapping */
395 *Handle = hNewHKey;
396
397 RtlLeaveCriticalSection(&HandleTableCS);
398 }
399 else
400 ErrorCode = ERROR_INVALID_HANDLE;
401
402 return ErrorCode;
403 }
404
405
406 /************************************************************************
407 * RegCloseKey
408 *
409 * @implemented
410 */
411 LONG WINAPI
412 RegCloseKey(HKEY hKey)
413 {
414 NTSTATUS Status;
415
416 /* don't close null handle or a pseudo handle */
417 if ((!hKey) || (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000))
418 {
419 return ERROR_INVALID_HANDLE;
420 }
421
422 Status = NtClose(hKey);
423 if (!NT_SUCCESS(Status))
424 {
425 return RtlNtStatusToDosError(Status);
426 }
427
428 return ERROR_SUCCESS;
429 }
430
431
432 static NTSTATUS
433 RegpCopyTree(IN HKEY hKeySrc,
434 IN HKEY hKeyDest)
435 {
436 typedef struct
437 {
438 LIST_ENTRY ListEntry;
439 HANDLE hKeySrc;
440 HANDLE hKeyDest;
441 } REGP_COPY_KEYS, *PREGP_COPY_KEYS;
442
443 LIST_ENTRY copyQueueHead;
444 PREGP_COPY_KEYS copyKeys, newCopyKeys;
445 union
446 {
447 KEY_VALUE_FULL_INFORMATION *KeyValue;
448 KEY_NODE_INFORMATION *KeyNode;
449 PVOID Buffer;
450 } Info;
451 ULONG Index, BufferSizeRequired, BufferSize = 0x200;
452 NTSTATUS Status = STATUS_SUCCESS;
453 NTSTATUS Status2 = STATUS_SUCCESS;
454
455 InitializeListHead(&copyQueueHead);
456
457 Info.Buffer = RtlAllocateHeap(ProcessHeap,
458 0,
459 BufferSize);
460 if (Info.Buffer == NULL)
461 {
462 return STATUS_INSUFFICIENT_RESOURCES;
463 }
464
465 copyKeys = RtlAllocateHeap(ProcessHeap,
466 0,
467 sizeof(REGP_COPY_KEYS));
468 if (copyKeys != NULL)
469 {
470 copyKeys->hKeySrc = hKeySrc;
471 copyKeys->hKeyDest = hKeyDest;
472 InsertHeadList(&copyQueueHead,
473 &copyKeys->ListEntry);
474
475 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
476
477 do
478 {
479 copyKeys = CONTAINING_RECORD(copyQueueHead.Flink,
480 REGP_COPY_KEYS,
481 ListEntry);
482
483 /* enumerate all values and copy them */
484 Index = 0;
485 for (;;)
486 {
487 Status2 = NtEnumerateValueKey(copyKeys->hKeySrc,
488 Index,
489 KeyValueFullInformation,
490 Info.KeyValue,
491 BufferSize,
492 &BufferSizeRequired);
493 if (NT_SUCCESS(Status2))
494 {
495 UNICODE_STRING ValueName;
496 PVOID Data;
497
498 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
499 ValueName.Length = Info.KeyValue->NameLength;
500 ValueName.MaximumLength = ValueName.Length;
501 ValueName.Buffer = Info.KeyValue->Name;
502
503 Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset);
504
505 Status2 = NtSetValueKey(copyKeys->hKeyDest,
506 &ValueName,
507 Info.KeyValue->TitleIndex,
508 Info.KeyValue->Type,
509 Data,
510 Info.KeyValue->DataLength);
511
512 /* don't break, let's try to copy as many values as possible */
513 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
514 {
515 Status = Status2;
516 }
517
518 Index++;
519 }
520 else if (Status2 == STATUS_BUFFER_OVERFLOW)
521 {
522 PVOID Buffer;
523
524 ASSERT(BufferSize < BufferSizeRequired);
525
526 Buffer = RtlReAllocateHeap(ProcessHeap,
527 0,
528 Info.Buffer,
529 BufferSizeRequired);
530 if (Buffer != NULL)
531 {
532 Info.Buffer = Buffer;
533 /* try again */
534 }
535 else
536 {
537 /* don't break, let's try to copy as many values as possible */
538 Status2 = STATUS_INSUFFICIENT_RESOURCES;
539 Index++;
540
541 if (NT_SUCCESS(Status))
542 {
543 Status = Status2;
544 }
545 }
546 }
547 else
548 {
549 /* break to avoid an infinite loop in case of denied access or
550 other errors! */
551 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
552 {
553 Status = Status2;
554 }
555
556 break;
557 }
558 }
559
560 /* enumerate all subkeys and open and enqueue them */
561 Index = 0;
562 for (;;)
563 {
564 Status2 = NtEnumerateKey(copyKeys->hKeySrc,
565 Index,
566 KeyNodeInformation,
567 Info.KeyNode,
568 BufferSize,
569 &BufferSizeRequired);
570 if (NT_SUCCESS(Status2))
571 {
572 HANDLE KeyHandle, NewKeyHandle;
573 OBJECT_ATTRIBUTES ObjectAttributes;
574 UNICODE_STRING SubKeyName, ClassName;
575
576 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
577 SubKeyName.Length = Info.KeyNode->NameLength;
578 SubKeyName.MaximumLength = SubKeyName.Length;
579 SubKeyName.Buffer = Info.KeyNode->Name;
580 ClassName.Length = Info.KeyNode->ClassLength;
581 ClassName.MaximumLength = ClassName.Length;
582 ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset);
583
584 /* open the subkey with sufficient rights */
585
586 InitializeObjectAttributes(&ObjectAttributes,
587 &SubKeyName,
588 OBJ_CASE_INSENSITIVE,
589 copyKeys->hKeySrc,
590 NULL);
591
592 Status2 = NtOpenKey(&KeyHandle,
593 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
594 &ObjectAttributes);
595 if (NT_SUCCESS(Status2))
596 {
597 /* FIXME - attempt to query the security information */
598
599 InitializeObjectAttributes(&ObjectAttributes,
600 &SubKeyName,
601 OBJ_CASE_INSENSITIVE,
602 copyKeys->hKeyDest,
603 NULL);
604
605 Status2 = NtCreateKey(&NewKeyHandle,
606 KEY_ALL_ACCESS,
607 &ObjectAttributes,
608 Info.KeyNode->TitleIndex,
609 &ClassName,
610 0,
611 NULL);
612 if (NT_SUCCESS(Status2))
613 {
614 newCopyKeys = RtlAllocateHeap(ProcessHeap,
615 0,
616 sizeof(REGP_COPY_KEYS));
617 if (newCopyKeys != NULL)
618 {
619 /* save the handles and enqueue the subkey */
620 newCopyKeys->hKeySrc = KeyHandle;
621 newCopyKeys->hKeyDest = NewKeyHandle;
622 InsertTailList(&copyQueueHead,
623 &newCopyKeys->ListEntry);
624 }
625 else
626 {
627 NtClose(KeyHandle);
628 NtClose(NewKeyHandle);
629
630 Status2 = STATUS_INSUFFICIENT_RESOURCES;
631 }
632 }
633 else
634 {
635 NtClose(KeyHandle);
636 }
637 }
638
639 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
640 {
641 Status = Status2;
642 }
643
644 Index++;
645 }
646 else if (Status2 == STATUS_BUFFER_OVERFLOW)
647 {
648 PVOID Buffer;
649
650 ASSERT(BufferSize < BufferSizeRequired);
651
652 Buffer = RtlReAllocateHeap(ProcessHeap,
653 0,
654 Info.Buffer,
655 BufferSizeRequired);
656 if (Buffer != NULL)
657 {
658 Info.Buffer = Buffer;
659 /* try again */
660 }
661 else
662 {
663 /* don't break, let's try to copy as many keys as possible */
664 Status2 = STATUS_INSUFFICIENT_RESOURCES;
665 Index++;
666
667 if (NT_SUCCESS(Status))
668 {
669 Status = Status2;
670 }
671 }
672 }
673 else
674 {
675 /* break to avoid an infinite loop in case of denied access or
676 other errors! */
677 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
678 {
679 Status = Status2;
680 }
681
682 break;
683 }
684 }
685
686 /* close the handles and remove the entry from the list */
687 if (copyKeys->hKeySrc != hKeySrc)
688 {
689 NtClose(copyKeys->hKeySrc);
690 }
691 if (copyKeys->hKeyDest != hKeyDest)
692 {
693 NtClose(copyKeys->hKeyDest);
694 }
695
696 RemoveEntryList(&copyKeys->ListEntry);
697
698 RtlFreeHeap(ProcessHeap,
699 0,
700 copyKeys);
701 } while (!IsListEmpty(&copyQueueHead));
702 }
703 else
704 Status = STATUS_INSUFFICIENT_RESOURCES;
705
706 RtlFreeHeap(ProcessHeap,
707 0,
708 Info.Buffer);
709
710 return Status;
711 }
712
713
714 /************************************************************************
715 * RegCopyTreeW
716 *
717 * @implemented
718 */
719 LONG WINAPI
720 RegCopyTreeW(IN HKEY hKeySrc,
721 IN LPCWSTR lpSubKey OPTIONAL,
722 IN HKEY hKeyDest)
723 {
724 HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
725 NTSTATUS Status;
726
727 Status = MapDefaultKey(&KeyHandle,
728 hKeySrc);
729 if (!NT_SUCCESS(Status))
730 {
731 return RtlNtStatusToDosError(Status);
732 }
733
734 Status = MapDefaultKey(&DestKeyHandle,
735 hKeyDest);
736 if (!NT_SUCCESS(Status))
737 {
738 goto Cleanup2;
739 }
740
741 if (lpSubKey != NULL)
742 {
743 OBJECT_ATTRIBUTES ObjectAttributes;
744 UNICODE_STRING SubKeyName;
745
746 RtlInitUnicodeString(&SubKeyName,
747 (LPWSTR)lpSubKey);
748
749 InitializeObjectAttributes(&ObjectAttributes,
750 &SubKeyName,
751 OBJ_CASE_INSENSITIVE,
752 KeyHandle,
753 NULL);
754
755 Status = NtOpenKey(&SubKeyHandle,
756 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
757 &ObjectAttributes);
758 if (!NT_SUCCESS(Status))
759 {
760 goto Cleanup;
761 }
762
763 CurKey = SubKeyHandle;
764 }
765 else
766 CurKey = KeyHandle;
767
768 Status = RegpCopyTree(CurKey,
769 hKeyDest);
770
771 if (SubKeyHandle != NULL)
772 {
773 NtClose(SubKeyHandle);
774 }
775
776 Cleanup:
777 ClosePredefKey(DestKeyHandle);
778 Cleanup2:
779 ClosePredefKey(KeyHandle);
780
781 if (!NT_SUCCESS(Status))
782 {
783 return RtlNtStatusToDosError(Status);
784 }
785
786 return ERROR_SUCCESS;
787 }
788
789
790 /************************************************************************
791 * RegCopyTreeA
792 *
793 * @implemented
794 */
795 LONG WINAPI
796 RegCopyTreeA(IN HKEY hKeySrc,
797 IN LPCSTR lpSubKey OPTIONAL,
798 IN HKEY hKeyDest)
799 {
800 UNICODE_STRING SubKeyName = { 0, 0, NULL };
801 LONG Ret;
802
803 if (lpSubKey != NULL &&
804 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
805 (LPSTR)lpSubKey))
806 {
807 return ERROR_NOT_ENOUGH_MEMORY;
808 }
809
810 Ret = RegCopyTreeW(hKeySrc,
811 SubKeyName.Buffer,
812 hKeyDest);
813
814 RtlFreeUnicodeString(&SubKeyName);
815
816 return Ret;
817 }
818
819
820 /************************************************************************
821 * RegConnectRegistryA
822 *
823 * @implemented
824 */
825 LONG WINAPI
826 RegConnectRegistryA(IN LPCSTR lpMachineName,
827 IN HKEY hKey,
828 OUT PHKEY phkResult)
829 {
830 UNICODE_STRING MachineName = { 0, 0, NULL };
831 LONG Ret;
832
833 if (lpMachineName != NULL &&
834 !RtlCreateUnicodeStringFromAsciiz(&MachineName,
835 (LPSTR)lpMachineName))
836 {
837 return ERROR_NOT_ENOUGH_MEMORY;
838 }
839
840 Ret = RegConnectRegistryW(MachineName.Buffer,
841 hKey,
842 phkResult);
843
844 RtlFreeUnicodeString(&MachineName);
845
846 return Ret;
847 }
848
849
850 /************************************************************************
851 * RegConnectRegistryW
852 *
853 * @unimplemented
854 */
855 LONG WINAPI
856 RegConnectRegistryW(LPCWSTR lpMachineName,
857 HKEY hKey,
858 PHKEY phkResult)
859 {
860 LONG ret;
861
862 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
863
864 if (!lpMachineName || !*lpMachineName)
865 {
866 /* Use the local machine name */
867 ret = RegOpenKeyW( hKey, NULL, phkResult );
868 }
869 else
870 {
871 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
872 DWORD len = sizeof(compName) / sizeof(WCHAR);
873
874 /* MSDN says lpMachineName must start with \\ : not so */
875 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
876 lpMachineName += 2;
877
878 if (GetComputerNameW(compName, &len))
879 {
880 if (!_wcsicmp(lpMachineName, compName))
881 ret = RegOpenKeyW(hKey, NULL, phkResult);
882 else
883 {
884 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
885 ret = ERROR_BAD_NETPATH;
886 }
887 }
888 else
889 ret = GetLastError();
890 }
891
892 return ret;
893 }
894
895
896 /************************************************************************
897 * CreateNestedKey
898 *
899 * Create key and all necessary intermediate keys
900 */
901 static NTSTATUS
902 CreateNestedKey(PHKEY KeyHandle,
903 POBJECT_ATTRIBUTES ObjectAttributes,
904 PUNICODE_STRING ClassString,
905 DWORD dwOptions,
906 REGSAM samDesired,
907 DWORD *lpdwDisposition)
908 {
909 OBJECT_ATTRIBUTES LocalObjectAttributes;
910 UNICODE_STRING LocalKeyName;
911 ULONG Disposition;
912 NTSTATUS Status;
913 ULONG FullNameLength;
914 ULONG Length;
915 PWCHAR Ptr;
916 HANDLE LocalKeyHandle;
917
918 Status = NtCreateKey((PHANDLE) KeyHandle,
919 samDesired,
920 ObjectAttributes,
921 0,
922 ClassString,
923 dwOptions,
924 (PULONG)lpdwDisposition);
925 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
926 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
927 return Status;
928
929 /* Copy object attributes */
930 RtlCopyMemory(&LocalObjectAttributes,
931 ObjectAttributes,
932 sizeof(OBJECT_ATTRIBUTES));
933 RtlCreateUnicodeString(&LocalKeyName,
934 ObjectAttributes->ObjectName->Buffer);
935 LocalObjectAttributes.ObjectName = &LocalKeyName;
936 FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
937
938 LocalKeyHandle = NULL;
939
940 /* Remove the last part of the key name and try to create the key again. */
941 while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
942 {
943 Ptr = wcsrchr(LocalKeyName.Buffer, '\\');
944 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
945 {
946 Status = STATUS_UNSUCCESSFUL;
947 break;
948 }
949
950 *Ptr = (WCHAR)0;
951 LocalKeyName.Length = wcslen(LocalKeyName.Buffer) * sizeof(WCHAR);
952
953 Status = NtCreateKey(&LocalKeyHandle,
954 KEY_CREATE_SUB_KEY,
955 &LocalObjectAttributes,
956 0,
957 NULL,
958 0,
959 &Disposition);
960 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
961 }
962
963 if (!NT_SUCCESS(Status))
964 {
965 RtlFreeUnicodeString(&LocalKeyName);
966 return Status;
967 }
968
969 /* Add removed parts of the key name and create them too. */
970 Length = wcslen(LocalKeyName.Buffer);
971 while (TRUE)
972 {
973 if (LocalKeyHandle)
974 NtClose (LocalKeyHandle);
975
976 LocalKeyName.Buffer[Length] = L'\\';
977 Length = wcslen (LocalKeyName.Buffer);
978 LocalKeyName.Length = Length * sizeof(WCHAR);
979
980 if (Length == FullNameLength)
981 {
982 Status = NtCreateKey((PHANDLE) KeyHandle,
983 samDesired,
984 ObjectAttributes,
985 0,
986 ClassString,
987 dwOptions,
988 (PULONG)lpdwDisposition);
989 break;
990 }
991
992 Status = NtCreateKey(&LocalKeyHandle,
993 KEY_CREATE_SUB_KEY,
994 &LocalObjectAttributes,
995 0,
996 NULL,
997 0,
998 &Disposition);
999 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
1000 if (!NT_SUCCESS(Status))
1001 break;
1002 }
1003
1004 RtlFreeUnicodeString(&LocalKeyName);
1005
1006 return Status;
1007 }
1008
1009
1010 /************************************************************************
1011 * RegCreateKeyExA
1012 *
1013 * @implemented
1014 */
1015 LONG WINAPI
1016 RegCreateKeyExA(HKEY hKey,
1017 LPCSTR lpSubKey,
1018 DWORD Reserved,
1019 LPSTR lpClass,
1020 DWORD dwOptions,
1021 REGSAM samDesired,
1022 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1023 PHKEY phkResult,
1024 LPDWORD lpdwDisposition)
1025 {
1026 UNICODE_STRING SubKeyString;
1027 UNICODE_STRING ClassString;
1028 OBJECT_ATTRIBUTES ObjectAttributes;
1029 HANDLE ParentKey;
1030 ULONG Attributes = OBJ_CASE_INSENSITIVE;
1031 NTSTATUS Status;
1032
1033 TRACE("RegCreateKeyExA() called\n");
1034
1035 if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
1036 return ERROR_INVALID_USER_BUFFER;
1037
1038 /* get the real parent key */
1039 Status = MapDefaultKey(&ParentKey,
1040 hKey);
1041 if (!NT_SUCCESS(Status))
1042 {
1043 return RtlNtStatusToDosError(Status);
1044 }
1045
1046 TRACE("ParentKey %p\n", ParentKey);
1047
1048 if (lpClass != NULL)
1049 {
1050 RtlCreateUnicodeStringFromAsciiz(&ClassString,
1051 lpClass);
1052 }
1053
1054 if (dwOptions & REG_OPTION_OPEN_LINK)
1055 Attributes |= OBJ_OPENLINK;
1056
1057 RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
1058 (LPSTR)lpSubKey);
1059 InitializeObjectAttributes(&ObjectAttributes,
1060 &SubKeyString,
1061 Attributes,
1062 (HANDLE)ParentKey,
1063 lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
1064 Status = CreateNestedKey(phkResult,
1065 &ObjectAttributes,
1066 (lpClass == NULL)? NULL : &ClassString,
1067 dwOptions,
1068 samDesired,
1069 lpdwDisposition);
1070 RtlFreeUnicodeString(&SubKeyString);
1071 if (lpClass != NULL)
1072 {
1073 RtlFreeUnicodeString(&ClassString);
1074 }
1075
1076 ClosePredefKey(ParentKey);
1077
1078 TRACE("Status %x\n", Status);
1079 if (!NT_SUCCESS(Status))
1080 {
1081 return RtlNtStatusToDosError(Status);
1082 }
1083
1084 return ERROR_SUCCESS;
1085 }
1086
1087
1088 /************************************************************************
1089 * RegCreateKeyExW
1090 *
1091 * @implemented
1092 */
1093 LONG WINAPI
1094 RegCreateKeyExW(HKEY hKey,
1095 LPCWSTR lpSubKey,
1096 DWORD Reserved,
1097 LPWSTR lpClass,
1098 DWORD dwOptions,
1099 REGSAM samDesired,
1100 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1101 PHKEY phkResult,
1102 LPDWORD lpdwDisposition)
1103 {
1104 UNICODE_STRING SubKeyString;
1105 UNICODE_STRING ClassString;
1106 OBJECT_ATTRIBUTES ObjectAttributes;
1107 HANDLE ParentKey;
1108 ULONG Attributes = OBJ_CASE_INSENSITIVE;
1109 NTSTATUS Status;
1110
1111 TRACE("RegCreateKeyExW() called\n");
1112
1113 if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
1114 return ERROR_INVALID_USER_BUFFER;
1115
1116 /* get the real parent key */
1117 Status = MapDefaultKey(&ParentKey,
1118 hKey);
1119 if (!NT_SUCCESS(Status))
1120 {
1121 return RtlNtStatusToDosError(Status);
1122 }
1123
1124 TRACE("ParentKey %p\n", ParentKey);
1125
1126 if (dwOptions & REG_OPTION_OPEN_LINK)
1127 Attributes |= OBJ_OPENLINK;
1128
1129 RtlInitUnicodeString(&ClassString,
1130 lpClass);
1131 RtlInitUnicodeString(&SubKeyString,
1132 lpSubKey);
1133 InitializeObjectAttributes(&ObjectAttributes,
1134 &SubKeyString,
1135 Attributes,
1136 (HANDLE)ParentKey,
1137 lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
1138 Status = CreateNestedKey(phkResult,
1139 &ObjectAttributes,
1140 (lpClass == NULL)? NULL : &ClassString,
1141 dwOptions,
1142 samDesired,
1143 lpdwDisposition);
1144
1145 ClosePredefKey(ParentKey);
1146
1147 TRACE("Status %x\n", Status);
1148 if (!NT_SUCCESS(Status))
1149 {
1150 return RtlNtStatusToDosError(Status);
1151 }
1152
1153 return ERROR_SUCCESS;
1154 }
1155
1156
1157 /************************************************************************
1158 * RegCreateKeyA
1159 *
1160 * @implemented
1161 */
1162 LONG WINAPI
1163 RegCreateKeyA(HKEY hKey,
1164 LPCSTR lpSubKey,
1165 PHKEY phkResult)
1166 {
1167 return RegCreateKeyExA(hKey,
1168 lpSubKey,
1169 0,
1170 NULL,
1171 0,
1172 MAXIMUM_ALLOWED,
1173 NULL,
1174 phkResult,
1175 NULL);
1176 }
1177
1178
1179 /************************************************************************
1180 * RegCreateKeyW
1181 *
1182 * @implemented
1183 */
1184 LONG WINAPI
1185 RegCreateKeyW(HKEY hKey,
1186 LPCWSTR lpSubKey,
1187 PHKEY phkResult)
1188 {
1189 return RegCreateKeyExW(hKey,
1190 lpSubKey,
1191 0,
1192 NULL,
1193 0,
1194 MAXIMUM_ALLOWED,
1195 NULL,
1196 phkResult,
1197 NULL);
1198 }
1199
1200
1201 /************************************************************************
1202 * RegDeleteKeyA
1203 *
1204 * @implemented
1205 */
1206 LONG WINAPI
1207 RegDeleteKeyA(HKEY hKey,
1208 LPCSTR lpSubKey)
1209 {
1210 OBJECT_ATTRIBUTES ObjectAttributes;
1211 UNICODE_STRING SubKeyName;
1212 HANDLE ParentKey;
1213 HANDLE TargetKey;
1214 NTSTATUS Status;
1215
1216 /* Make sure we got a subkey */
1217 if (!lpSubKey)
1218 {
1219 /* Fail */
1220 return ERROR_INVALID_PARAMETER;
1221 }
1222
1223 Status = MapDefaultKey(&ParentKey,
1224 hKey);
1225 if (!NT_SUCCESS(Status))
1226 {
1227 return RtlNtStatusToDosError(Status);
1228 }
1229
1230 RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1231 (LPSTR)lpSubKey);
1232 InitializeObjectAttributes(&ObjectAttributes,
1233 &SubKeyName,
1234 OBJ_CASE_INSENSITIVE,
1235 ParentKey,
1236 NULL);
1237
1238 Status = NtOpenKey(&TargetKey,
1239 DELETE,
1240 &ObjectAttributes);
1241 RtlFreeUnicodeString(&SubKeyName);
1242 if (!NT_SUCCESS(Status))
1243 {
1244 goto Cleanup;
1245 }
1246
1247 Status = NtDeleteKey(TargetKey);
1248 NtClose (TargetKey);
1249
1250 Cleanup:
1251 ClosePredefKey(ParentKey);
1252
1253 if (!NT_SUCCESS(Status))
1254 {
1255 return RtlNtStatusToDosError(Status);
1256 }
1257
1258 return ERROR_SUCCESS;
1259 }
1260
1261
1262 /************************************************************************
1263 * RegDeleteKeyW
1264 *
1265 * @implemented
1266 */
1267 LONG WINAPI
1268 RegDeleteKeyW(HKEY hKey,
1269 LPCWSTR lpSubKey)
1270 {
1271 OBJECT_ATTRIBUTES ObjectAttributes;
1272 UNICODE_STRING SubKeyName;
1273 HANDLE ParentKey;
1274 HANDLE TargetKey;
1275 NTSTATUS Status;
1276
1277 /* Make sure we got a subkey */
1278 if (!lpSubKey)
1279 {
1280 /* Fail */
1281 return ERROR_INVALID_PARAMETER;
1282 }
1283
1284 Status = MapDefaultKey(&ParentKey,
1285 hKey);
1286 if (!NT_SUCCESS(Status))
1287 {
1288 return RtlNtStatusToDosError(Status);
1289 }
1290
1291 RtlInitUnicodeString(&SubKeyName,
1292 (LPWSTR)lpSubKey);
1293 InitializeObjectAttributes(&ObjectAttributes,
1294 &SubKeyName,
1295 OBJ_CASE_INSENSITIVE,
1296 ParentKey,
1297 NULL);
1298 Status = NtOpenKey(&TargetKey,
1299 DELETE,
1300 &ObjectAttributes);
1301 if (!NT_SUCCESS(Status))
1302 {
1303 goto Cleanup;
1304 }
1305
1306 Status = NtDeleteKey(TargetKey);
1307 NtClose(TargetKey);
1308
1309 Cleanup:
1310 ClosePredefKey(ParentKey);
1311
1312 if (!NT_SUCCESS(Status))
1313 {
1314 return RtlNtStatusToDosError(Status);
1315 }
1316
1317 return ERROR_SUCCESS;
1318 }
1319
1320
1321 /************************************************************************
1322 * RegDeleteKeyExA
1323 *
1324 * @implemented
1325 */
1326 LONG
1327 WINAPI
1328 RegDeleteKeyExA(HKEY hKey,
1329 LPCSTR lpSubKey,
1330 REGSAM samDesired,
1331 DWORD Reserved)
1332 {
1333 OBJECT_ATTRIBUTES ObjectAttributes;
1334 UNICODE_STRING SubKeyName;
1335 HANDLE ParentKey;
1336 HANDLE TargetKey;
1337 NTSTATUS Status;
1338
1339 /* Make sure we got a subkey */
1340 if (!lpSubKey)
1341 {
1342 /* Fail */
1343 return ERROR_INVALID_PARAMETER;
1344 }
1345
1346 Status = MapDefaultKey(&ParentKey,
1347 hKey);
1348 if (!NT_SUCCESS(Status))
1349 {
1350 return RtlNtStatusToDosError(Status);
1351 }
1352
1353 if (samDesired & KEY_WOW64_32KEY)
1354 ERR("Wow64 not yet supported!\n");
1355
1356 if (samDesired & KEY_WOW64_64KEY)
1357 ERR("Wow64 not yet supported!\n");
1358
1359 RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1360 (LPSTR)lpSubKey);
1361 InitializeObjectAttributes(&ObjectAttributes,
1362 &SubKeyName,
1363 OBJ_CASE_INSENSITIVE,
1364 ParentKey,
1365 NULL);
1366
1367 Status = NtOpenKey(&TargetKey,
1368 DELETE,
1369 &ObjectAttributes);
1370 RtlFreeUnicodeString(&SubKeyName);
1371 if (!NT_SUCCESS(Status))
1372 {
1373 goto Cleanup;
1374 }
1375
1376 Status = NtDeleteKey(TargetKey);
1377 NtClose (TargetKey);
1378
1379 Cleanup:
1380 ClosePredefKey(ParentKey);
1381
1382 if (!NT_SUCCESS(Status))
1383 {
1384 return RtlNtStatusToDosError(Status);
1385 }
1386
1387 return ERROR_SUCCESS;
1388 }
1389
1390
1391 /************************************************************************
1392 * RegDeleteKeyExW
1393 *
1394 * @implemented
1395 */
1396 LONG
1397 WINAPI
1398 RegDeleteKeyExW(HKEY hKey,
1399 LPCWSTR lpSubKey,
1400 REGSAM samDesired,
1401 DWORD Reserved)
1402 {
1403 OBJECT_ATTRIBUTES ObjectAttributes;
1404 UNICODE_STRING SubKeyName;
1405 HANDLE ParentKey;
1406 HANDLE TargetKey;
1407 NTSTATUS Status;
1408
1409 /* Make sure we got a subkey */
1410 if (!lpSubKey)
1411 {
1412 /* Fail */
1413 return ERROR_INVALID_PARAMETER;
1414 }
1415
1416 Status = MapDefaultKey(&ParentKey,
1417 hKey);
1418 if (!NT_SUCCESS(Status))
1419 {
1420 return RtlNtStatusToDosError(Status);
1421 }
1422
1423 if (samDesired & KEY_WOW64_32KEY)
1424 ERR("Wow64 not yet supported!\n");
1425
1426 if (samDesired & KEY_WOW64_64KEY)
1427 ERR("Wow64 not yet supported!\n");
1428
1429
1430 RtlInitUnicodeString(&SubKeyName,
1431 (LPWSTR)lpSubKey);
1432 InitializeObjectAttributes(&ObjectAttributes,
1433 &SubKeyName,
1434 OBJ_CASE_INSENSITIVE,
1435 ParentKey,
1436 NULL);
1437 Status = NtOpenKey(&TargetKey,
1438 DELETE,
1439 &ObjectAttributes);
1440 if (!NT_SUCCESS(Status))
1441 {
1442 goto Cleanup;
1443 }
1444
1445 Status = NtDeleteKey(TargetKey);
1446 NtClose(TargetKey);
1447
1448 Cleanup:
1449 ClosePredefKey(ParentKey);
1450
1451 if (!NT_SUCCESS(Status))
1452 {
1453 return RtlNtStatusToDosError(Status);
1454 }
1455
1456 return ERROR_SUCCESS;
1457 }
1458
1459
1460 /************************************************************************
1461 * RegDeleteKeyValueW
1462 *
1463 * @implemented
1464 */
1465 LONG WINAPI
1466 RegDeleteKeyValueW(IN HKEY hKey,
1467 IN LPCWSTR lpSubKey OPTIONAL,
1468 IN LPCWSTR lpValueName OPTIONAL)
1469 {
1470 UNICODE_STRING ValueName;
1471 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1472 NTSTATUS Status;
1473
1474 Status = MapDefaultKey(&KeyHandle,
1475 hKey);
1476 if (!NT_SUCCESS(Status))
1477 {
1478 return RtlNtStatusToDosError(Status);
1479 }
1480
1481 if (lpSubKey != NULL)
1482 {
1483 OBJECT_ATTRIBUTES ObjectAttributes;
1484 UNICODE_STRING SubKeyName;
1485
1486 RtlInitUnicodeString(&SubKeyName,
1487 (LPWSTR)lpSubKey);
1488
1489 InitializeObjectAttributes(&ObjectAttributes,
1490 &SubKeyName,
1491 OBJ_CASE_INSENSITIVE,
1492 KeyHandle,
1493 NULL);
1494
1495 Status = NtOpenKey(&SubKeyHandle,
1496 KEY_SET_VALUE,
1497 &ObjectAttributes);
1498 if (!NT_SUCCESS(Status))
1499 {
1500 goto Cleanup;
1501 }
1502
1503 CurKey = SubKeyHandle;
1504 }
1505 else
1506 CurKey = KeyHandle;
1507
1508 RtlInitUnicodeString(&ValueName,
1509 (LPWSTR)lpValueName);
1510
1511 Status = NtDeleteValueKey(CurKey,
1512 &ValueName);
1513
1514 if (SubKeyHandle != NULL)
1515 {
1516 NtClose(SubKeyHandle);
1517 }
1518
1519 Cleanup:
1520 ClosePredefKey(KeyHandle);
1521
1522 if (!NT_SUCCESS(Status))
1523 {
1524 return RtlNtStatusToDosError(Status);
1525 }
1526
1527 return ERROR_SUCCESS;
1528 }
1529
1530
1531 /************************************************************************
1532 * RegDeleteKeyValueA
1533 *
1534 * @implemented
1535 */
1536 LONG WINAPI
1537 RegDeleteKeyValueA(IN HKEY hKey,
1538 IN LPCSTR lpSubKey OPTIONAL,
1539 IN LPCSTR lpValueName OPTIONAL)
1540 {
1541 UNICODE_STRING SubKey = { 0, 0, NULL }, ValueName = { 0, 0, NULL };
1542 LONG Ret;
1543
1544 if (lpSubKey != NULL &&
1545 !RtlCreateUnicodeStringFromAsciiz(&SubKey,
1546 (LPSTR)lpSubKey))
1547 {
1548 return ERROR_NOT_ENOUGH_MEMORY;
1549 }
1550
1551 if (lpValueName != NULL &&
1552 !RtlCreateUnicodeStringFromAsciiz(&ValueName,
1553 (LPSTR)lpValueName))
1554 {
1555 RtlFreeUnicodeString(&SubKey);
1556 return ERROR_NOT_ENOUGH_MEMORY;
1557 }
1558
1559 Ret = RegDeleteKeyValueW(hKey,
1560 SubKey.Buffer,
1561 SubKey.Buffer);
1562
1563 RtlFreeUnicodeString(&SubKey);
1564 RtlFreeUnicodeString(&ValueName);
1565
1566 return Ret;
1567 }
1568
1569 #if 0
1570 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1571 static NTSTATUS
1572 RegpDeleteTree(IN HKEY hKey)
1573 {
1574 typedef struct
1575 {
1576 LIST_ENTRY ListEntry;
1577 HANDLE KeyHandle;
1578 } REGP_DEL_KEYS, *PREG_DEL_KEYS;
1579
1580 LIST_ENTRY delQueueHead;
1581 PREG_DEL_KEYS delKeys, newDelKeys;
1582 HANDLE ProcessHeap;
1583 ULONG BufferSize;
1584 PKEY_BASIC_INFORMATION BasicInfo;
1585 PREG_DEL_KEYS KeyDelRoot;
1586 NTSTATUS Status = STATUS_SUCCESS;
1587 NTSTATUS Status2 = STATUS_SUCCESS;
1588
1589 InitializeListHead(&delQueueHead);
1590
1591 ProcessHeap = RtlGetProcessHeap();
1592
1593 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1594 structure for the root key, we only do that for subkeys as we need to
1595 allocate REGP_DEL_KEYS structures anyway! */
1596 KeyDelRoot = RtlAllocateHeap(ProcessHeap,
1597 0,
1598 sizeof(REGP_DEL_KEYS));
1599 if (KeyDelRoot != NULL)
1600 {
1601 KeyDelRoot->KeyHandle = hKey;
1602 InsertTailList(&delQueueHead,
1603 &KeyDelRoot->ListEntry);
1604
1605 do
1606 {
1607 delKeys = CONTAINING_RECORD(delQueueHead.Flink,
1608 REGP_DEL_KEYS,
1609 ListEntry);
1610
1611 BufferSize = 0;
1612 BasicInfo = NULL;
1613 newDelKeys = NULL;
1614
1615 ReadFirstSubKey:
1616 /* check if this key contains subkeys and delete them first by queuing
1617 them at the head of the list */
1618 Status2 = NtEnumerateKey(delKeys->KeyHandle,
1619 0,
1620 KeyBasicInformation,
1621 BasicInfo,
1622 BufferSize,
1623 &BufferSize);
1624
1625 if (NT_SUCCESS(Status2))
1626 {
1627 OBJECT_ATTRIBUTES ObjectAttributes;
1628 UNICODE_STRING SubKeyName;
1629
1630 ASSERT(newDelKeys != NULL);
1631 ASSERT(BasicInfo != NULL);
1632
1633 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1634 SubKeyName.Length = BasicInfo->NameLength;
1635 SubKeyName.MaximumLength = BasicInfo->NameLength;
1636 SubKeyName.Buffer = BasicInfo->Name;
1637
1638 InitializeObjectAttributes(&ObjectAttributes,
1639 &SubKeyName,
1640 OBJ_CASE_INSENSITIVE,
1641 delKeys->KeyHandle,
1642 NULL);
1643
1644 /* open the subkey */
1645 Status2 = NtOpenKey(&newDelKeys->KeyHandle,
1646 DELETE | KEY_ENUMERATE_SUB_KEYS,
1647 &ObjectAttributes);
1648 if (!NT_SUCCESS(Status2))
1649 {
1650 goto SubKeyFailure;
1651 }
1652
1653 /* enqueue this key to the head of the deletion queue */
1654 InsertHeadList(&delQueueHead,
1655 &newDelKeys->ListEntry);
1656
1657 /* try again from the head of the list */
1658 continue;
1659 }
1660 else
1661 {
1662 if (Status2 == STATUS_BUFFER_TOO_SMALL)
1663 {
1664 newDelKeys = RtlAllocateHeap(ProcessHeap,
1665 0,
1666 BufferSize + sizeof(REGP_DEL_KEYS));
1667 if (newDelKeys != NULL)
1668 {
1669 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1670
1671 /* try again */
1672 goto ReadFirstSubKey;
1673 }
1674 else
1675 {
1676 /* don't break, let's try to delete as many keys as possible */
1677 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1678 goto SubKeyFailureNoFree;
1679 }
1680 }
1681 else if (Status2 == STATUS_BUFFER_OVERFLOW)
1682 {
1683 PREG_DEL_KEYS newDelKeys2;
1684
1685 ASSERT(newDelKeys != NULL);
1686
1687 /* we need more memory to query the key name */
1688 newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
1689 0,
1690 newDelKeys,
1691 BufferSize + sizeof(REGP_DEL_KEYS));
1692 if (newDelKeys2 != NULL)
1693 {
1694 newDelKeys = newDelKeys2;
1695 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1696
1697 /* try again */
1698 goto ReadFirstSubKey;
1699 }
1700 else
1701 {
1702 /* don't break, let's try to delete as many keys as possible */
1703 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1704 }
1705 }
1706 else if (Status2 == STATUS_NO_MORE_ENTRIES)
1707 {
1708 /* in some race conditions where another thread would delete
1709 the same tree at the same time, newDelKeys could actually
1710 be != NULL! */
1711 if (newDelKeys != NULL)
1712 {
1713 RtlFreeHeap(ProcessHeap,
1714 0,
1715 newDelKeys);
1716 }
1717 break;
1718 }
1719
1720 SubKeyFailure:
1721 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1722 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1723 if (newDelKeys != NULL)
1724 {
1725 RtlFreeHeap(ProcessHeap,
1726 0,
1727 newDelKeys);
1728 }
1729
1730 SubKeyFailureNoFree:
1731 /* don't break, let's try to delete as many keys as possible */
1732 if (NT_SUCCESS(Status))
1733 {
1734 Status = Status2;
1735 }
1736 }
1737
1738 Status2 = NtDeleteKey(delKeys->KeyHandle);
1739
1740 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1741
1742 if (!NT_SUCCESS(Status2))
1743 {
1744 /* close the key handle so we don't leak handles for keys we were
1745 unable to delete. But only do this for handles not supplied
1746 by the caller! */
1747
1748 if (delKeys->KeyHandle != hKey)
1749 {
1750 NtClose(delKeys->KeyHandle);
1751 }
1752
1753 if (NT_SUCCESS(Status))
1754 {
1755 /* don't break, let's try to delete as many keys as possible */
1756 Status = Status2;
1757 }
1758 }
1759
1760 /* remove the entry from the list */
1761 RemoveEntryList(&delKeys->ListEntry);
1762
1763 RtlFreeHeap(ProcessHeap,
1764 0,
1765 delKeys);
1766 } while (!IsListEmpty(&delQueueHead));
1767 }
1768 else
1769 Status = STATUS_INSUFFICIENT_RESOURCES;
1770
1771 return Status;
1772 }
1773
1774
1775 /************************************************************************
1776 * RegDeleteTreeW
1777 *
1778 * @implemented
1779 */
1780 LONG WINAPI
1781 RegDeleteTreeW(IN HKEY hKey,
1782 IN LPCWSTR lpSubKey OPTIONAL)
1783 {
1784 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1785 NTSTATUS Status;
1786
1787 Status = MapDefaultKey(&KeyHandle,
1788 hKey);
1789 if (!NT_SUCCESS(Status))
1790 {
1791 return RtlNtStatusToDosError(Status);
1792 }
1793
1794 if (lpSubKey != NULL)
1795 {
1796 OBJECT_ATTRIBUTES ObjectAttributes;
1797 UNICODE_STRING SubKeyName;
1798
1799 RtlInitUnicodeString(&SubKeyName,
1800 (LPWSTR)lpSubKey);
1801
1802 InitializeObjectAttributes(&ObjectAttributes,
1803 &SubKeyName,
1804 OBJ_CASE_INSENSITIVE,
1805 KeyHandle,
1806 NULL);
1807
1808 Status = NtOpenKey(&SubKeyHandle,
1809 DELETE | KEY_ENUMERATE_SUB_KEYS,
1810 &ObjectAttributes);
1811 if (!NT_SUCCESS(Status))
1812 {
1813 goto Cleanup;
1814 }
1815
1816 CurKey = SubKeyHandle;
1817 }
1818 else
1819 CurKey = KeyHandle;
1820
1821 Status = RegpDeleteTree(CurKey);
1822
1823 if (NT_SUCCESS(Status))
1824 {
1825 /* make sure we only close hKey (KeyHandle) when the caller specified a
1826 subkey, because the handle would be invalid already! */
1827 if (CurKey != KeyHandle)
1828 {
1829 ClosePredefKey(KeyHandle);
1830 }
1831
1832 return ERROR_SUCCESS;
1833 }
1834 else
1835 {
1836 /* make sure we close all handles we created! */
1837 if (SubKeyHandle != NULL)
1838 {
1839 NtClose(SubKeyHandle);
1840 }
1841
1842 Cleanup:
1843 ClosePredefKey(KeyHandle);
1844
1845 return RtlNtStatusToDosError(Status);
1846 }
1847 }
1848 #endif
1849
1850
1851 /************************************************************************
1852 * RegDeleteTreeW
1853 *
1854 * @implemented
1855 */
1856 LSTATUS
1857 WINAPI
1858 RegDeleteTreeW(HKEY hKey,
1859 LPCWSTR lpszSubKey)
1860 {
1861 LONG ret;
1862 DWORD dwMaxSubkeyLen, dwMaxValueLen;
1863 DWORD dwMaxLen, dwSize;
1864 NTSTATUS Status;
1865 HANDLE KeyHandle;
1866 HKEY hSubKey;
1867 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1868
1869 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
1870
1871 Status = MapDefaultKey(&KeyHandle,
1872 hKey);
1873 if (!NT_SUCCESS(Status))
1874 {
1875 return RtlNtStatusToDosError(Status);
1876 }
1877
1878 hSubKey = KeyHandle;
1879
1880 if(lpszSubKey)
1881 {
1882 ret = RegOpenKeyExW(KeyHandle, lpszSubKey, 0, KEY_READ, &hSubKey);
1883 if (ret)
1884 {
1885 ClosePredefKey(KeyHandle);
1886 return ret;
1887 }
1888 }
1889
1890 /* Get highest length for keys, values */
1891 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
1892 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
1893 if (ret) goto cleanup;
1894
1895 dwMaxSubkeyLen++;
1896 dwMaxValueLen++;
1897 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
1898 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
1899 {
1900 /* Name too big: alloc a buffer for it */
1901 if (!(lpszName = RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
1902 {
1903 ret = ERROR_NOT_ENOUGH_MEMORY;
1904 goto cleanup;
1905 }
1906 }
1907
1908
1909 /* Recursively delete all the subkeys */
1910 while (TRUE)
1911 {
1912 dwSize = dwMaxLen;
1913 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
1914 NULL, NULL, NULL)) break;
1915
1916 ret = RegDeleteTreeW(hSubKey, lpszName);
1917 if (ret) goto cleanup;
1918 }
1919
1920 if (lpszSubKey)
1921 ret = RegDeleteKeyW(KeyHandle, lpszSubKey);
1922 else
1923 while (TRUE)
1924 {
1925 dwSize = dwMaxLen;
1926 if (RegEnumValueW(KeyHandle, 0, lpszName, &dwSize,
1927 NULL, NULL, NULL, NULL)) break;
1928
1929 ret = RegDeleteValueW(KeyHandle, lpszName);
1930 if (ret) goto cleanup;
1931 }
1932
1933 cleanup:
1934 /* Free buffer if allocated */
1935 if (lpszName != szNameBuf)
1936 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName);
1937 if(lpszSubKey)
1938 RegCloseKey(hSubKey);
1939
1940 ClosePredefKey(KeyHandle);
1941
1942 return ret;
1943 }
1944
1945
1946 /************************************************************************
1947 * RegDeleteTreeA
1948 *
1949 * @implemented
1950 */
1951 LONG WINAPI
1952 RegDeleteTreeA(IN HKEY hKey,
1953 IN LPCSTR lpSubKey OPTIONAL)
1954 {
1955 UNICODE_STRING SubKeyName = { 0, 0, NULL };
1956 LONG Ret;
1957
1958 if (lpSubKey != NULL &&
1959 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1960 (LPSTR)lpSubKey))
1961 {
1962 return ERROR_NOT_ENOUGH_MEMORY;
1963 }
1964
1965 Ret = RegDeleteTreeW(hKey,
1966 SubKeyName.Buffer);
1967
1968 RtlFreeUnicodeString(&SubKeyName);
1969
1970 return Ret;
1971 }
1972
1973
1974 /************************************************************************
1975 * RegDisableReflectionKey
1976 *
1977 * @unimplemented
1978 */
1979 LONG WINAPI
1980 RegDisableReflectionKey(IN HKEY hBase)
1981 {
1982 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1983 return ERROR_CALL_NOT_IMPLEMENTED;
1984 }
1985
1986
1987 /************************************************************************
1988 * RegEnableReflectionKey
1989 *
1990 * @unimplemented
1991 */
1992 LONG WINAPI
1993 RegEnableReflectionKey(IN HKEY hBase)
1994 {
1995 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1996 return ERROR_CALL_NOT_IMPLEMENTED;
1997 }
1998
1999
2000 /******************************************************************************
2001 * RegpApplyRestrictions [internal]
2002 *
2003 * Helper function for RegGetValueA/W.
2004 */
2005 static VOID
2006 RegpApplyRestrictions(DWORD dwFlags,
2007 DWORD dwType,
2008 DWORD cbData,
2009 PLONG ret)
2010 {
2011 /* Check if the type is restricted by the passed flags */
2012 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
2013 {
2014 DWORD dwMask = 0;
2015
2016 switch (dwType)
2017 {
2018 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
2019 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
2020 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
2021 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
2022 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
2023 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
2024 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
2025 }
2026
2027 if (dwFlags & dwMask)
2028 {
2029 /* Type is not restricted, check for size mismatch */
2030 if (dwType == REG_BINARY)
2031 {
2032 DWORD cbExpect = 0;
2033
2034 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
2035 cbExpect = 4;
2036 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
2037 cbExpect = 8;
2038
2039 if (cbExpect && cbData != cbExpect)
2040 *ret = ERROR_DATATYPE_MISMATCH;
2041 }
2042 }
2043 else *ret = ERROR_UNSUPPORTED_TYPE;
2044 }
2045 }
2046
2047
2048 /******************************************************************************
2049 * RegGetValueW [ADVAPI32.@]
2050 *
2051 * Retrieves the type and data for a value name associated with a key,
2052 * optionally expanding its content and restricting its type.
2053 *
2054 * PARAMS
2055 * hKey [I] Handle to an open key.
2056 * pszSubKey [I] Name of the subkey of hKey.
2057 * pszValue [I] Name of value under hKey/szSubKey to query.
2058 * dwFlags [I] Flags restricting the value type to retrieve.
2059 * pdwType [O] Destination for the values type, may be NULL.
2060 * pvData [O] Destination for the values content, may be NULL.
2061 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
2062 * retrieve the whole content, including the trailing '\0'
2063 * for strings.
2064 *
2065 * RETURNS
2066 * Success: ERROR_SUCCESS
2067 * Failure: nonzero error code from Winerror.h
2068 *
2069 * NOTES
2070 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
2071 * expanded and pdwType is set to REG_SZ instead.
2072 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
2073 * without RRF_NOEXPAND is thus not allowed.
2074 * An exception is the case where RRF_RT_ANY is specified, because then
2075 * RRF_NOEXPAND is allowed.
2076 */
2077 LSTATUS WINAPI
2078 RegGetValueW(HKEY hKey,
2079 LPCWSTR pszSubKey,
2080 LPCWSTR pszValue,
2081 DWORD dwFlags,
2082 LPDWORD pdwType,
2083 PVOID pvData,
2084 LPDWORD pcbData)
2085 {
2086 DWORD dwType, cbData = pcbData ? *pcbData : 0;
2087 PVOID pvBuf = NULL;
2088 LONG ret;
2089
2090 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2091 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
2092 pvData, pcbData, cbData);
2093
2094 if (pvData && !pcbData)
2095 return ERROR_INVALID_PARAMETER;
2096 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
2097 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
2098 return ERROR_INVALID_PARAMETER;
2099
2100 if (pszSubKey && pszSubKey[0])
2101 {
2102 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
2103 if (ret != ERROR_SUCCESS) return ret;
2104 }
2105
2106 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
2107
2108 /* If we are going to expand we need to read in the whole the value even
2109 * if the passed buffer was too small as the expanded string might be
2110 * smaller than the unexpanded one and could fit into cbData bytes. */
2111 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
2112 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
2113 {
2114 do
2115 {
2116 HeapFree(GetProcessHeap(), 0, pvBuf);
2117
2118 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2119 if (!pvBuf)
2120 {
2121 ret = ERROR_NOT_ENOUGH_MEMORY;
2122 break;
2123 }
2124
2125 if (ret == ERROR_MORE_DATA || !pvData)
2126 ret = RegQueryValueExW(hKey, pszValue, NULL,
2127 &dwType, pvBuf, &cbData);
2128 else
2129 {
2130 /* Even if cbData was large enough we have to copy the
2131 * string since ExpandEnvironmentStrings can't handle
2132 * overlapping buffers. */
2133 CopyMemory(pvBuf, pvData, cbData);
2134 }
2135
2136 /* Both the type or the value itself could have been modified in
2137 * between so we have to keep retrying until the buffer is large
2138 * enough or we no longer have to expand the value. */
2139 }
2140 while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2141
2142 if (ret == ERROR_SUCCESS)
2143 {
2144 /* Recheck dwType in case it changed since the first call */
2145 if (dwType == REG_EXPAND_SZ)
2146 {
2147 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
2148 pcbData ? *pcbData : 0) * sizeof(WCHAR);
2149 dwType = REG_SZ;
2150 if (pvData && pcbData && cbData > *pcbData)
2151 ret = ERROR_MORE_DATA;
2152 }
2153 else if (pvData)
2154 CopyMemory(pvData, pvBuf, *pcbData);
2155 }
2156
2157 HeapFree(GetProcessHeap(), 0, pvBuf);
2158 }
2159
2160 if (pszSubKey && pszSubKey[0])
2161 RegCloseKey(hKey);
2162
2163 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2164
2165 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
2166 ZeroMemory(pvData, *pcbData);
2167
2168 if (pdwType)
2169 *pdwType = dwType;
2170
2171 if (pcbData)
2172 *pcbData = cbData;
2173
2174 return ret;
2175 }
2176
2177
2178 /******************************************************************************
2179 * RegGetValueA [ADVAPI32.@]
2180 *
2181 * See RegGetValueW.
2182 */
2183 LSTATUS WINAPI
2184 RegGetValueA(HKEY hKey,
2185 LPCSTR pszSubKey,
2186 LPCSTR pszValue,
2187 DWORD dwFlags,
2188 LPDWORD pdwType,
2189 PVOID pvData,
2190 LPDWORD pcbData)
2191 {
2192 DWORD dwType, cbData = pcbData ? *pcbData : 0;
2193 PVOID pvBuf = NULL;
2194 LONG ret;
2195
2196 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2197 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
2198 cbData);
2199
2200 if (pvData && !pcbData)
2201 return ERROR_INVALID_PARAMETER;
2202 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
2203 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
2204 return ERROR_INVALID_PARAMETER;
2205
2206 if (pszSubKey && pszSubKey[0])
2207 {
2208 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
2209 if (ret != ERROR_SUCCESS) return ret;
2210 }
2211
2212 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
2213
2214 /* If we are going to expand we need to read in the whole the value even
2215 * if the passed buffer was too small as the expanded string might be
2216 * smaller than the unexpanded one and could fit into cbData bytes. */
2217 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
2218 (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
2219 {
2220 do {
2221 HeapFree(GetProcessHeap(), 0, pvBuf);
2222
2223 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2224 if (!pvBuf)
2225 {
2226 ret = ERROR_NOT_ENOUGH_MEMORY;
2227 break;
2228 }
2229
2230 if (ret == ERROR_MORE_DATA || !pvData)
2231 ret = RegQueryValueExA(hKey, pszValue, NULL,
2232 &dwType, pvBuf, &cbData);
2233 else
2234 {
2235 /* Even if cbData was large enough we have to copy the
2236 * string since ExpandEnvironmentStrings can't handle
2237 * overlapping buffers. */
2238 CopyMemory(pvBuf, pvData, cbData);
2239 }
2240
2241 /* Both the type or the value itself could have been modified in
2242 * between so we have to keep retrying until the buffer is large
2243 * enough or we no longer have to expand the value. */
2244 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2245
2246 if (ret == ERROR_SUCCESS)
2247 {
2248 /* Recheck dwType in case it changed since the first call */
2249 if (dwType == REG_EXPAND_SZ)
2250 {
2251 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
2252 pcbData ? *pcbData : 0);
2253 dwType = REG_SZ;
2254 if(pvData && pcbData && cbData > *pcbData)
2255 ret = ERROR_MORE_DATA;
2256 }
2257 else if (pvData)
2258 CopyMemory(pvData, pvBuf, *pcbData);
2259 }
2260
2261 HeapFree(GetProcessHeap(), 0, pvBuf);
2262 }
2263
2264 if (pszSubKey && pszSubKey[0])
2265 RegCloseKey(hKey);
2266
2267 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2268
2269 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
2270 ZeroMemory(pvData, *pcbData);
2271
2272 if (pdwType) *pdwType = dwType;
2273 if (pcbData) *pcbData = cbData;
2274
2275 return ret;
2276 }
2277
2278
2279 /************************************************************************
2280 * RegSetKeyValueW
2281 *
2282 * @implemented
2283 */
2284 LONG WINAPI
2285 RegSetKeyValueW(IN HKEY hKey,
2286 IN LPCWSTR lpSubKey OPTIONAL,
2287 IN LPCWSTR lpValueName OPTIONAL,
2288 IN DWORD dwType,
2289 IN LPCVOID lpData OPTIONAL,
2290 IN DWORD cbData)
2291 {
2292 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2293 NTSTATUS Status;
2294 LONG Ret;
2295
2296 Status = MapDefaultKey(&KeyHandle,
2297 hKey);
2298 if (!NT_SUCCESS(Status))
2299 {
2300 return RtlNtStatusToDosError(Status);
2301 }
2302
2303 if (lpSubKey != NULL)
2304 {
2305 OBJECT_ATTRIBUTES ObjectAttributes;
2306 UNICODE_STRING SubKeyName;
2307
2308 RtlInitUnicodeString(&SubKeyName,
2309 (LPWSTR)lpSubKey);
2310
2311 InitializeObjectAttributes(&ObjectAttributes,
2312 &SubKeyName,
2313 OBJ_CASE_INSENSITIVE,
2314 KeyHandle,
2315 NULL);
2316
2317 Status = NtOpenKey(&SubKeyHandle,
2318 KEY_SET_VALUE,
2319 &ObjectAttributes);
2320 if (!NT_SUCCESS(Status))
2321 {
2322 Ret = RtlNtStatusToDosError(Status);
2323 goto Cleanup;
2324 }
2325
2326 CurKey = SubKeyHandle;
2327 }
2328 else
2329 CurKey = KeyHandle;
2330
2331 Ret = RegSetValueExW(CurKey,
2332 lpValueName,
2333 0,
2334 dwType,
2335 lpData,
2336 cbData);
2337
2338 if (SubKeyHandle != NULL)
2339 {
2340 NtClose(SubKeyHandle);
2341 }
2342
2343 Cleanup:
2344 ClosePredefKey(KeyHandle);
2345
2346 return Ret;
2347 }
2348
2349
2350 /************************************************************************
2351 * RegSetKeyValueA
2352 *
2353 * @implemented
2354 */
2355 LONG WINAPI
2356 RegSetKeyValueA(IN HKEY hKey,
2357 IN LPCSTR lpSubKey OPTIONAL,
2358 IN LPCSTR lpValueName OPTIONAL,
2359 IN DWORD dwType,
2360 IN LPCVOID lpData OPTIONAL,
2361 IN DWORD cbData)
2362 {
2363 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2364 NTSTATUS Status;
2365 LONG Ret;
2366
2367 Status = MapDefaultKey(&KeyHandle,
2368 hKey);
2369 if (!NT_SUCCESS(Status))
2370 {
2371 return RtlNtStatusToDosError(Status);
2372 }
2373
2374 if (lpSubKey != NULL)
2375 {
2376 OBJECT_ATTRIBUTES ObjectAttributes;
2377 UNICODE_STRING SubKeyName;
2378
2379 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
2380 (LPSTR)lpSubKey))
2381 {
2382 Ret = ERROR_NOT_ENOUGH_MEMORY;
2383 goto Cleanup;
2384 }
2385
2386 InitializeObjectAttributes(&ObjectAttributes,
2387 &SubKeyName,
2388 OBJ_CASE_INSENSITIVE,
2389 KeyHandle,
2390 NULL);
2391
2392 Status = NtOpenKey(&SubKeyHandle,
2393 KEY_SET_VALUE,
2394 &ObjectAttributes);
2395
2396 RtlFreeUnicodeString(&SubKeyName);
2397
2398 if (!NT_SUCCESS(Status))
2399 {
2400 Ret = RtlNtStatusToDosError(Status);
2401 goto Cleanup;
2402 }
2403
2404 CurKey = SubKeyHandle;
2405 }
2406 else
2407 CurKey = KeyHandle;
2408
2409 Ret = RegSetValueExA(CurKey,
2410 lpValueName,
2411 0,
2412 dwType,
2413 lpData,
2414 cbData);
2415
2416 if (SubKeyHandle != NULL)
2417 {
2418 NtClose(SubKeyHandle);
2419 }
2420
2421 Cleanup:
2422 ClosePredefKey(KeyHandle);
2423
2424 return Ret;
2425 }
2426
2427
2428 /************************************************************************
2429 * RegDeleteValueA
2430 *
2431 * @implemented
2432 */
2433 LONG WINAPI
2434 RegDeleteValueA(HKEY hKey,
2435 LPCSTR lpValueName)
2436 {
2437 UNICODE_STRING ValueName;
2438 HANDLE KeyHandle;
2439 NTSTATUS Status;
2440
2441 Status = MapDefaultKey(&KeyHandle,
2442 hKey);
2443 if (!NT_SUCCESS(Status))
2444 {
2445 return RtlNtStatusToDosError(Status);
2446 }
2447
2448 RtlCreateUnicodeStringFromAsciiz(&ValueName,
2449 (LPSTR)lpValueName);
2450 Status = NtDeleteValueKey(KeyHandle,
2451 &ValueName);
2452 RtlFreeUnicodeString (&ValueName);
2453
2454 ClosePredefKey(KeyHandle);
2455
2456 if (!NT_SUCCESS(Status))
2457 {
2458 return RtlNtStatusToDosError(Status);
2459 }
2460
2461 return ERROR_SUCCESS;
2462 }
2463
2464
2465 /************************************************************************
2466 * RegDeleteValueW
2467 *
2468 * @implemented
2469 */
2470 LONG WINAPI
2471 RegDeleteValueW(HKEY hKey,
2472 LPCWSTR lpValueName)
2473 {
2474 UNICODE_STRING ValueName;
2475 NTSTATUS Status;
2476 HANDLE KeyHandle;
2477
2478 Status = MapDefaultKey(&KeyHandle,
2479 hKey);
2480 if (!NT_SUCCESS(Status))
2481 {
2482 return RtlNtStatusToDosError(Status);
2483 }
2484
2485 RtlInitUnicodeString(&ValueName,
2486 (LPWSTR)lpValueName);
2487
2488 Status = NtDeleteValueKey(KeyHandle,
2489 &ValueName);
2490
2491 ClosePredefKey(KeyHandle);
2492
2493 if (!NT_SUCCESS(Status))
2494 {
2495 return RtlNtStatusToDosError(Status);
2496 }
2497
2498 return ERROR_SUCCESS;
2499 }
2500
2501
2502 /************************************************************************
2503 * RegEnumKeyA
2504 *
2505 * @implemented
2506 */
2507 LONG WINAPI
2508 RegEnumKeyA(HKEY hKey,
2509 DWORD dwIndex,
2510 LPSTR lpName,
2511 DWORD cbName)
2512 {
2513 DWORD dwLength;
2514
2515 dwLength = cbName;
2516 return RegEnumKeyExA(hKey,
2517 dwIndex,
2518 lpName,
2519 &dwLength,
2520 NULL,
2521 NULL,
2522 NULL,
2523 NULL);
2524 }
2525
2526
2527 /************************************************************************
2528 * RegEnumKeyW
2529 *
2530 * @implemented
2531 */
2532 LONG WINAPI
2533 RegEnumKeyW(HKEY hKey,
2534 DWORD dwIndex,
2535 LPWSTR lpName,
2536 DWORD cbName)
2537 {
2538 DWORD dwLength;
2539
2540 dwLength = cbName;
2541 return RegEnumKeyExW(hKey,
2542 dwIndex,
2543 lpName,
2544 &dwLength,
2545 NULL,
2546 NULL,
2547 NULL,
2548 NULL);
2549 }
2550
2551
2552 /************************************************************************
2553 * RegEnumKeyExA
2554 *
2555 * @implemented
2556 */
2557 LONG WINAPI
2558 RegEnumKeyExA(HKEY hKey,
2559 DWORD dwIndex,
2560 LPSTR lpName,
2561 LPDWORD lpcbName,
2562 LPDWORD lpReserved,
2563 LPSTR lpClass,
2564 LPDWORD lpcbClass,
2565 PFILETIME lpftLastWriteTime)
2566 {
2567 union
2568 {
2569 KEY_NODE_INFORMATION Node;
2570 KEY_BASIC_INFORMATION Basic;
2571 } *KeyInfo;
2572
2573 UNICODE_STRING StringU;
2574 ANSI_STRING StringA;
2575 LONG ErrorCode = ERROR_SUCCESS;
2576 DWORD NameLength;
2577 DWORD ClassLength = 0;
2578 DWORD BufferSize;
2579 ULONG ResultSize;
2580 HANDLE KeyHandle;
2581 NTSTATUS Status;
2582
2583 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2584 hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
2585
2586 if ((lpClass) && (!lpcbClass))
2587 {
2588 return ERROR_INVALID_PARAMETER;
2589 }
2590
2591 Status = MapDefaultKey(&KeyHandle, hKey);
2592 if (!NT_SUCCESS(Status))
2593 {
2594 return RtlNtStatusToDosError(Status);
2595 }
2596
2597 if (*lpcbName > 0)
2598 {
2599 NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
2600 }
2601 else
2602 {
2603 NameLength = 0;
2604 }
2605
2606 if (lpClass)
2607 {
2608 if (*lpcbClass > 0)
2609 {
2610 ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2611 }
2612 else
2613 {
2614 ClassLength = 0;
2615 }
2616
2617 /* The class name should start at a dword boundary */
2618 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
2619 }
2620 else
2621 {
2622 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
2623 }
2624
2625 KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
2626 if (KeyInfo == NULL)
2627 {
2628 ErrorCode = ERROR_OUTOFMEMORY;
2629 goto Cleanup;
2630 }
2631
2632 Status = NtEnumerateKey(KeyHandle,
2633 (ULONG)dwIndex,
2634 lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
2635 KeyInfo,
2636 BufferSize,
2637 &ResultSize);
2638 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
2639 if (!NT_SUCCESS(Status))
2640 {
2641 ErrorCode = RtlNtStatusToDosError (Status);
2642 }
2643 else
2644 {
2645 if (lpClass == NULL)
2646 {
2647 if (KeyInfo->Basic.NameLength > NameLength)
2648 {
2649 ErrorCode = ERROR_BUFFER_OVERFLOW;
2650 }
2651 else
2652 {
2653 StringU.Buffer = KeyInfo->Basic.Name;
2654 StringU.Length = KeyInfo->Basic.NameLength;
2655 StringU.MaximumLength = KeyInfo->Basic.NameLength;
2656 }
2657 }
2658 else
2659 {
2660 if (KeyInfo->Node.NameLength > NameLength ||
2661 KeyInfo->Node.ClassLength > ClassLength)
2662 {
2663 ErrorCode = ERROR_BUFFER_OVERFLOW;
2664 }
2665 else
2666 {
2667 StringA.Buffer = lpClass;
2668 StringA.Length = 0;
2669 StringA.MaximumLength = *lpcbClass;
2670 StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
2671 StringU.Length = KeyInfo->Node.ClassLength;
2672 StringU.MaximumLength = KeyInfo->Node.ClassLength;
2673 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
2674 lpClass[StringA.Length] = 0;
2675 *lpcbClass = StringA.Length;
2676 StringU.Buffer = KeyInfo->Node.Name;
2677 StringU.Length = KeyInfo->Node.NameLength;
2678 StringU.MaximumLength = KeyInfo->Node.NameLength;
2679 }
2680 }
2681
2682 if (ErrorCode == ERROR_SUCCESS)
2683 {
2684 StringA.Buffer = lpName;
2685 StringA.Length = 0;
2686 StringA.MaximumLength = *lpcbName;
2687 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
2688 lpName[StringA.Length] = 0;
2689 *lpcbName = StringA.Length;
2690 if (lpftLastWriteTime != NULL)
2691 {
2692 if (lpClass == NULL)
2693 {
2694 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
2695 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
2696 }
2697 else
2698 {
2699 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
2700 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
2701 }
2702 }
2703 }
2704 }
2705
2706 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2707 TRACE("Key Name1 Length %d\n", NameLength);
2708 TRACE("Key Name Length %d\n", *lpcbName);
2709 TRACE("Key Name %s\n", lpName);
2710
2711 RtlFreeHeap(ProcessHeap,
2712 0,
2713 KeyInfo);
2714
2715 Cleanup:
2716 ClosePredefKey(KeyHandle);
2717
2718 return ErrorCode;
2719 }
2720
2721
2722 /************************************************************************
2723 * RegEnumKeyExW
2724 *
2725 * @implemented
2726 */
2727 LONG WINAPI
2728 RegEnumKeyExW(HKEY hKey,
2729 DWORD dwIndex,
2730 LPWSTR lpName,
2731 LPDWORD lpcbName,
2732 LPDWORD lpReserved,
2733 LPWSTR lpClass,
2734 LPDWORD lpcbClass,
2735 PFILETIME lpftLastWriteTime)
2736 {
2737 union
2738 {
2739 KEY_NODE_INFORMATION Node;
2740 KEY_BASIC_INFORMATION Basic;
2741 } *KeyInfo;
2742
2743 ULONG BufferSize;
2744 ULONG ResultSize;
2745 ULONG NameLength;
2746 ULONG ClassLength = 0;
2747 HANDLE KeyHandle;
2748 LONG ErrorCode = ERROR_SUCCESS;
2749 NTSTATUS Status;
2750
2751 Status = MapDefaultKey(&KeyHandle,
2752 hKey);
2753 if (!NT_SUCCESS(Status))
2754 {
2755 return RtlNtStatusToDosError(Status);
2756 }
2757
2758 if (*lpcbName > 0)
2759 {
2760 NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
2761 }
2762 else
2763 {
2764 NameLength = 0;
2765 }
2766
2767 if (lpClass)
2768 {
2769 if (*lpcbClass > 0)
2770 {
2771 ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2772 }
2773 else
2774 {
2775 ClassLength = 0;
2776 }
2777
2778 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
2779 }
2780 else
2781 {
2782 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
2783 }
2784
2785 KeyInfo = RtlAllocateHeap(ProcessHeap,
2786 0,
2787 BufferSize);
2788 if (KeyInfo == NULL)
2789 {
2790 ErrorCode = ERROR_OUTOFMEMORY;
2791 goto Cleanup;
2792 }
2793
2794 Status = NtEnumerateKey(KeyHandle,
2795 (ULONG)dwIndex,
2796 lpClass ? KeyNodeInformation : KeyBasicInformation,
2797 KeyInfo,
2798 BufferSize,
2799 &ResultSize);
2800 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
2801 if (!NT_SUCCESS(Status))
2802 {
2803 ErrorCode = RtlNtStatusToDosError (Status);
2804 }
2805 else
2806 {
2807 if (lpClass == NULL)
2808 {
2809 if (KeyInfo->Basic.NameLength > NameLength)
2810 {
2811 ErrorCode = ERROR_BUFFER_OVERFLOW;
2812 }
2813 else
2814 {
2815 RtlCopyMemory(lpName,
2816 KeyInfo->Basic.Name,
2817 KeyInfo->Basic.NameLength);
2818 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
2819 lpName[*lpcbName] = 0;
2820 }
2821 }
2822 else
2823 {
2824 if (KeyInfo->Node.NameLength > NameLength ||
2825 KeyInfo->Node.ClassLength > ClassLength)
2826 {
2827 ErrorCode = ERROR_BUFFER_OVERFLOW;
2828 }
2829 else
2830 {
2831 RtlCopyMemory(lpName,
2832 KeyInfo->Node.Name,
2833 KeyInfo->Node.NameLength);
2834 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
2835 lpName[*lpcbName] = 0;
2836 RtlCopyMemory(lpClass,
2837 (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
2838 KeyInfo->Node.ClassLength);
2839 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
2840 lpClass[*lpcbClass] = 0;
2841 }
2842 }
2843
2844 if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
2845 {
2846 if (lpClass == NULL)
2847 {
2848 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
2849 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
2850 }
2851 else
2852 {
2853 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
2854 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
2855 }
2856 }
2857 }
2858
2859 RtlFreeHeap(ProcessHeap,
2860 0,
2861 KeyInfo);
2862
2863 Cleanup:
2864 ClosePredefKey(KeyHandle);
2865
2866 return ErrorCode;
2867 }
2868
2869
2870 /************************************************************************
2871 * RegEnumValueA
2872 *
2873 * @implemented
2874 */
2875 LONG WINAPI
2876 RegEnumValueA(HKEY hKey,
2877 DWORD index,
2878 LPSTR value,
2879 LPDWORD val_count,
2880 LPDWORD reserved,
2881 LPDWORD type,
2882 LPBYTE data,
2883 LPDWORD count)
2884 {
2885 HANDLE KeyHandle;
2886 NTSTATUS status;
2887 ULONG total_size;
2888 char buffer[256], *buf_ptr = buffer;
2889 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2890 static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
2891
2892 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2893 // hkey, index, value, val_count, reserved, type, data, count );
2894
2895 /* NT only checks count, not val_count */
2896 if ((data && !count) || reserved)
2897 return ERROR_INVALID_PARAMETER;
2898
2899 status = MapDefaultKey(&KeyHandle, hKey);
2900 if (!NT_SUCCESS(status))
2901 {
2902 return RtlNtStatusToDosError(status);
2903 }
2904
2905 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2906 if (data) total_size += *count;
2907 total_size = min( sizeof(buffer), total_size );
2908
2909 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2910 buffer, total_size, &total_size );
2911 if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
2912
2913 /* we need to fetch the contents for a string type even if not requested,
2914 * because we need to compute the length of the ASCII string. */
2915 if (value || data || is_string(info->Type))
2916 {
2917 /* retry with a dynamically allocated buffer */
2918 while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL))
2919 {
2920 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2921 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2922 {
2923 status = STATUS_INSUFFICIENT_RESOURCES;
2924 goto done;
2925 }
2926 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2927 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2928 buf_ptr, total_size, &total_size );
2929 }
2930
2931 if (status) goto done;
2932
2933 if (is_string(info->Type))
2934 {
2935 ULONG len;
2936 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2937 info->DataLength );
2938 if (data && len)
2939 {
2940 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2941 else
2942 {
2943 RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2944 info->DataLength );
2945 /* if the type is REG_SZ and data is not 0-terminated
2946 * and there is enough space in the buffer NT appends a \0 */
2947 if (len < *count && data[len-1]) data[len] = 0;
2948 }
2949 }
2950 info->DataLength = len;
2951 }
2952 else if (data)
2953 {
2954 if (info->DataLength > *count) status = STATUS_BUFFER_OVERFLOW;
2955 else memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
2956 }
2957
2958 if (value && !status)
2959 {
2960 ULONG len;
2961
2962 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2963 if (len >= *val_count)
2964 {
2965 status = STATUS_BUFFER_OVERFLOW;
2966 if (*val_count)
2967 {
2968 len = *val_count - 1;
2969 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2970 value[len] = 0;
2971 }
2972 }
2973 else
2974 {
2975 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2976 value[len] = 0;
2977 *val_count = len;
2978 }
2979 }
2980 }
2981 else status = STATUS_SUCCESS;
2982
2983 if (type) *type = info->Type;
2984 if (count) *count = info->DataLength;
2985
2986 done:
2987 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2988 ClosePredefKey(KeyHandle);
2989 return RtlNtStatusToDosError(status);
2990 }
2991
2992
2993 /******************************************************************************
2994 * RegEnumValueW [ADVAPI32.@]
2995 * @implemented
2996 *
2997 * PARAMS
2998 * hkey [I] Handle to key to query
2999 * index [I] Index of value to query
3000 * value [O] Value string
3001 * val_count [I/O] Size of value buffer (in wchars)
3002 * reserved [I] Reserved
3003 * type [O] Type code
3004 * data [O] Value data
3005 * count [I/O] Size of data buffer (in bytes)
3006 *
3007 * RETURNS
3008 * Success: ERROR_SUCCESS
3009 * Failure: nonzero error code from Winerror.h
3010 */
3011 LONG WINAPI
3012 RegEnumValueW(HKEY hKey,
3013 DWORD index,
3014 LPWSTR value,
3015 PDWORD val_count,
3016 PDWORD reserved,
3017 PDWORD type,
3018 LPBYTE data,
3019 PDWORD count)
3020 {
3021 HANDLE KeyHandle;
3022 NTSTATUS status;
3023 ULONG total_size;
3024 char buffer[256], *buf_ptr = buffer;
3025 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
3026 static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
3027
3028 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
3029 // hkey, index, value, val_count, reserved, type, data, count );
3030
3031 /* NT only checks count, not val_count */
3032 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
3033
3034 status = MapDefaultKey(&KeyHandle, hKey);
3035 if (!NT_SUCCESS(status))
3036 {
3037 return RtlNtStatusToDosError(status);
3038 }
3039
3040 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
3041 if (data) total_size += *count;
3042 total_size = min( sizeof(buffer), total_size );
3043
3044 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
3045 buffer, total_size, &total_size );
3046 if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
3047
3048 if (value || data)
3049 {
3050 /* retry with a dynamically allocated buffer */
3051 while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL))
3052 {
3053 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
3054 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
3055 {
3056 status = ERROR_NOT_ENOUGH_MEMORY;
3057 goto done;
3058 }
3059 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
3060 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
3061 buf_ptr, total_size, &total_size );
3062 }
3063
3064 if (status) goto done;
3065
3066 if (value)
3067 {
3068 if (info->NameLength/sizeof(WCHAR) >= *val_count)
3069 {
3070 status = STATUS_BUFFER_OVERFLOW;
3071 goto overflow;
3072 }
3073 memcpy( value, info->Name, info->NameLength );
3074 *val_count = info->NameLength / sizeof(WCHAR);
3075 value[*val_count] = 0;
3076 }
3077
3078 if (data)
3079 {
3080 if (info->DataLength > *count)
3081 {
3082 status = STATUS_BUFFER_OVERFLOW;
3083 goto overflow;
3084 }
3085 memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
3086 if (is_string(info->Type) && info->DataLength <= *count - sizeof(WCHAR))
3087 {
3088 /* if the type is REG_SZ and data is not 0-terminated
3089 * and there is enough space in the buffer NT appends a \0 */
3090 WCHAR *ptr = (WCHAR *)(data + info->DataLength);
3091 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
3092 }
3093 }
3094 }
3095 else status = STATUS_SUCCESS;
3096
3097 overflow:
3098 if (type) *type = info->Type;
3099 if (count) *count = info->DataLength;
3100
3101 done:
3102 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
3103 ClosePredefKey(KeyHandle);
3104 return RtlNtStatusToDosError(status);
3105 }
3106
3107
3108 /************************************************************************
3109 * RegFlushKey
3110 *
3111 * @implemented
3112 */
3113 LONG WINAPI
3114 RegFlushKey(HKEY hKey)
3115 {
3116 HANDLE KeyHandle;
3117 NTSTATUS Status;
3118
3119 if (hKey == HKEY_PERFORMANCE_DATA)
3120 {
3121 return ERROR_SUCCESS;
3122 }
3123
3124 Status = MapDefaultKey(&KeyHandle,
3125 hKey);
3126 if (!NT_SUCCESS(Status))
3127 {
3128 return RtlNtStatusToDosError(Status);
3129 }
3130
3131 Status = NtFlushKey(KeyHandle);
3132
3133 ClosePredefKey(KeyHandle);
3134
3135 if (!NT_SUCCESS(Status))
3136 {
3137 return RtlNtStatusToDosError(Status);
3138 }
3139
3140 return ERROR_SUCCESS;
3141 }
3142
3143
3144 /************************************************************************
3145 * RegGetKeySecurity
3146 *
3147 * @implemented
3148 */
3149 LONG WINAPI
3150 RegGetKeySecurity(HKEY hKey,
3151 SECURITY_INFORMATION SecurityInformation,
3152 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3153 LPDWORD lpcbSecurityDescriptor)
3154 {
3155 HANDLE KeyHandle;
3156 NTSTATUS Status;
3157
3158 if (hKey == HKEY_PERFORMANCE_DATA)
3159 {
3160 return ERROR_INVALID_HANDLE;
3161 }
3162
3163 Status = MapDefaultKey(&KeyHandle,
3164 hKey);
3165 if (!NT_SUCCESS(Status))
3166 {
3167 TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
3168 return RtlNtStatusToDosError(Status);
3169 }
3170
3171 #if 0
3172 Status = NtQuerySecurityObject(KeyHandle,
3173 SecurityInformation,
3174 pSecurityDescriptor,
3175 *lpcbSecurityDescriptor,
3176 lpcbSecurityDescriptor);
3177 #endif
3178
3179 ClosePredefKey(KeyHandle);
3180
3181 if (!NT_SUCCESS(Status))
3182 {
3183 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
3184 return RtlNtStatusToDosError(Status);
3185 }
3186
3187 return ERROR_SUCCESS;
3188 }
3189
3190
3191 /************************************************************************
3192 * RegLoadKeyA
3193 *
3194 * @implemented
3195 */
3196 LONG WINAPI
3197 RegLoadKeyA(HKEY hKey,
3198 LPCSTR lpSubKey,
3199 LPCSTR lpFile)
3200 {
3201 UNICODE_STRING FileName;
3202 UNICODE_STRING KeyName;
3203 LONG ErrorCode;
3204
3205 RtlCreateUnicodeStringFromAsciiz(&KeyName,
3206 (LPSTR)lpSubKey);
3207 RtlCreateUnicodeStringFromAsciiz(&FileName,
3208 (LPSTR)lpFile);
3209
3210 ErrorCode = RegLoadKeyW(hKey,
3211 KeyName.Buffer,
3212 FileName.Buffer);
3213
3214 RtlFreeUnicodeString(&FileName);
3215 RtlFreeUnicodeString(&KeyName);
3216
3217 return ErrorCode;
3218 }
3219
3220
3221 /************************************************************************
3222 * RegLoadKeyW
3223 *
3224 * @implemented
3225 */
3226 LONG WINAPI
3227 RegLoadKeyW(HKEY hKey,
3228 LPCWSTR lpSubKey,
3229 LPCWSTR lpFile)
3230 {
3231 OBJECT_ATTRIBUTES FileObjectAttributes;
3232 OBJECT_ATTRIBUTES KeyObjectAttributes;
3233 UNICODE_STRING FileName;
3234 UNICODE_STRING KeyName;
3235 HANDLE KeyHandle;
3236 NTSTATUS Status;
3237 LONG ErrorCode = ERROR_SUCCESS;
3238
3239 if (hKey == HKEY_PERFORMANCE_DATA)
3240 {
3241 return ERROR_INVALID_HANDLE;
3242 }
3243
3244 Status = MapDefaultKey(&KeyHandle,
3245 hKey);
3246 if (!NT_SUCCESS(Status))
3247 {
3248 return RtlNtStatusToDosError(Status);
3249 }
3250
3251 if (!RtlDosPathNameToNtPathName_U(lpFile,
3252 &FileName,
3253 NULL,
3254 NULL))
3255 {
3256 ErrorCode = ERROR_BAD_PATHNAME;
3257 goto Cleanup;
3258 }
3259
3260 InitializeObjectAttributes(&FileObjectAttributes,
3261 &FileName,
3262 OBJ_CASE_INSENSITIVE,
3263 NULL,
3264 NULL);
3265
3266 RtlInitUnicodeString(&KeyName,
3267 (LPWSTR)lpSubKey);
3268
3269 InitializeObjectAttributes(&KeyObjectAttributes,
3270 &KeyName,
3271 OBJ_CASE_INSENSITIVE,
3272 KeyHandle,
3273 NULL);
3274
3275 Status = NtLoadKey(&KeyObjectAttributes,
3276 &FileObjectAttributes);
3277
3278 RtlFreeHeap(RtlGetProcessHeap(),
3279 0,
3280 FileName.Buffer);
3281
3282 if (!NT_SUCCESS(Status))
3283 {
3284 ErrorCode = RtlNtStatusToDosError(Status);
3285 goto Cleanup;
3286 }
3287
3288 Cleanup:
3289 ClosePredefKey(KeyHandle);
3290
3291 return ErrorCode;
3292 }
3293
3294
3295 /************************************************************************
3296 * RegNotifyChangeKeyValue
3297 *
3298 * @unimplemented
3299 */
3300 LONG WINAPI
3301 RegNotifyChangeKeyValue(HKEY hKey,
3302 BOOL bWatchSubtree,
3303 DWORD dwNotifyFilter,
3304 HANDLE hEvent,
3305 BOOL fAsynchronous)
3306 {
3307 IO_STATUS_BLOCK IoStatusBlock;
3308 HANDLE KeyHandle;
3309 NTSTATUS Status;
3310 LONG ErrorCode = ERROR_SUCCESS;
3311
3312 if (hKey == HKEY_PERFORMANCE_DATA)
3313 {
3314 return ERROR_INVALID_HANDLE;
3315 }
3316
3317 if (fAsynchronous == TRUE && hEvent == NULL)
3318 {
3319 return ERROR_INVALID_PARAMETER;
3320 }
3321
3322 Status = MapDefaultKey(&KeyHandle,
3323 hKey);
3324 if (!NT_SUCCESS(Status))
3325 {
3326 return RtlNtStatusToDosError(Status);
3327 }
3328
3329 /* FIXME: Remote key handles must fail */
3330
3331 Status = NtNotifyChangeKey(KeyHandle,
3332 hEvent,
3333 0,
3334 0,
3335 &IoStatusBlock,
3336 dwNotifyFilter,
3337 bWatchSubtree,
3338 0,
3339 0,
3340 fAsynchronous);
3341 if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
3342 {
3343 ErrorCode = RtlNtStatusToDosError(Status);
3344 }
3345
3346 ClosePredefKey(KeyHandle);
3347
3348 return ErrorCode;
3349 }
3350
3351
3352 /************************************************************************
3353 * RegOpenCurrentUser
3354 *
3355 * @implemented
3356 */
3357 LONG WINAPI
3358 RegOpenCurrentUser(IN REGSAM samDesired,
3359 OUT PHKEY phkResult)
3360 {
3361 NTSTATUS Status;
3362
3363 Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
3364 (PHANDLE)phkResult);
3365 if (!NT_SUCCESS(Status))
3366 {
3367 /* NOTE - don't set the last error code! just return the error! */
3368 return RtlNtStatusToDosError(Status);
3369 }
3370
3371 return ERROR_SUCCESS;
3372 }
3373
3374
3375 /************************************************************************
3376 * RegOpenKeyA
3377 *
3378 * 20050503 Fireball - imported from WINE
3379 *
3380 * @implemented
3381 */
3382 LONG WINAPI
3383 RegOpenKeyA(HKEY hKey,
3384 LPCSTR lpSubKey,
3385 PHKEY phkResult)
3386 {
3387 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3388 hKey, lpSubKey, phkResult);
3389
3390 if (!phkResult)
3391 return ERROR_INVALID_PARAMETER;
3392
3393 if (!hKey && lpSubKey && phkResult)
3394 {
3395 return ERROR_INVALID_HANDLE;
3396 }
3397
3398 if (!lpSubKey || !*lpSubKey)
3399 {
3400 *phkResult = hKey;
3401 return ERROR_SUCCESS;
3402 }
3403
3404 return RegOpenKeyExA(hKey,
3405 lpSubKey,
3406 0,
3407 MAXIMUM_ALLOWED,
3408 phkResult);
3409 }
3410
3411
3412 /************************************************************************
3413 * RegOpenKeyW
3414 *
3415 * 19981101 Ariadne
3416 * 19990525 EA
3417 * 20050503 Fireball - imported from WINE
3418 *
3419 * @implemented
3420 */
3421 LONG WINAPI
3422 RegOpenKeyW(HKEY hKey,
3423 LPCWSTR lpSubKey,
3424 PHKEY phkResult)
3425 {
3426 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3427 hKey, lpSubKey, phkResult);
3428
3429 if (!phkResult)
3430 return ERROR_INVALID_PARAMETER;
3431
3432 if (!hKey && lpSubKey && phkResult)
3433 {
3434 return ERROR_INVALID_HANDLE;
3435 }
3436
3437 if (!lpSubKey || !*lpSubKey)
3438 {
3439 *phkResult = hKey;
3440 return ERROR_SUCCESS;
3441 }
3442
3443 return RegOpenKeyExW(hKey,
3444 lpSubKey,
3445 0,
3446 MAXIMUM_ALLOWED,
3447 phkResult);
3448 }
3449
3450
3451 /************************************************************************
3452 * RegOpenKeyExA
3453 *
3454 * @implemented
3455 */
3456 LONG WINAPI
3457 RegOpenKeyExA(HKEY hKey,
3458 LPCSTR lpSubKey,
3459 DWORD ulOptions,
3460 REGSAM samDesired,
3461 PHKEY phkResult)
3462 {
3463 OBJECT_ATTRIBUTES ObjectAttributes;
3464 UNICODE_STRING SubKeyString;
3465 HANDLE KeyHandle;
3466 NTSTATUS Status;
3467 ULONG Attributes = OBJ_CASE_INSENSITIVE;
3468 LONG ErrorCode = ERROR_SUCCESS;
3469
3470 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3471 hKey, lpSubKey, ulOptions, samDesired, phkResult);
3472 if (!phkResult)
3473 {
3474 return ERROR_INVALID_PARAMETER;
3475 }
3476
3477 Status = MapDefaultKey(&KeyHandle,
3478 hKey);
3479 if (!NT_SUCCESS(Status))
3480 {
3481 return RtlNtStatusToDosError(Status);
3482 }
3483
3484 if (ulOptions & REG_OPTION_OPEN_LINK)
3485 Attributes |= OBJ_OPENLINK;
3486
3487 RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
3488 (LPSTR)lpSubKey);
3489 InitializeObjectAttributes(&ObjectAttributes,
3490 &SubKeyString,
3491 Attributes,
3492 KeyHandle,
3493 NULL);
3494
3495 Status = NtOpenKey((PHANDLE)phkResult,
3496 samDesired,
3497 &ObjectAttributes);
3498 RtlFreeUnicodeString(&SubKeyString);
3499 if (!NT_SUCCESS(Status))
3500 {
3501 ErrorCode = RtlNtStatusToDosError(Status);
3502 }
3503
3504 ClosePredefKey(KeyHandle);
3505
3506 return ErrorCode;
3507 }
3508
3509
3510 /************************************************************************
3511 * RegOpenKeyExW
3512 *
3513 * @implemented
3514 */
3515 LONG WINAPI
3516 RegOpenKeyExW(HKEY hKey,
3517 LPCWSTR lpSubKey,
3518 DWORD ulOptions,
3519 REGSAM samDesired,
3520 PHKEY phkResult)
3521 {
3522 OBJECT_ATTRIBUTES ObjectAttributes;
3523 UNICODE_STRING SubKeyString;
3524 HANDLE KeyHandle;
3525 NTSTATUS Status;
3526 ULONG Attributes = OBJ_CASE_INSENSITIVE;
3527 LONG ErrorCode = ERROR_SUCCESS;
3528
3529 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3530 hKey, lpSubKey, ulOptions, samDesired, phkResult);
3531 if (!phkResult)
3532 {
3533 return ERROR_INVALID_PARAMETER;
3534 }
3535
3536 Status = MapDefaultKey(&KeyHandle, hKey);
3537 if (!NT_SUCCESS(Status))
3538 {
3539 return RtlNtStatusToDosError(Status);
3540 }
3541
3542 if (ulOptions & REG_OPTION_OPEN_LINK)
3543 Attributes |= OBJ_OPENLINK;
3544
3545 if (lpSubKey != NULL)
3546 RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
3547 else
3548 RtlInitUnicodeString(&SubKeyString, (LPWSTR)L"");
3549
3550 InitializeObjectAttributes(&ObjectAttributes,
3551 &SubKeyString,
3552 Attributes,
3553 KeyHandle,
3554 NULL);
3555
3556 Status = NtOpenKey((PHANDLE)phkResult,
3557 samDesired,
3558 &ObjectAttributes);
3559 if (!NT_SUCCESS(Status))
3560 {
3561 ErrorCode = RtlNtStatusToDosError(Status);
3562 }
3563
3564 ClosePredefKey(KeyHandle);
3565
3566 return ErrorCode;
3567 }
3568
3569
3570 /************************************************************************
3571 * RegOpenUserClassesRoot
3572 *
3573 * @implemented
3574 */
3575 LONG WINAPI
3576 RegOpenUserClassesRoot(IN HANDLE hToken,
3577 IN DWORD dwOptions,
3578 IN REGSAM samDesired,
3579 OUT PHKEY phkResult)
3580 {
3581 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
3582 const WCHAR UserClassesKeySuffix[] = L"_Classes";
3583 PTOKEN_USER TokenUserData;
3584 ULONG RequiredLength;
3585 UNICODE_STRING UserSidString, UserClassesKeyRoot;
3586 OBJECT_ATTRIBUTES ObjectAttributes;
3587 NTSTATUS Status;
3588
3589 /* check parameters */
3590 if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
3591 {
3592 return ERROR_INVALID_PARAMETER;
3593 }
3594
3595 /*
3596 * Get the user sid from the token
3597 */
3598
3599 ReadTokenSid:
3600 /* determine how much memory we need */
3601 Status = NtQueryInformationToken(hToken,
3602 TokenUser,
3603 NULL,
3604 0,
3605 &RequiredLength);
3606 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
3607 {
3608 /* NOTE - as opposed to all other registry functions windows does indeed
3609 change the last error code in case the caller supplied a invalid
3610 handle for example! */
3611 return RtlNtStatusToDosError(Status);
3612 }
3613 RegInitialize(); /* HACK until delay-loading is implemented */
3614 TokenUserData = RtlAllocateHeap(ProcessHeap,
3615 0,
3616 RequiredLength);
3617 if (TokenUserData == NULL)
3618 {
3619 return ERROR_NOT_ENOUGH_MEMORY;
3620 }
3621
3622 /* attempt to read the information */
3623 Status = NtQueryInformationToken(hToken,
3624 TokenUser,
3625 TokenUserData,
3626 RequiredLength,
3627 &RequiredLength);
3628 if (!NT_SUCCESS(Status))
3629 {
3630 RtlFreeHeap(ProcessHeap,
3631 0,
3632 TokenUserData);
3633 if (Status == STATUS_BUFFER_TOO_SMALL)
3634 {
3635 /* the information appears to have changed?! try again */
3636 goto ReadTokenSid;
3637 }
3638
3639 /* NOTE - as opposed to all other registry functions windows does indeed
3640 change the last error code in case the caller supplied a invalid
3641 handle for example! */
3642 return RtlNtStatusToDosError(Status);
3643 }
3644
3645 /*
3646 * Build the absolute path for the user's registry in the form
3647 * "\Registry\User\<SID>_Classes"
3648 */
3649 Status = RtlConvertSidToUnicodeString(&UserSidString,
3650 TokenUserData->User.Sid,
3651 TRUE);
3652
3653 /* we don't need the user data anymore, free it */
3654 RtlFreeHeap(ProcessHeap,
3655 0,
3656 TokenUserData);
3657
3658 if (!NT_SUCCESS(Status))
3659 {
3660 return RtlNtStatusToDosError(Status);
3661 }
3662
3663 /* allocate enough memory for the entire key string */
3664 UserClassesKeyRoot.Length = 0;
3665 UserClassesKeyRoot.MaximumLength = UserSidString.Length +
3666 sizeof(UserClassesKeyPrefix) +
3667 sizeof(UserClassesKeySuffix);
3668 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
3669 0,
3670 UserClassesKeyRoot.MaximumLength);
3671 if (UserClassesKeyRoot.Buffer == NULL)
3672 {
3673 RtlFreeUnicodeString(&UserSidString);
3674 return RtlNtStatusToDosError(Status);
3675 }
3676
3677 /* build the string */
3678 RtlAppendUnicodeToString(&UserClassesKeyRoot,
3679 UserClassesKeyPrefix);
3680 RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
3681 &UserSidString);
3682 RtlAppendUnicodeToString(&UserClassesKeyRoot,
3683 UserClassesKeySuffix);
3684
3685 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
3686
3687 /*
3688 * Open the key
3689 */
3690 InitializeObjectAttributes(&ObjectAttributes,
3691 &UserClassesKeyRoot,
3692 OBJ_CASE_INSENSITIVE,
3693 NULL,
3694 NULL);
3695
3696 Status = NtOpenKey((PHANDLE)phkResult,
3697 samDesired,
3698 &ObjectAttributes);
3699
3700 RtlFreeUnicodeString(&UserSidString);
3701 RtlFreeUnicodeString(&UserClassesKeyRoot);
3702
3703 if (!NT_SUCCESS(Status))
3704 {
3705 return RtlNtStatusToDosError(Status);
3706 }
3707
3708 return ERROR_SUCCESS;
3709 }
3710
3711
3712 /************************************************************************
3713 * RegQueryInfoKeyA
3714 *
3715 * @implemented
3716 */
3717 LONG WINAPI
3718 RegQueryInfoKeyA(HKEY hKey,
3719 LPSTR lpClass,
3720 LPDWORD lpcbClass,
3721 LPDWORD lpReserved,
3722 LPDWORD lpcSubKeys,
3723 LPDWORD lpcbMaxSubKeyLen,
3724 LPDWORD lpcbMaxClassLen,
3725 LPDWORD lpcValues,
3726 LPDWORD lpcbMaxValueNameLen,
3727 LPDWORD lpcbMaxValueLen,
3728 LPDWORD lpcbSecurityDescriptor,
3729 PFILETIME lpftLastWriteTime)
3730 {
3731 WCHAR ClassName[MAX_PATH];
3732 UNICODE_STRING UnicodeString;
3733 ANSI_STRING AnsiString;
3734 LONG ErrorCode;
3735
3736 RtlInitUnicodeString(&UnicodeString,
3737 NULL);
3738 if (lpClass != NULL)
3739 {
3740 UnicodeString.Buffer = &ClassName[0];
3741 UnicodeString.MaximumLength = sizeof(ClassName);
3742 AnsiString.MaximumLength = *lpcbClass;
3743 }
3744
3745 ErrorCode = RegQueryInfoKeyW(hKey,
3746 UnicodeString.Buffer,
3747 lpcbClass,
3748 lpReserved,
3749 lpcSubKeys,
3750 lpcbMaxSubKeyLen,
3751 lpcbMaxClassLen,
3752 lpcValues,
3753 lpcbMaxValueNameLen,
3754 lpcbMaxValueLen,
3755 lpcbSecurityDescriptor,
3756 lpftLastWriteTime);
3757 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
3758 {
3759 AnsiString.Buffer = lpClass;
3760 AnsiString.Length = 0;
3761 UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
3762 RtlUnicodeStringToAnsiString(&AnsiString,
3763 &UnicodeString,
3764 FALSE);
3765 *lpcbClass = AnsiString.Length;
3766 lpClass[AnsiString.Length] = 0;
3767 }
3768
3769 return ErrorCode;
3770 }
3771
3772
3773 /************************************************************************
3774 * RegQueryInfoKeyW
3775 *
3776 * @implemented
3777 */
3778 LONG WINAPI
3779 RegQueryInfoKeyW(HKEY hKey,
3780 LPWSTR lpClass,
3781 LPDWORD lpcbClass,
3782 LPDWORD lpReserved,
3783 LPDWORD lpcSubKeys,
3784 LPDWORD lpcbMaxSubKeyLen,
3785 LPDWORD lpcbMaxClassLen,
3786 LPDWORD lpcValues,
3787 LPDWORD lpcbMaxValueNameLen,
3788 LPDWORD lpcbMaxValueLen,
3789 LPDWORD lpcbSecurityDescriptor,
3790 PFILETIME lpftLastWriteTime)
3791 {
3792 KEY_FULL_INFORMATION FullInfoBuffer;
3793 PKEY_FULL_INFORMATION FullInfo;
3794 ULONG FullInfoSize;
3795 ULONG ClassLength = 0;
3796 HANDLE KeyHandle;
3797 NTSTATUS Status;
3798 ULONG Length;
3799 LONG ErrorCode = ERROR_SUCCESS;
3800
3801 if ((lpClass) && (!lpcbClass))
3802 {
3803 return ERROR_INVALID_PARAMETER;
3804 }
3805
3806 Status = MapDefaultKey(&KeyHandle,
3807 hKey);
3808 if (!NT_SUCCESS(Status))
3809 {
3810 return RtlNtStatusToDosError(Status);
3811 }
3812
3813 if (lpClass != NULL)
3814 {
3815 if (*lpcbClass > 0)
3816 {
3817 ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3818 }
3819 else
3820 {
3821 ClassLength = 0;
3822 }
3823
3824 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3825 FullInfo = RtlAllocateHeap(ProcessHeap,
3826 0,
3827 FullInfoSize);
3828 if (FullInfo == NULL)
3829 {
3830 ErrorCode = ERROR_OUTOFMEMORY;
3831 goto Cleanup;
3832 }
3833
3834 FullInfo->ClassLength = ClassLength;
3835 }
3836 else
3837 {
3838 FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3839 FullInfo = &FullInfoBuffer;
3840 FullInfo->ClassLength = 0;
3841 }
3842 FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
3843
3844 Status = NtQueryKey(KeyHandle,
3845 KeyFullInformation,
3846 FullInfo,
3847 FullInfoSize,
3848 &Length);
3849 TRACE("NtQueryKey() returned status 0x%X\n", Status);
3850 if (!NT_SUCCESS(Status))
3851 {
3852 if (lpClass != NULL)
3853 {
3854 RtlFreeHeap(ProcessHeap,
3855 0,
3856 FullInfo);
3857 }
3858
3859 ErrorCode = RtlNtStatusToDosError(Status);
3860 goto Cleanup;
3861 }
3862
3863 TRACE("SubKeys %d\n", FullInfo->SubKeys);
3864 if (lpcSubKeys != NULL)
3865 {
3866 *lpcSubKeys = FullInfo->SubKeys;
3867 }
3868
3869 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3870 if (lpcbMaxSubKeyLen != NULL)
3871 {
3872 *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
3873 }
3874
3875 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3876 if (lpcbMaxClassLen != NULL)
3877 {
3878 *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
3879 }
3880
3881 TRACE("Values %lu\n", FullInfo->Values);
3882 if (lpcValues != NULL)
3883 {
3884 *lpcValues = FullInfo->Values;
3885 }
3886
3887 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3888 if (lpcbMaxValueNameLen != NULL)
3889 {
3890 *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
3891 }
3892
3893 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3894 if (lpcbMaxValueLen != NULL)
3895 {
3896 *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
3897 }
3898
3899 #if 0
3900 if (lpcbSecurityDescriptor != NULL)
3901 {
3902 Status = NtQuerySecurityObject(KeyHandle,
3903 OWNER_SECURITY_INFORMATION |
3904 GROUP_SECURITY_INFORMATION |
3905 DACL_SECURITY_INFORMATION,
3906 NULL,
3907 0,
3908 lpcbSecurityDescriptor);
3909 if (!NT_SUCCESS(Status))
3910 {
3911 if (lpClass != NULL)
3912 {
3913 RtlFreeHeap(ProcessHeap,
3914 0,
3915 FullInfo);
3916 }
3917
3918 ErrorCode = RtlNtStatusToDosError(Status);
3919 goto Cleanup;
3920 }
3921 }
3922 #endif
3923
3924 if (lpftLastWriteTime != NULL)
3925 {
3926 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3927 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3928 }
3929
3930 if (lpClass != NULL)
3931 {
3932 if (FullInfo->ClassLength > ClassLength)
3933 {
3934 ErrorCode = ERROR_BUFFER_OVERFLOW;
3935 }
3936 else
3937 {
3938 RtlCopyMemory(lpClass,
3939 FullInfo->Class,
3940 FullInfo->ClassLength);
3941 *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
3942 lpClass[*lpcbClass] = 0;
3943 }
3944
3945 RtlFreeHeap(ProcessHeap,
3946 0,
3947 FullInfo);
3948 }
3949
3950 Cleanup:
3951 ClosePredefKey(KeyHandle);
3952
3953 return ErrorCode;
3954 }
3955
3956
3957 /************************************************************************
3958 * RegQueryMultipleValuesA
3959 *
3960 * @implemented
3961 */
3962 LONG WINAPI
3963 RegQueryMultipleValuesA(HKEY hKey,
3964 PVALENTA val_list,
3965 DWORD num_vals,
3966 LPSTR lpValueBuf,
3967 LPDWORD ldwTotsize)
3968 {
3969 ULONG i;
3970 DWORD maxBytes = *ldwTotsize;
3971 LPSTR bufptr = (LPSTR)lpValueBuf;
3972 LONG ErrorCode;
3973
3974 if (maxBytes >= (1024*1024))
3975 return ERROR_TRANSFER_TOO_LONG;
3976
3977 *ldwTotsize = 0;
3978
3979 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3980 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3981
3982 for (i = 0; i < num_vals; i++)
3983 {
3984 val_list[i].ve_valuelen = 0;
3985 ErrorCode = RegQueryValueExA(hKey,
3986 val_list[i].ve_valuename,
3987 NULL,
3988 NULL,
3989 NULL,
3990 &val_list[i].ve_valuelen);
3991 if (ErrorCode != ERROR_SUCCESS)
3992 {
3993 return ErrorCode;
3994 }
3995
3996 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3997 {
3998 ErrorCode = RegQueryValueExA(hKey,
3999 val_list[i].ve_valuename,
4000 NULL,
4001 &val_list[i].ve_type,
4002 (LPBYTE)bufptr,
4003 &val_list[i].ve_valuelen);
4004 if (ErrorCode != ERROR_SUCCESS)
4005 {
4006 return ErrorCode;
4007 }
4008
4009 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
4010
4011 bufptr += val_list[i].ve_valuelen;
4012 }
4013
4014 *ldwTotsize += val_list[i].ve_valuelen;
4015 }
4016
4017 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
4018 }
4019
4020
4021 /************************************************************************
4022 * RegQueryMultipleValuesW
4023 *
4024 * @implemented
4025 */
4026 LONG WINAPI
4027 RegQueryMultipleValuesW(HKEY hKey,
4028 PVALENTW val_list,
4029 DWORD num_vals,
4030 LPWSTR lpValueBuf,
4031 LPDWORD ldwTotsize)
4032 {
4033 ULONG i;
4034 DWORD maxBytes = *ldwTotsize;
4035 LPSTR bufptr = (LPSTR)lpValueBuf;
4036 LONG ErrorCode;
4037
4038 if (maxBytes >= (1024*1024))
4039 return ERROR_TRANSFER_TOO_LONG;
4040
4041 *ldwTotsize = 0;
4042
4043 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
4044 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
4045
4046 for (i = 0; i < num_vals; i++)
4047 {
4048 val_list[i].ve_valuelen = 0;
4049 ErrorCode = RegQueryValueExW(hKey,
4050 val_list[i].ve_valuename,
4051 NULL,
4052 NULL,
4053 NULL,
4054 &val_list[i].ve_valuelen);
4055 if (ErrorCode != ERROR_SUCCESS)
4056 {
4057 return ErrorCode;
4058 }
4059
4060 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
4061 {
4062 ErrorCode = RegQueryValueExW(hKey,
4063 val_list[i].ve_valuename,
4064 NULL,
4065 &val_list[i].ve_type,
4066 (LPBYTE)bufptr,
4067 &val_list[i].ve_valuelen);
4068 if (ErrorCode != ERROR_SUCCESS)
4069 {
4070 return ErrorCode;
4071 }
4072
4073 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
4074
4075 bufptr += val_list[i].ve_valuelen;
4076 }
4077
4078 *ldwTotsize += val_list[i].ve_valuelen;
4079 }
4080
4081 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
4082 }
4083
4084
4085 /************************************************************************
4086 * RegQueryReflectionKey
4087 *
4088 * @unimplemented
4089 */
4090 LONG WINAPI
4091 RegQueryReflectionKey(IN HKEY hBase,
4092 OUT BOOL* bIsReflectionDisabled)
4093 {
4094 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
4095 hBase, bIsReflectionDisabled);
4096 return ERROR_CALL_NOT_IMPLEMENTED;
4097 }
4098
4099
4100 /******************************************************************************
4101 * RegQueryValueExA [ADVAPI32.@]
4102 *
4103 * Get the type and contents of a specified value under with a key.
4104 *
4105 * PARAMS
4106 * hkey [I] Handle of the key to query
4107 * name [I] Name of value under hkey to query
4108 * reserved [I] Reserved - must be NULL
4109 * type [O] Destination for the value type, or NULL if not required
4110 * data [O] Destination for the values contents, or NULL if not required
4111 * count [I/O] Size of data, updated with the number of bytes returned
4112 *
4113 * RETURNS
4114 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
4115 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4116 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4117 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4118 *
4119 * NOTES
4120 * MSDN states that if data is too small it is partially filled. In reality
4121 * it remains untouched.
4122 */
4123 LONG
4124 WINAPI
4125 RegQueryValueExA(HKEY hkeyorg,
4126 LPCSTR name,
4127 LPDWORD reserved,
4128 LPDWORD type,
4129 LPBYTE data,
4130 LPDWORD count)
4131 {
4132 HANDLE hkey;
4133 NTSTATUS status;
4134 ANSI_STRING nameA;
4135 UNICODE_STRING nameW;
4136 DWORD total_size, datalen = 0;
4137 char buffer[256], *buf_ptr = buffer;
4138 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
4139 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4140
4141 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4142 hkeyorg, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
4143
4144 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4145 status = MapDefaultKey(&hkey, hkeyorg);
4146 if (!NT_SUCCESS(status))
4147 {
4148 return RtlNtStatusToDosError(status);
4149 }
4150
4151 if (count) datalen = *count;
4152 if (!data && count) *count = 0;
4153
4154 RtlInitAnsiString( &nameA, name );
4155 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
4156 {
4157 ClosePredefKey(hkey);
4158 return RtlNtStatusToDosError(status);
4159 }
4160
4161 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
4162 buffer, sizeof(buffer), &total_size );
4163 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
4164
4165 /* we need to fetch the contents for a string type even if not requested,
4166 * because we need to compute the length of the ASCII string. */
4167 if (data || is_string(info->Type))
4168 {
4169 /* retry with a dynamically allocated buffer */
4170 while (status == STATUS_BUFFER_OVERFLOW)
4171 {
4172 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4173 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4174 {
4175 status = STATUS_NO_MEMORY;
4176 goto done;
4177 }
4178 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4179 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
4180 buf_ptr, total_size, &total_size );
4181 }
4182
4183 if (status) goto done;
4184
4185 if (is_string(info->Type))
4186 {
4187 DWORD len;
4188
4189 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
4190 total_size - info_size );
4191 if (data && len)
4192 {
4193 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
4194 else
4195 {
4196 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
4197 total_size - info_size );
4198 /* if the type is REG_SZ and data is not 0-terminated
4199 * and there is enough space in the buffer NT appends a \0 */
4200 if (len < datalen && data[len-1]) data[len] = 0;
4201 }
4202 }
4203 total_size = len + info_size;
4204 }
4205 else if (data)
4206 {
4207 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
4208 else memcpy( data, buf_ptr + info_size, total_size - info_size );
4209 }
4210 }
4211 else status = STATUS_SUCCESS;
4212
4213 if (type) *type = info->Type;
4214 if (count) *count = total_size - info_size;
4215
4216 done:
4217 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4218 RtlFreeUnicodeString( &nameW );
4219 ClosePredefKey(hkey);
4220 return RtlNtStatusToDosError(status);
4221 }
4222
4223
4224 /************************************************************************
4225 * RegQueryValueExW
4226 *
4227 * @implemented
4228 */
4229 LONG
4230 WINAPI
4231 RegQueryValueExW(HKEY hkeyorg,
4232 LPCWSTR name,
4233 LPDWORD reserved,
4234 LPDWORD type,
4235 LPBYTE data,
4236 LPDWORD count)
4237 {
4238 HANDLE hkey;
4239 NTSTATUS status;
4240 UNICODE_STRING name_str;
4241 DWORD total_size;
4242 char buffer[256], *buf_ptr = buffer;
4243 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
4244 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4245
4246 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4247 hkeyorg, debugstr_w(name), reserved, type, data, count,
4248 (count && data) ? *count : 0 );
4249
4250 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4251
4252 status = MapDefaultKey(&hkey, hkeyorg);
4253 if (!NT_SUCCESS(status))
4254 {
4255 return RtlNtStatusToDosError(status);
4256 }
4257
4258 RtlInitUnicodeString( &name_str, name );
4259
4260 if (data) total_size = min( sizeof(buffer), *count + info_size );
4261 else
4262 {
4263 total_size = info_size;
4264 if (count) *count = 0;
4265 }
4266
4267 /* this matches Win9x behaviour - NT sets *type to a random value */
4268 if (type) *type = REG_NONE;
4269
4270 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4271 buffer, total_size, &total_size );
4272 if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) goto done;
4273
4274 if (data)
4275 {
4276 /* retry with a dynamically allocated buffer */
4277 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
4278 {
4279 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4280 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4281 {
4282 ClosePredefKey(hkey);
4283 return ERROR_NOT_ENOUGH_MEMORY;
4284 }
4285 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4286 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4287 buf_ptr, total_size, &total_size );
4288 }
4289
4290 if (NT_SUCCESS(status))
4291 {
4292 memcpy( data, buf_ptr + info_size, total_size - info_size );
4293 /* if the type is REG_SZ and data is not 0-terminated
4294 * and there is enough space in the buffer NT appends a \0 */
4295 if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR))
4296 {
4297 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
4298 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
4299 }
4300 }
4301 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
4302 }
4303 else status = STATUS_SUCCESS;
4304
4305 if (type) *type = info->Type;
4306 if (count) *count = total_size - info_size;
4307
4308 done:
4309 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4310 ClosePredefKey(hkey);
4311 return RtlNtStatusToDosError(status);
4312 }
4313
4314
4315 /************************************************************************
4316 * RegQueryValueA
4317 *
4318 * @implemented
4319 */
4320 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
4321 {
4322 DWORD ret;
4323 HKEY subkey = hkey;
4324
4325 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
4326
4327 if (name && name[0])
4328 {
4329 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
4330 }
4331 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4332 if (subkey != hkey) RegCloseKey( subkey );
4333 if (ret == ERROR_FILE_NOT_FOUND)
4334 {
4335 /* return empty string if default value not found */
4336 if (data) *data = 0;
4337 if (count) *count = 1;
4338 ret = ERROR_SUCCESS;
4339 }
4340 return ret;
4341 }
4342
4343
4344 /************************************************************************
4345 * RegQueryValueW
4346 *
4347 * @implemented
4348 */
4349 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
4350 {
4351 DWORD ret;
4352 HKEY subkey = hkey;
4353
4354 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
4355 if (hkey == NULL)
4356 {
4357 return ERROR_INVALID_HANDLE;
4358 }
4359 if (name && name[0])
4360 {
4361 ret = RegOpenKeyW( hkey, name, &subkey);
4362 if (ret != ERROR_SUCCESS)
4363 {
4364 return ret;
4365 }
4366 }
4367
4368 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4369
4370 if (subkey != hkey)
4371 {
4372 RegCloseKey( subkey );
4373 }
4374
4375 if (ret == ERROR_FILE_NOT_FOUND)
4376 {
4377 /* return empty string if default value not found */
4378 if (data)
4379 *data = 0;
4380 if (count)
4381 *count = sizeof(WCHAR);
4382 ret = ERROR_SUCCESS;
4383 }
4384 return ret;
4385 }
4386
4387
4388 /************************************************************************
4389 * RegReplaceKeyA
4390 *
4391 * @implemented
4392 */
4393 LONG WINAPI
4394 RegReplaceKeyA(HKEY hKey,
4395 LPCSTR lpSubKey,
4396 LPCSTR lpNewFile,
4397 LPCSTR lpOldFile)
4398 {
4399 UNICODE_STRING SubKey;
4400 UNICODE_STRING NewFile;
4401 UNICODE_STRING OldFile;
4402 LONG ErrorCode;
4403
4404 RtlCreateUnicodeStringFromAsciiz(&SubKey,
4405 (PCSZ)lpSubKey);
4406 RtlCreateUnicodeStringFromAsciiz(&OldFile,
4407 (PCSZ)lpOldFile);
4408 RtlCreateUnicodeStringFromAsciiz(&NewFile,
4409 (PCSZ)lpNewFile);
4410
4411 ErrorCode = RegReplaceKeyW(hKey,
4412 SubKey.Buffer,
4413 NewFile.Buffer,
4414 OldFile.Buffer);
4415
4416 RtlFreeUnicodeString(&OldFile);
4417 RtlFreeUnicodeString(&NewFile);
4418 RtlFreeUnicodeString(&SubKey);
4419
4420 return ErrorCode;
4421 }
4422
4423
4424 /************************************************************************
4425 * RegReplaceKeyW
4426 *
4427 * @unimplemented
4428 */
4429 LONG WINAPI
4430 RegReplaceKeyW(HKEY hKey,
4431 LPCWSTR lpSubKey,
4432 LPCWSTR lpNewFile,
4433 LPCWSTR lpOldFile)
4434 {
4435 OBJECT_ATTRIBUTES KeyObjectAttributes;
4436 OBJECT_ATTRIBUTES NewObjectAttributes;
4437 OBJECT_ATTRIBUTES OldObjectAttributes;
4438 UNICODE_STRING SubKeyName;
4439 UNICODE_STRING NewFileName;
4440 UNICODE_STRING OldFileName;
4441 BOOLEAN CloseRealKey;
4442 HANDLE RealKeyHandle;
4443 HANDLE KeyHandle;
4444 NTSTATUS Status;
4445 LONG ErrorCode = ERROR_SUCCESS;
4446
4447 if (hKey == HKEY_PERFORMANCE_DATA)
4448 {
4449 return ERROR_INVALID_HANDLE;
4450 }
4451
4452 Status = MapDefaultKey(&KeyHandle,
4453 hKey);
4454 if (!NT_SUCCESS(Status))
4455 {
4456 return RtlNtStatusToDosError(Status);
4457 }
4458
4459 /* Open the real key */
4460 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
4461 {
4462 RtlInitUnicodeString(&SubKeyName,
4463 (PWSTR)lpSubKey);
4464 InitializeObjectAttributes(&KeyObjectAttributes,
4465 &SubKeyName,
4466 OBJ_CASE_INSENSITIVE,
4467 KeyHandle,
4468 NULL);
4469 Status = NtOpenKey(&RealKeyHandle,
4470 MAXIMUM_ALLOWED,
4471 &KeyObjectAttributes);
4472 if (!NT_SUCCESS(Status))
4473 {
4474 ErrorCode = RtlNtStatusToDosError(Status);
4475 goto Cleanup;
4476 }
4477
4478 CloseRealKey = TRUE;
4479 }
4480 else
4481 {
4482 RealKeyHandle = KeyHandle;
4483 CloseRealKey = FALSE;
4484 }
4485
4486 /* Convert new file name */
4487 if (!RtlDosPathNameToNtPathName_U(lpNewFile,
4488 &NewFileName,
4489 NULL,
4490 NULL))
4491 {
4492 if (CloseRealKey)
4493 {
4494 NtClose(RealKeyHandle);
4495 }
4496
4497 ErrorCode = ERROR_INVALID_PARAMETER;
4498 goto Cleanup;
4499 }
4500
4501 InitializeObjectAttributes(&NewObjectAttributes,
4502 &NewFileName,
4503 OBJ_CASE_INSENSITIVE,
4504 NULL,
4505 NULL);
4506
4507 /* Convert old file name */
4508 if (!RtlDosPathNameToNtPathName_U(lpOldFile,
4509 &OldFileName,
4510 NULL,
4511 NULL))
4512 {
4513 RtlFreeHeap(RtlGetProcessHeap (),
4514 0,
4515 NewFileName.Buffer);
4516 if (CloseRealKey)
4517 {
4518 NtClose(RealKeyHandle);
4519 }
4520
4521 ErrorCode = ERROR_INVALID_PARAMETER;
4522 goto Cleanup;
4523 }
4524
4525 InitializeObjectAttributes(&OldObjectAttributes,
4526 &OldFileName,
4527 OBJ_CASE_INSENSITIVE,
4528 NULL,
4529 NULL);
4530
4531 Status = NtReplaceKey(&NewObjectAttributes,
4532 RealKeyHandle,
4533 &OldObjectAttributes);
4534
4535 RtlFreeHeap(RtlGetProcessHeap(),
4536 0,
4537 OldFileName.Buffer);
4538 RtlFreeHeap(RtlGetProcessHeap(),
4539 0,
4540 NewFileName.Buffer);
4541
4542 if (CloseRealKey)
4543 {
4544 NtClose(RealKeyHandle);
4545 }
4546
4547 if (!NT_SUCCESS(Status))
4548 {
4549 return RtlNtStatusToDosError(Status);
4550 }
4551
4552 Cleanup:
4553 ClosePredefKey(KeyHandle);
4554
4555 return ErrorCode;
4556 }
4557
4558
4559 /************************************************************************
4560 * RegRestoreKeyA
4561 *
4562 * @implemented
4563 */
4564 LONG WINAPI
4565 RegRestoreKeyA(HKEY hKey,
4566 LPCSTR lpFile,
4567 DWORD dwFlags)
4568 {
4569 UNICODE_STRING FileName;
4570 LONG ErrorCode;
4571
4572 RtlCreateUnicodeStringFromAsciiz(&FileName,
4573 (PCSZ)lpFile);
4574
4575 ErrorCode = RegRestoreKeyW(hKey,
4576 FileName.Buffer,
4577 dwFlags);
4578
4579 RtlFreeUnicodeString(&FileName);
4580
4581 return ErrorCode;
4582 }
4583
4584
4585 /************************************************************************
4586 * RegRestoreKeyW
4587 *
4588 * @implemented
4589 */
4590 LONG WINAPI
4591 RegRestoreKeyW(HKEY hKey,
4592 LPCWSTR lpFile,
4593 DWORD dwFlags)
4594 {
4595 OBJECT_ATTRIBUTES ObjectAttributes;
4596 IO_STATUS_BLOCK IoStatusBlock;
4597 UNICODE_STRING FileName;
4598 HANDLE FileHandle;
4599 HANDLE KeyHandle;
4600 NTSTATUS Status;
4601
4602 if (hKey == HKEY_PERFORMANCE_DATA)
4603 {
4604 return ERROR_INVALID_HANDLE;
4605 }
4606
4607 Status = MapDefaultKey(&KeyHandle,
4608 hKey);
4609 if (!NT_SUCCESS(Status))
4610 {
4611 return RtlNtStatusToDosError(Status);
4612 }
4613
4614 if (!RtlDosPathNameToNtPathName_U(lpFile,
4615 &FileName,
4616 NULL,
4617 NULL))
4618 {
4619 Status = STATUS_INVALID_PARAMETER;
4620 goto Cleanup;
4621 }
4622
4623 InitializeObjectAttributes(&ObjectAttributes,
4624 &FileName,
4625 OBJ_CASE_INSENSITIVE,
4626 NULL,
4627 NULL);
4628
4629 Status = NtOpenFile(&FileHandle,
4630 FILE_GENERIC_READ,
4631 &ObjectAttributes,
4632 &IoStatusBlock,
4633 FILE_SHARE_READ,
4634 FILE_SYNCHRONOUS_IO_NONALERT);
4635 RtlFreeHeap(RtlGetProcessHeap(),
4636 0,
4637 FileName.Buffer);
4638 if (!NT_SUCCESS(Status))
4639 {
4640 goto Cleanup;
4641 }
4642
4643 Status = NtRestoreKey(KeyHandle,
4644 FileHandle,
4645 (ULONG)dwFlags);
4646 NtClose (FileHandle);
4647
4648 Cleanup:
4649 ClosePredefKey(KeyHandle);
4650
4651 if (!NT_SUCCESS(Status))
4652 {
4653 return RtlNtStatusToDosError(Status);
4654 }
4655
4656 return ERROR_SUCCESS;
4657 }
4658
4659
4660 /************************************************************************
4661 * RegSaveKeyA
4662 *
4663 * @implemented
4664 */
4665 LONG WINAPI
4666 RegSaveKeyA(HKEY hKey,
4667 LPCSTR lpFile,
4668 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4669 {
4670 UNICODE_STRING FileName;
4671 LONG ErrorCode;
4672
4673 RtlCreateUnicodeStringFromAsciiz(&FileName,
4674 (LPSTR)lpFile);
4675 ErrorCode = RegSaveKeyW(hKey,
4676 FileName.Buffer,
4677 lpSecurityAttributes);
4678 RtlFreeUnicodeString(&FileName);
4679
4680 return ErrorCode;
4681 }
4682
4683
4684 /************************************************************************
4685 * RegSaveKeyW
4686 *
4687 * @implemented
4688 */
4689 LONG WINAPI
4690 RegSaveKeyW(HKEY hKey,
4691 LPCWSTR lpFile,
4692 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4693 {
4694 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
4695 OBJECT_ATTRIBUTES ObjectAttributes;
4696 UNICODE_STRING FileName;
4697 IO_STATUS_BLOCK IoStatusBlock;
4698 HANDLE FileHandle;
4699 HANDLE KeyHandle;
4700 NTSTATUS Status;
4701
4702 Status = MapDefaultKey(&KeyHandle,
4703 hKey);
4704 if (!NT_SUCCESS(Status))
4705 {
4706 return RtlNtStatusToDosError(Status);
4707 }
4708
4709 if (!RtlDosPathNameToNtPathName_U(lpFile,
4710 &FileName,
4711 NULL,
4712 NULL))
4713 {
4714 Status = STATUS_INVALID_PARAMETER;
4715 goto Cleanup;
4716 }
4717
4718 if (lpSecurityAttributes != NULL)
4719 {
4720 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4721 }
4722
4723 InitializeObjectAttributes(&ObjectAttributes,
4724 &FileName,
4725 OBJ_CASE_INSENSITIVE,
4726 NULL,
4727 SecurityDescriptor);
4728 Status = NtCreateFile(&FileHandle,
4729 GENERIC_WRITE | SYNCHRONIZE,
4730 &ObjectAttributes,
4731 &IoStatusBlock,
4732 NULL,
4733 FILE_ATTRIBUTE_NORMAL,
4734 FILE_SHARE_READ,
4735 FILE_CREATE,
4736 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
4737 NULL,
4738 0);
4739 RtlFreeHeap(RtlGetProcessHeap(),
4740 0,
4741 FileName.Buffer);
4742 if (!NT_SUCCESS(Status))
4743 {
4744 goto Cleanup;
4745 }
4746
4747 Status = NtSaveKey(KeyHandle,
4748 FileHandle);
4749 NtClose (FileHandle);
4750
4751 Cleanup:
4752 ClosePredefKey(KeyHandle);
4753
4754 if (!NT_SUCCESS(Status))
4755 {
4756 return RtlNtStatusToDosError(Status);
4757 }
4758
4759 return ERROR_SUCCESS;
4760 }
4761
4762
4763 /************************************************************************
4764 * RegSaveKeyExA
4765 *
4766 * @implemented
4767 */
4768 LONG
4769 WINAPI
4770 RegSaveKeyExA(HKEY hKey,
4771 LPCSTR lpFile,
4772 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4773 DWORD Flags)
4774 {
4775 UNICODE_STRING FileName;
4776 LONG ErrorCode;
4777
4778 RtlCreateUnicodeStringFromAsciiz(&FileName,
4779 (LPSTR)lpFile);
4780 ErrorCode = RegSaveKeyExW(hKey,
4781 FileName.Buffer,
4782 lpSecurityAttributes,
4783 Flags);
4784 RtlFreeUnicodeString(&FileName);
4785
4786 return ErrorCode;
4787 }
4788
4789
4790 /************************************************************************
4791 * RegSaveKeyExW
4792 *
4793 * @unimplemented
4794 */
4795 LONG
4796 WINAPI
4797 RegSaveKeyExW(HKEY hKey,
4798 LPCWSTR lpFile,
4799 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4800 DWORD Flags)
4801 {
4802 switch (Flags)
4803 {
4804 case REG_STANDARD_FORMAT:
4805 case REG_LATEST_FORMAT:
4806 case REG_NO_COMPRESSION:
4807 break;
4808 default:
4809 return ERROR_INVALID_PARAMETER;
4810 }
4811
4812 FIXME("RegSaveKeyExW(): Flags ignored!\n");
4813
4814 return RegSaveKeyW(hKey,
4815 lpFile,
4816 lpSecurityAttributes);
4817 }
4818
4819
4820 /************************************************************************
4821 * RegSetKeySecurity
4822 *
4823 * @implemented
4824 */
4825 LONG WINAPI
4826 RegSetKeySecurity(HKEY hKey,
4827 SECURITY_INFORMATION SecurityInformation,
4828 PSECURITY_DESCRIPTOR pSecurityDescriptor)
4829 {
4830 HANDLE KeyHandle;
4831 NTSTATUS Status;
4832
4833 if (hKey == HKEY_PERFORMANCE_DATA)
4834 {
4835 return ERROR_INVALID_HANDLE;
4836 }
4837
4838 Status = MapDefaultKey(&KeyHandle,
4839 hKey);
4840 if (!NT_SUCCESS(Status))
4841 {
4842 return RtlNtStatusToDosError(Status);
4843 }
4844
4845 Status = NtSetSecurityObject(KeyHandle,
4846 SecurityInformation,
4847 pSecurityDescriptor);
4848
4849 ClosePredefKey(KeyHandle);
4850
4851 if (!NT_SUCCESS(Status))
4852 {
4853 return RtlNtStatusToDosError(Status);
4854 }
4855
4856 return ERROR_SUCCESS;
4857 }
4858
4859
4860 /************************************************************************
4861 * RegSetValueExA
4862 *
4863 * @implemented
4864 */
4865 LONG WINAPI
4866 RegSetValueExA(HKEY hKey,
4867 LPCSTR lpValueName,
4868 DWORD Reserved,
4869 DWORD dwType,
4870 CONST BYTE* lpData,
4871 DWORD cbData)
4872 {
4873 UNICODE_STRING ValueName;
4874 LPWSTR pValueName;
4875 ANSI_STRING AnsiString;
4876 UNICODE_STRING Data;
4877 LONG ErrorCode;
4878 LPBYTE pData;
4879 DWORD DataSize;
4880 NTSTATUS Status;
4881
4882 /* Convert SubKey name to Unicode */
4883 if (lpValueName != NULL && lpValueName[0] != '\0')
4884 {
4885 BOOL bConverted;
4886 bConverted = RtlCreateUnicodeStringFromAsciiz(&ValueName,
4887 (PSTR)lpValueName);
4888 if(!bConverted)
4889 return ERROR_NOT_ENOUGH_MEMORY;
4890 }
4891 else
4892 {
4893 ValueName.Buffer = NULL;
4894 }
4895
4896 pValueName = (LPWSTR)ValueName.Buffer;
4897
4898
4899 if (is_string(dwType) && (cbData != 0))
4900 {
4901 /* Convert ANSI string Data to Unicode */
4902 /* If last character NOT zero then increment length */
4903 LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0);
4904 AnsiString.Buffer = (PSTR)lpData;
4905 AnsiString.Length = cbData + bNoNulledStr;
4906 AnsiString.MaximumLength = cbData + bNoNulledStr;
4907 Status = RtlAnsiStringToUnicodeString(&Data,
4908 &AnsiString,
4909 TRUE);
4910
4911 if (!NT_SUCCESS(Status))
4912 {
4913 if (pValueName != NULL)
4914 RtlFreeUnicodeString(&ValueName);
4915
4916 return RtlNtStatusToDosError(Status);
4917 }
4918 pData = (LPBYTE)Data.Buffer;
4919 DataSize = cbData * sizeof(WCHAR);
4920 }
4921 else
4922 {
4923 Data.Buffer = NULL;
4924 pData = (LPBYTE)lpData;
4925 DataSize = cbData;
4926 }
4927
4928 ErrorCode = RegSetValueExW(hKey,
4929 pValueName,
4930 Reserved,
4931 dwType,
4932 pData,
4933 DataSize);
4934
4935 if (pValueName != NULL)
4936 RtlFreeUnicodeString(&ValueName);
4937
4938 if (Data.Buffer != NULL)
4939 RtlFreeUnicodeString(&Data);
4940
4941 return ErrorCode;
4942 }
4943
4944
4945 /************************************************************************
4946 * RegSetValueExW
4947 *
4948 * @implemented
4949 */
4950 LONG WINAPI
4951 RegSetValueExW(HKEY hKey,
4952 LPCWSTR lpValueName,
4953 DWORD Reserved,
4954 DWORD dwType,
4955 CONST BYTE* lpData,
4956 DWORD cbData)
4957 {
4958 UNICODE_STRING ValueName;
4959 HANDLE KeyHandle;
4960 NTSTATUS Status;
4961
4962 if (is_string(dwType) && (cbData != 0))
4963 {
4964 PWSTR pwsData = (PWSTR)lpData;
4965
4966 _SEH2_TRY
4967 {
4968 if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
4969 (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
4970 {
4971 /* Increment length if last character is not zero and next is zero */
4972 cbData += sizeof(WCHAR);
4973 }
4974 }
4975 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4976 {
4977 _SEH2_YIELD(return ERROR_NOACCESS);
4978 }
4979 _SEH2_END;
4980 }
4981
4982 Status = MapDefaultKey(&KeyHandle,
4983 hKey);
4984 if (!NT_SUCCESS(Status))
4985 {
4986 return RtlNtStatusToDosError(Status);
4987 }
4988
4989 RtlInitUnicodeString(&ValueName, lpValueName);
4990
4991 Status = NtSetValueKey(KeyHandle,
4992 &ValueName,
4993 0,
4994 dwType,
4995 (PVOID)lpData,
4996 (ULONG)cbData);
4997
4998 ClosePredefKey(KeyHandle);
4999
5000 if (!NT_SUCCESS(Status))
5001 {
5002 return RtlNtStatusToDosError(Status);
5003 }
5004
5005 return ERROR_SUCCESS;
5006 }
5007
5008
5009 /************************************************************************
5010 * RegSetValueA
5011 *
5012 * @implemented
5013 */
5014 LONG WINAPI
5015 RegSetValueA(HKEY hKeyOriginal,
5016 LPCSTR lpSubKey,
5017 DWORD dwType,
5018 LPCSTR lpData,
5019 DWORD cbData)
5020 {
5021 HKEY subkey;
5022 HANDLE hKey;
5023 DWORD ret;
5024 NTSTATUS Status;
5025
5026 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData );
5027
5028 if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER;
5029
5030 Status = MapDefaultKey(&hKey, hKeyOriginal);
5031 if (!NT_SUCCESS(Status))
5032 {
5033 return RtlNtStatusToDosError (Status);
5034 }
5035 subkey = hKey;
5036
5037 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
5038 {
5039 ret = RegCreateKeyA(hKey, lpSubKey, &subkey);
5040 if (ret != ERROR_SUCCESS)
5041 goto Cleanup;
5042 }
5043
5044 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 );
5045 if (subkey != hKey)
5046 RegCloseKey(subkey);
5047
5048 Cleanup:
5049 ClosePredefKey(hKey);
5050
5051 return ret;
5052 }
5053
5054
5055 /************************************************************************
5056 * RegSetValueW
5057 *
5058 * @implemented
5059 */
5060 LONG WINAPI
5061 RegSetValueW(HKEY hKeyOriginal,
5062 LPCWSTR lpSubKey,
5063 DWORD dwType,
5064 LPCWSTR lpData,
5065 DWORD cbData)
5066 {
5067 HKEY subkey;
5068 HANDLE hKey;
5069 DWORD ret;
5070 NTSTATUS Status;
5071
5072 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData );
5073
5074 if (dwType != REG_SZ || !lpData)
5075 return ERROR_INVALID_PARAMETER;
5076
5077 Status = MapDefaultKey(&hKey,
5078 hKeyOriginal);
5079 if (!NT_SUCCESS(Status))
5080 {
5081 return RtlNtStatusToDosError(Status);
5082 }
5083 subkey = hKey;
5084
5085 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
5086 {
5087 ret = RegCreateKeyW(hKey, lpSubKey, &subkey);
5088 if (ret != ERROR_SUCCESS)
5089 goto Cleanup;
5090 }
5091
5092 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData,
5093 (wcslen( lpData ) + 1) * sizeof(WCHAR) );
5094 if (subkey != hKey)
5095 RegCloseKey(subkey);
5096
5097 Cleanup:
5098 ClosePredefKey(hKey);
5099
5100 return ret;
5101 }
5102
5103
5104 /************************************************************************
5105 * RegUnLoadKeyA
5106 *
5107 * @implemented
5108 */
5109 LONG WINAPI
5110 RegUnLoadKeyA(HKEY hKey,
5111 LPCSTR lpSubKey)
5112 {
5113 UNICODE_STRING KeyName;
5114 DWORD ErrorCode;
5115
5116 RtlCreateUnicodeStringFromAsciiz(&KeyName,
5117 (LPSTR)lpSubKey);
5118
5119 ErrorCode = RegUnLoadKeyW(hKey,
5120 KeyName.Buffer);
5121
5122 RtlFreeUnicodeString (&KeyName);
5123
5124 return ErrorCode;
5125 }
5126
5127
5128 /************************************************************************
5129 * RegUnLoadKeyW
5130 *
5131 * @implemented
5132 */
5133 LONG WINAPI
5134 RegUnLoadKeyW(HKEY hKey,
5135 LPCWSTR lpSubKey)
5136 {
5137 OBJECT_ATTRIBUTES ObjectAttributes;
5138 UNICODE_STRING KeyName;
5139 HANDLE KeyHandle;
5140 NTSTATUS Status;
5141
5142 if (hKey == HKEY_PERFORMANCE_DATA)
5143 {
5144 return ERROR_INVALID_HANDLE;
5145 }
5146
5147 Status = MapDefaultKey(&KeyHandle, hKey);
5148 if (!NT_SUCCESS(Status))
5149 {
5150 return RtlNtStatusToDosError(Status);
5151 }
5152
5153 RtlInitUnicodeString(&KeyName,
5154 (LPWSTR)lpSubKey);
5155
5156 InitializeObjectAttributes(&ObjectAttributes,
5157 &KeyName,
5158 OBJ_CASE_INSENSITIVE,
5159 KeyHandle,
5160 NULL);
5161
5162 Status = NtUnloadKey(&ObjectAttributes);
5163
5164 ClosePredefKey(KeyHandle);
5165
5166 if (!NT_SUCCESS(Status))
5167 {
5168 return RtlNtStatusToDosError(Status);
5169 }
5170
5171 return ERROR_SUCCESS;
5172 }
5173
5174
5175 /******************************************************************************
5176 * load_string [Internal]
5177 *
5178 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5179 * avoid importing user32, which is higher level than advapi32. Helper for
5180 * RegLoadMUIString.
5181 */
5182 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
5183 {
5184 HGLOBAL hMemory;
5185 HRSRC hResource;
5186 WCHAR *pString;
5187 int idxString;
5188
5189 /* Negative values have to be inverted. */
5190 if (HIWORD(resId) == 0xffff)
5191 resId = (UINT)(-((INT)resId));
5192
5193 /* Load the resource into memory and get a pointer to it. */
5194 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
5195 if (!hResource) return 0;
5196 hMemory = LoadResource(hModule, hResource);
5197 if (!hMemory) return 0;
5198 pString = LockResource(hMemory);
5199
5200 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5201 idxString = resId & 0xf;
5202 while (idxString--) pString += *pString + 1;
5203
5204 /* If no buffer is given, return length of the string. */
5205 if (!pwszBuffer) return *pString;
5206
5207 /* Else copy over the string, respecting the buffer size. */
5208 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
5209 if (cMaxChars >= 0)
5210 {
5211 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
5212 pwszBuffer[cMaxChars] = L'\0';
5213 }
5214
5215 return cMaxChars;
5216 }
5217
5218
5219 /************************************************************************
5220 * RegLoadMUIStringW
5221 *
5222 * @implemented
5223 */
5224 LONG WINAPI
5225 RegLoadMUIStringW(IN HKEY hKey,
5226 IN LPCWSTR pszValue OPTIONAL,
5227 OUT LPWSTR pszOutBuf,
5228 IN DWORD cbOutBuf,
5229 OUT LPDWORD pcbData OPTIONAL,
5230 IN DWORD Flags,
5231 IN LPCWSTR pszDirectory OPTIONAL)
5232 {
5233 DWORD dwValueType, cbData;
5234 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
5235 LONG result;
5236
5237 /* Parameter sanity checks. */
5238 if (!hKey || !pszOutBuf)
5239 return ERROR_INVALID_PARAMETER;
5240
5241 if (pszDirectory && *pszDirectory)
5242 {
5243 FIXME("BaseDir parameter not yet supported!\n");
5244 return ERROR_INVALID_PARAMETER;
5245 }
5246
5247 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5248 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
5249 if (result != ERROR_SUCCESS) goto cleanup;
5250 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
5251 {
5252 result = ERROR_FILE_NOT_FOUND;
5253 goto cleanup;
5254 }
5255 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5256 if (!pwszTempBuffer)
5257 {
5258 result = ERROR_NOT_ENOUGH_MEMORY;
5259 goto cleanup;
5260 }
5261 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
5262 if (result != ERROR_SUCCESS) goto cleanup;
5263
5264 /* Expand environment variables, if appropriate, or copy the original string over. */
5265 if (dwValueType == REG_EXPAND_SZ)
5266 {
5267 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
5268 if (!cbData) goto cleanup;
5269 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5270 if (!pwszExpandedBuffer)
5271 {
5272 result = ERROR_NOT_ENOUGH_MEMORY;
5273 goto cleanup;
5274 }
5275 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
5276 }
5277 else
5278 {
5279 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5280 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
5281 }
5282
5283 /* If the value references a resource based string, parse the value and load the string.
5284 * Else just copy over the original value. */
5285 result = ERROR_SUCCESS;
5286 if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
5287 {
5288 lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
5289 }
5290 else
5291 {
5292 WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
5293 UINT uiStringId;
5294 HMODULE hModule;
5295
5296 /* Format of the expanded value is 'path_to_dll,-resId' */
5297 if (!pComma || pComma[1] != L'-')
5298 {
5299 result = ERROR_BADKEY;
5300 goto cleanup;
5301 }
5302
5303 uiStringId = _wtoi(pComma+2);
5304 *pComma = L'\0';
5305
5306 hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
5307 if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
5308 result = ERROR_BADKEY;
5309 FreeLibrary(hModule);
5310 }
5311
5312 cleanup:
5313 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
5314 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
5315 return result;
5316 }
5317
5318
5319 /************************************************************************
5320 * RegLoadMUIStringA
5321 *
5322 * @implemented
5323 */
5324 LONG WINAPI
5325 RegLoadMUIStringA(IN HKEY hKey,
5326 IN LPCSTR pszValue OPTIONAL,
5327 OUT LPSTR pszOutBuf,
5328 IN DWORD cbOutBuf,
5329 OUT LPDWORD pcbData OPTIONAL,
5330 IN DWORD Flags,
5331 IN LPCSTR pszDirectory OPTIONAL)
5332 {
5333 UNICODE_STRING valueW, baseDirW;
5334 WCHAR *pwszBuffer;
5335 DWORD cbData = cbOutBuf * sizeof(WCHAR);
5336 LONG result;
5337
5338 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
5339 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
5340 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
5341 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
5342 {
5343 result = ERROR_NOT_ENOUGH_MEMORY;
5344 goto cleanup;
5345 }
5346
5347 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
5348 baseDirW.Buffer);
5349
5350 if (result == ERROR_SUCCESS)
5351 {
5352 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
5353 if (pcbData)
5354 *pcbData = cbData;
5355 }
5356
5357 cleanup:
5358 HeapFree(GetProcessHeap(), 0, pwszBuffer);
5359 RtlFreeUnicodeString(&baseDirW);
5360 RtlFreeUnicodeString(&valueW);
5361
5362 return result;
5363 }
5364
5365 /* EOF */