[SHELL-EXPERIMENTS]
[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 Status = NtQuerySecurityObject(KeyHandle,
3172 SecurityInformation,
3173 pSecurityDescriptor,
3174 *lpcbSecurityDescriptor,
3175 lpcbSecurityDescriptor);
3176
3177 ClosePredefKey(KeyHandle);
3178
3179 if (!NT_SUCCESS(Status))
3180 {
3181 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
3182 return RtlNtStatusToDosError(Status);
3183 }
3184
3185 return ERROR_SUCCESS;
3186 }
3187
3188
3189 /************************************************************************
3190 * RegLoadKeyA
3191 *
3192 * @implemented
3193 */
3194 LONG WINAPI
3195 RegLoadKeyA(HKEY hKey,
3196 LPCSTR lpSubKey,
3197 LPCSTR lpFile)
3198 {
3199 UNICODE_STRING FileName;
3200 UNICODE_STRING KeyName;
3201 LONG ErrorCode;
3202
3203 RtlCreateUnicodeStringFromAsciiz(&KeyName,
3204 (LPSTR)lpSubKey);
3205 RtlCreateUnicodeStringFromAsciiz(&FileName,
3206 (LPSTR)lpFile);
3207
3208 ErrorCode = RegLoadKeyW(hKey,
3209 KeyName.Buffer,
3210 FileName.Buffer);
3211
3212 RtlFreeUnicodeString(&FileName);
3213 RtlFreeUnicodeString(&KeyName);
3214
3215 return ErrorCode;
3216 }
3217
3218
3219 /************************************************************************
3220 * RegLoadKeyW
3221 *
3222 * @implemented
3223 */
3224 LONG WINAPI
3225 RegLoadKeyW(HKEY hKey,
3226 LPCWSTR lpSubKey,
3227 LPCWSTR lpFile)
3228 {
3229 OBJECT_ATTRIBUTES FileObjectAttributes;
3230 OBJECT_ATTRIBUTES KeyObjectAttributes;
3231 UNICODE_STRING FileName;
3232 UNICODE_STRING KeyName;
3233 HANDLE KeyHandle;
3234 NTSTATUS Status;
3235 LONG ErrorCode = ERROR_SUCCESS;
3236
3237 if (hKey == HKEY_PERFORMANCE_DATA)
3238 {
3239 return ERROR_INVALID_HANDLE;
3240 }
3241
3242 Status = MapDefaultKey(&KeyHandle,
3243 hKey);
3244 if (!NT_SUCCESS(Status))
3245 {
3246 return RtlNtStatusToDosError(Status);
3247 }
3248
3249 if (!RtlDosPathNameToNtPathName_U(lpFile,
3250 &FileName,
3251 NULL,
3252 NULL))
3253 {
3254 ErrorCode = ERROR_BAD_PATHNAME;
3255 goto Cleanup;
3256 }
3257
3258 InitializeObjectAttributes(&FileObjectAttributes,
3259 &FileName,
3260 OBJ_CASE_INSENSITIVE,
3261 NULL,
3262 NULL);
3263
3264 RtlInitUnicodeString(&KeyName,
3265 (LPWSTR)lpSubKey);
3266
3267 InitializeObjectAttributes(&KeyObjectAttributes,
3268 &KeyName,
3269 OBJ_CASE_INSENSITIVE,
3270 KeyHandle,
3271 NULL);
3272
3273 Status = NtLoadKey(&KeyObjectAttributes,
3274 &FileObjectAttributes);
3275
3276 RtlFreeHeap(RtlGetProcessHeap(),
3277 0,
3278 FileName.Buffer);
3279
3280 if (!NT_SUCCESS(Status))
3281 {
3282 ErrorCode = RtlNtStatusToDosError(Status);
3283 goto Cleanup;
3284 }
3285
3286 Cleanup:
3287 ClosePredefKey(KeyHandle);
3288
3289 return ErrorCode;
3290 }
3291
3292
3293 /************************************************************************
3294 * RegNotifyChangeKeyValue
3295 *
3296 * @unimplemented
3297 */
3298 LONG WINAPI
3299 RegNotifyChangeKeyValue(HKEY hKey,
3300 BOOL bWatchSubtree,
3301 DWORD dwNotifyFilter,
3302 HANDLE hEvent,
3303 BOOL fAsynchronous)
3304 {
3305 IO_STATUS_BLOCK IoStatusBlock;
3306 HANDLE KeyHandle;
3307 NTSTATUS Status;
3308 LONG ErrorCode = ERROR_SUCCESS;
3309
3310 if (hKey == HKEY_PERFORMANCE_DATA)
3311 {
3312 return ERROR_INVALID_HANDLE;
3313 }
3314
3315 if (fAsynchronous == TRUE && hEvent == NULL)
3316 {
3317 return ERROR_INVALID_PARAMETER;
3318 }
3319
3320 Status = MapDefaultKey(&KeyHandle,
3321 hKey);
3322 if (!NT_SUCCESS(Status))
3323 {
3324 return RtlNtStatusToDosError(Status);
3325 }
3326
3327 /* FIXME: Remote key handles must fail */
3328
3329 Status = NtNotifyChangeKey(KeyHandle,
3330 hEvent,
3331 0,
3332 0,
3333 &IoStatusBlock,
3334 dwNotifyFilter,
3335 bWatchSubtree,
3336 0,
3337 0,
3338 fAsynchronous);
3339 if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
3340 {
3341 ErrorCode = RtlNtStatusToDosError(Status);
3342 }
3343
3344 ClosePredefKey(KeyHandle);
3345
3346 return ErrorCode;
3347 }
3348
3349
3350 /************************************************************************
3351 * RegOpenCurrentUser
3352 *
3353 * @implemented
3354 */
3355 LONG WINAPI
3356 RegOpenCurrentUser(IN REGSAM samDesired,
3357 OUT PHKEY phkResult)
3358 {
3359 NTSTATUS Status;
3360
3361 Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
3362 (PHANDLE)phkResult);
3363 if (!NT_SUCCESS(Status))
3364 {
3365 /* NOTE - don't set the last error code! just return the error! */
3366 return RtlNtStatusToDosError(Status);
3367 }
3368
3369 return ERROR_SUCCESS;
3370 }
3371
3372
3373 /************************************************************************
3374 * RegOpenKeyA
3375 *
3376 * 20050503 Fireball - imported from WINE
3377 *
3378 * @implemented
3379 */
3380 LONG WINAPI
3381 RegOpenKeyA(HKEY hKey,
3382 LPCSTR lpSubKey,
3383 PHKEY phkResult)
3384 {
3385 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3386 hKey, lpSubKey, phkResult);
3387
3388 if (!phkResult)
3389 return ERROR_INVALID_PARAMETER;
3390
3391 if (!hKey && lpSubKey && phkResult)
3392 {
3393 return ERROR_INVALID_HANDLE;
3394 }
3395
3396 if (!lpSubKey || !*lpSubKey)
3397 {
3398 *phkResult = hKey;
3399 return ERROR_SUCCESS;
3400 }
3401
3402 return RegOpenKeyExA(hKey,
3403 lpSubKey,
3404 0,
3405 MAXIMUM_ALLOWED,
3406 phkResult);
3407 }
3408
3409
3410 /************************************************************************
3411 * RegOpenKeyW
3412 *
3413 * 19981101 Ariadne
3414 * 19990525 EA
3415 * 20050503 Fireball - imported from WINE
3416 *
3417 * @implemented
3418 */
3419 LONG WINAPI
3420 RegOpenKeyW(HKEY hKey,
3421 LPCWSTR lpSubKey,
3422 PHKEY phkResult)
3423 {
3424 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3425 hKey, lpSubKey, phkResult);
3426
3427 if (!phkResult)
3428 return ERROR_INVALID_PARAMETER;
3429
3430 if (!hKey && lpSubKey && phkResult)
3431 {
3432 return ERROR_INVALID_HANDLE;
3433 }
3434
3435 if (!lpSubKey || !*lpSubKey)
3436 {
3437 *phkResult = hKey;
3438 return ERROR_SUCCESS;
3439 }
3440
3441 return RegOpenKeyExW(hKey,
3442 lpSubKey,
3443 0,
3444 MAXIMUM_ALLOWED,
3445 phkResult);
3446 }
3447
3448
3449 /************************************************************************
3450 * RegOpenKeyExA
3451 *
3452 * @implemented
3453 */
3454 LONG WINAPI
3455 RegOpenKeyExA(HKEY hKey,
3456 LPCSTR lpSubKey,
3457 DWORD ulOptions,
3458 REGSAM samDesired,
3459 PHKEY phkResult)
3460 {
3461 OBJECT_ATTRIBUTES ObjectAttributes;
3462 UNICODE_STRING SubKeyString;
3463 HANDLE KeyHandle;
3464 NTSTATUS Status;
3465 ULONG Attributes = OBJ_CASE_INSENSITIVE;
3466 LONG ErrorCode = ERROR_SUCCESS;
3467
3468 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3469 hKey, lpSubKey, ulOptions, samDesired, phkResult);
3470 if (!phkResult)
3471 {
3472 return ERROR_INVALID_PARAMETER;
3473 }
3474
3475 Status = MapDefaultKey(&KeyHandle,
3476 hKey);
3477 if (!NT_SUCCESS(Status))
3478 {
3479 return RtlNtStatusToDosError(Status);
3480 }
3481
3482 if (ulOptions & REG_OPTION_OPEN_LINK)
3483 Attributes |= OBJ_OPENLINK;
3484
3485 RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
3486 (LPSTR)lpSubKey);
3487 InitializeObjectAttributes(&ObjectAttributes,
3488 &SubKeyString,
3489 Attributes,
3490 KeyHandle,
3491 NULL);
3492
3493 Status = NtOpenKey((PHANDLE)phkResult,
3494 samDesired,
3495 &ObjectAttributes);
3496 RtlFreeUnicodeString(&SubKeyString);
3497 if (!NT_SUCCESS(Status))
3498 {
3499 ErrorCode = RtlNtStatusToDosError(Status);
3500 }
3501
3502 ClosePredefKey(KeyHandle);
3503
3504 return ErrorCode;
3505 }
3506
3507
3508 /************************************************************************
3509 * RegOpenKeyExW
3510 *
3511 * @implemented
3512 */
3513 LONG WINAPI
3514 RegOpenKeyExW(HKEY hKey,
3515 LPCWSTR lpSubKey,
3516 DWORD ulOptions,
3517 REGSAM samDesired,
3518 PHKEY phkResult)
3519 {
3520 OBJECT_ATTRIBUTES ObjectAttributes;
3521 UNICODE_STRING SubKeyString;
3522 HANDLE KeyHandle;
3523 NTSTATUS Status;
3524 ULONG Attributes = OBJ_CASE_INSENSITIVE;
3525 LONG ErrorCode = ERROR_SUCCESS;
3526
3527 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3528 hKey, lpSubKey, ulOptions, samDesired, phkResult);
3529 if (!phkResult)
3530 {
3531 return ERROR_INVALID_PARAMETER;
3532 }
3533
3534 Status = MapDefaultKey(&KeyHandle, hKey);
3535 if (!NT_SUCCESS(Status))
3536 {
3537 return RtlNtStatusToDosError(Status);
3538 }
3539
3540 if (ulOptions & REG_OPTION_OPEN_LINK)
3541 Attributes |= OBJ_OPENLINK;
3542
3543 if (lpSubKey != NULL)
3544 RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
3545 else
3546 RtlInitUnicodeString(&SubKeyString, (LPWSTR)L"");
3547
3548 InitializeObjectAttributes(&ObjectAttributes,
3549 &SubKeyString,
3550 Attributes,
3551 KeyHandle,
3552 NULL);
3553
3554 Status = NtOpenKey((PHANDLE)phkResult,
3555 samDesired,
3556 &ObjectAttributes);
3557 if (!NT_SUCCESS(Status))
3558 {
3559 ErrorCode = RtlNtStatusToDosError(Status);
3560 }
3561
3562 ClosePredefKey(KeyHandle);
3563
3564 return ErrorCode;
3565 }
3566
3567
3568 /************************************************************************
3569 * RegOpenUserClassesRoot
3570 *
3571 * @implemented
3572 */
3573 LONG WINAPI
3574 RegOpenUserClassesRoot(IN HANDLE hToken,
3575 IN DWORD dwOptions,
3576 IN REGSAM samDesired,
3577 OUT PHKEY phkResult)
3578 {
3579 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
3580 const WCHAR UserClassesKeySuffix[] = L"_Classes";
3581 PTOKEN_USER TokenUserData;
3582 ULONG RequiredLength;
3583 UNICODE_STRING UserSidString, UserClassesKeyRoot;
3584 OBJECT_ATTRIBUTES ObjectAttributes;
3585 NTSTATUS Status;
3586
3587 /* check parameters */
3588 if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
3589 {
3590 return ERROR_INVALID_PARAMETER;
3591 }
3592
3593 /*
3594 * Get the user sid from the token
3595 */
3596
3597 ReadTokenSid:
3598 /* determine how much memory we need */
3599 Status = NtQueryInformationToken(hToken,
3600 TokenUser,
3601 NULL,
3602 0,
3603 &RequiredLength);
3604 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
3605 {
3606 /* NOTE - as opposed to all other registry functions windows does indeed
3607 change the last error code in case the caller supplied a invalid
3608 handle for example! */
3609 return RtlNtStatusToDosError(Status);
3610 }
3611 RegInitialize(); /* HACK until delay-loading is implemented */
3612 TokenUserData = RtlAllocateHeap(ProcessHeap,
3613 0,
3614 RequiredLength);
3615 if (TokenUserData == NULL)
3616 {
3617 return ERROR_NOT_ENOUGH_MEMORY;
3618 }
3619
3620 /* attempt to read the information */
3621 Status = NtQueryInformationToken(hToken,
3622 TokenUser,
3623 TokenUserData,
3624 RequiredLength,
3625 &RequiredLength);
3626 if (!NT_SUCCESS(Status))
3627 {
3628 RtlFreeHeap(ProcessHeap,
3629 0,
3630 TokenUserData);
3631 if (Status == STATUS_BUFFER_TOO_SMALL)
3632 {
3633 /* the information appears to have changed?! try again */
3634 goto ReadTokenSid;
3635 }
3636
3637 /* NOTE - as opposed to all other registry functions windows does indeed
3638 change the last error code in case the caller supplied a invalid
3639 handle for example! */
3640 return RtlNtStatusToDosError(Status);
3641 }
3642
3643 /*
3644 * Build the absolute path for the user's registry in the form
3645 * "\Registry\User\<SID>_Classes"
3646 */
3647 Status = RtlConvertSidToUnicodeString(&UserSidString,
3648 TokenUserData->User.Sid,
3649 TRUE);
3650
3651 /* we don't need the user data anymore, free it */
3652 RtlFreeHeap(ProcessHeap,
3653 0,
3654 TokenUserData);
3655
3656 if (!NT_SUCCESS(Status))
3657 {
3658 return RtlNtStatusToDosError(Status);
3659 }
3660
3661 /* allocate enough memory for the entire key string */
3662 UserClassesKeyRoot.Length = 0;
3663 UserClassesKeyRoot.MaximumLength = UserSidString.Length +
3664 sizeof(UserClassesKeyPrefix) +
3665 sizeof(UserClassesKeySuffix);
3666 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
3667 0,
3668 UserClassesKeyRoot.MaximumLength);
3669 if (UserClassesKeyRoot.Buffer == NULL)
3670 {
3671 RtlFreeUnicodeString(&UserSidString);
3672 return RtlNtStatusToDosError(Status);
3673 }
3674
3675 /* build the string */
3676 RtlAppendUnicodeToString(&UserClassesKeyRoot,
3677 UserClassesKeyPrefix);
3678 RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
3679 &UserSidString);
3680 RtlAppendUnicodeToString(&UserClassesKeyRoot,
3681 UserClassesKeySuffix);
3682
3683 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
3684
3685 /*
3686 * Open the key
3687 */
3688 InitializeObjectAttributes(&ObjectAttributes,
3689 &UserClassesKeyRoot,
3690 OBJ_CASE_INSENSITIVE,
3691 NULL,
3692 NULL);
3693
3694 Status = NtOpenKey((PHANDLE)phkResult,
3695 samDesired,
3696 &ObjectAttributes);
3697
3698 RtlFreeUnicodeString(&UserSidString);
3699 RtlFreeUnicodeString(&UserClassesKeyRoot);
3700
3701 if (!NT_SUCCESS(Status))
3702 {
3703 return RtlNtStatusToDosError(Status);
3704 }
3705
3706 return ERROR_SUCCESS;
3707 }
3708
3709
3710 /************************************************************************
3711 * RegQueryInfoKeyA
3712 *
3713 * @implemented
3714 */
3715 LONG WINAPI
3716 RegQueryInfoKeyA(HKEY hKey,
3717 LPSTR lpClass,
3718 LPDWORD lpcbClass,
3719 LPDWORD lpReserved,
3720 LPDWORD lpcSubKeys,
3721 LPDWORD lpcbMaxSubKeyLen,
3722 LPDWORD lpcbMaxClassLen,
3723 LPDWORD lpcValues,
3724 LPDWORD lpcbMaxValueNameLen,
3725 LPDWORD lpcbMaxValueLen,
3726 LPDWORD lpcbSecurityDescriptor,
3727 PFILETIME lpftLastWriteTime)
3728 {
3729 WCHAR ClassName[MAX_PATH];
3730 UNICODE_STRING UnicodeString;
3731 ANSI_STRING AnsiString;
3732 LONG ErrorCode;
3733
3734 RtlInitUnicodeString(&UnicodeString,
3735 NULL);
3736 if (lpClass != NULL)
3737 {
3738 UnicodeString.Buffer = &ClassName[0];
3739 UnicodeString.MaximumLength = sizeof(ClassName);
3740 AnsiString.MaximumLength = *lpcbClass;
3741 }
3742
3743 ErrorCode = RegQueryInfoKeyW(hKey,
3744 UnicodeString.Buffer,
3745 lpcbClass,
3746 lpReserved,
3747 lpcSubKeys,
3748 lpcbMaxSubKeyLen,
3749 lpcbMaxClassLen,
3750 lpcValues,
3751 lpcbMaxValueNameLen,
3752 lpcbMaxValueLen,
3753 lpcbSecurityDescriptor,
3754 lpftLastWriteTime);
3755 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
3756 {
3757 AnsiString.Buffer = lpClass;
3758 AnsiString.Length = 0;
3759 UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
3760 RtlUnicodeStringToAnsiString(&AnsiString,
3761 &UnicodeString,
3762 FALSE);
3763 *lpcbClass = AnsiString.Length;
3764 lpClass[AnsiString.Length] = 0;
3765 }
3766
3767 return ErrorCode;
3768 }
3769
3770
3771 /************************************************************************
3772 * RegQueryInfoKeyW
3773 *
3774 * @implemented
3775 */
3776 LONG WINAPI
3777 RegQueryInfoKeyW(HKEY hKey,
3778 LPWSTR lpClass,
3779 LPDWORD lpcbClass,
3780 LPDWORD lpReserved,
3781 LPDWORD lpcSubKeys,
3782 LPDWORD lpcbMaxSubKeyLen,
3783 LPDWORD lpcbMaxClassLen,
3784 LPDWORD lpcValues,
3785 LPDWORD lpcbMaxValueNameLen,
3786 LPDWORD lpcbMaxValueLen,
3787 LPDWORD lpcbSecurityDescriptor,
3788 PFILETIME lpftLastWriteTime)
3789 {
3790 KEY_FULL_INFORMATION FullInfoBuffer;
3791 PKEY_FULL_INFORMATION FullInfo;
3792 ULONG FullInfoSize;
3793 ULONG ClassLength = 0;
3794 HANDLE KeyHandle;
3795 NTSTATUS Status;
3796 ULONG Length;
3797 LONG ErrorCode = ERROR_SUCCESS;
3798
3799 if ((lpClass) && (!lpcbClass))
3800 {
3801 return ERROR_INVALID_PARAMETER;
3802 }
3803
3804 Status = MapDefaultKey(&KeyHandle,
3805 hKey);
3806 if (!NT_SUCCESS(Status))
3807 {
3808 return RtlNtStatusToDosError(Status);
3809 }
3810
3811 if (lpClass != NULL)
3812 {
3813 if (*lpcbClass > 0)
3814 {
3815 ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3816 }
3817 else
3818 {
3819 ClassLength = 0;
3820 }
3821
3822 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3823 FullInfo = RtlAllocateHeap(ProcessHeap,
3824 0,
3825 FullInfoSize);
3826 if (FullInfo == NULL)
3827 {
3828 ErrorCode = ERROR_OUTOFMEMORY;
3829 goto Cleanup;
3830 }
3831
3832 FullInfo->ClassLength = ClassLength;
3833 }
3834 else
3835 {
3836 FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3837 FullInfo = &FullInfoBuffer;
3838 FullInfo->ClassLength = 0;
3839 }
3840 FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
3841
3842 Status = NtQueryKey(KeyHandle,
3843 KeyFullInformation,
3844 FullInfo,
3845 FullInfoSize,
3846 &Length);
3847 TRACE("NtQueryKey() returned status 0x%X\n", Status);
3848 if (!NT_SUCCESS(Status))
3849 {
3850 if (lpClass != NULL)
3851 {
3852 RtlFreeHeap(ProcessHeap,
3853 0,
3854 FullInfo);
3855 }
3856
3857 ErrorCode = RtlNtStatusToDosError(Status);
3858 goto Cleanup;
3859 }
3860
3861 TRACE("SubKeys %d\n", FullInfo->SubKeys);
3862 if (lpcSubKeys != NULL)
3863 {
3864 *lpcSubKeys = FullInfo->SubKeys;
3865 }
3866
3867 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3868 if (lpcbMaxSubKeyLen != NULL)
3869 {
3870 *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
3871 }
3872
3873 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3874 if (lpcbMaxClassLen != NULL)
3875 {
3876 *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
3877 }
3878
3879 TRACE("Values %lu\n", FullInfo->Values);
3880 if (lpcValues != NULL)
3881 {
3882 *lpcValues = FullInfo->Values;
3883 }
3884
3885 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3886 if (lpcbMaxValueNameLen != NULL)
3887 {
3888 *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
3889 }
3890
3891 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3892 if (lpcbMaxValueLen != NULL)
3893 {
3894 *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
3895 }
3896
3897 if (lpcbSecurityDescriptor != NULL)
3898 {
3899 Status = NtQuerySecurityObject(KeyHandle,
3900 OWNER_SECURITY_INFORMATION |
3901 GROUP_SECURITY_INFORMATION |
3902 DACL_SECURITY_INFORMATION,
3903 NULL,
3904 0,
3905 lpcbSecurityDescriptor);
3906 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
3907 {
3908 if (lpClass != NULL)
3909 {
3910 RtlFreeHeap(ProcessHeap,
3911 0,
3912 FullInfo);
3913 }
3914
3915 ErrorCode = RtlNtStatusToDosError(Status);
3916 goto Cleanup;
3917 }
3918 }
3919
3920 if (lpftLastWriteTime != NULL)
3921 {
3922 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3923 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3924 }
3925
3926 if (lpClass != NULL)
3927 {
3928 if (FullInfo->ClassLength > ClassLength)
3929 {
3930 ErrorCode = ERROR_BUFFER_OVERFLOW;
3931 }
3932 else
3933 {
3934 RtlCopyMemory(lpClass,
3935 FullInfo->Class,
3936 FullInfo->ClassLength);
3937 *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
3938 lpClass[*lpcbClass] = 0;
3939 }
3940
3941 RtlFreeHeap(ProcessHeap,
3942 0,
3943 FullInfo);
3944 }
3945
3946 Cleanup:
3947 ClosePredefKey(KeyHandle);
3948
3949 return ErrorCode;
3950 }
3951
3952
3953 /************************************************************************
3954 * RegQueryMultipleValuesA
3955 *
3956 * @implemented
3957 */
3958 LONG WINAPI
3959 RegQueryMultipleValuesA(HKEY hKey,
3960 PVALENTA val_list,
3961 DWORD num_vals,
3962 LPSTR lpValueBuf,
3963 LPDWORD ldwTotsize)
3964 {
3965 ULONG i;
3966 DWORD maxBytes = *ldwTotsize;
3967 LPSTR bufptr = (LPSTR)lpValueBuf;
3968 LONG ErrorCode;
3969
3970 if (maxBytes >= (1024*1024))
3971 return ERROR_TRANSFER_TOO_LONG;
3972
3973 *ldwTotsize = 0;
3974
3975 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3976 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3977
3978 for (i = 0; i < num_vals; i++)
3979 {
3980 val_list[i].ve_valuelen = 0;
3981 ErrorCode = RegQueryValueExA(hKey,
3982 val_list[i].ve_valuename,
3983 NULL,
3984 NULL,
3985 NULL,
3986 &val_list[i].ve_valuelen);
3987 if (ErrorCode != ERROR_SUCCESS)
3988 {
3989 return ErrorCode;
3990 }
3991
3992 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3993 {
3994 ErrorCode = RegQueryValueExA(hKey,
3995 val_list[i].ve_valuename,
3996 NULL,
3997 &val_list[i].ve_type,
3998 (LPBYTE)bufptr,
3999 &val_list[i].ve_valuelen);
4000 if (ErrorCode != ERROR_SUCCESS)
4001 {
4002 return ErrorCode;
4003 }
4004
4005 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
4006
4007 bufptr += val_list[i].ve_valuelen;
4008 }
4009
4010 *ldwTotsize += val_list[i].ve_valuelen;
4011 }
4012
4013 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
4014 }
4015
4016
4017 /************************************************************************
4018 * RegQueryMultipleValuesW
4019 *
4020 * @implemented
4021 */
4022 LONG WINAPI
4023 RegQueryMultipleValuesW(HKEY hKey,
4024 PVALENTW val_list,
4025 DWORD num_vals,
4026 LPWSTR lpValueBuf,
4027 LPDWORD ldwTotsize)
4028 {
4029 ULONG i;
4030 DWORD maxBytes = *ldwTotsize;
4031 LPSTR bufptr = (LPSTR)lpValueBuf;
4032 LONG ErrorCode;
4033
4034 if (maxBytes >= (1024*1024))
4035 return ERROR_TRANSFER_TOO_LONG;
4036
4037 *ldwTotsize = 0;
4038
4039 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
4040 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
4041
4042 for (i = 0; i < num_vals; i++)
4043 {
4044 val_list[i].ve_valuelen = 0;
4045 ErrorCode = RegQueryValueExW(hKey,
4046 val_list[i].ve_valuename,
4047 NULL,
4048 NULL,
4049 NULL,
4050 &val_list[i].ve_valuelen);
4051 if (ErrorCode != ERROR_SUCCESS)
4052 {
4053 return ErrorCode;
4054 }
4055
4056 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
4057 {
4058 ErrorCode = RegQueryValueExW(hKey,
4059 val_list[i].ve_valuename,
4060 NULL,
4061 &val_list[i].ve_type,
4062 (LPBYTE)bufptr,
4063 &val_list[i].ve_valuelen);
4064 if (ErrorCode != ERROR_SUCCESS)
4065 {
4066 return ErrorCode;
4067 }
4068
4069 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
4070
4071 bufptr += val_list[i].ve_valuelen;
4072 }
4073
4074 *ldwTotsize += val_list[i].ve_valuelen;
4075 }
4076
4077 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
4078 }
4079
4080
4081 /************************************************************************
4082 * RegQueryReflectionKey
4083 *
4084 * @unimplemented
4085 */
4086 LONG WINAPI
4087 RegQueryReflectionKey(IN HKEY hBase,
4088 OUT BOOL* bIsReflectionDisabled)
4089 {
4090 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
4091 hBase, bIsReflectionDisabled);
4092 return ERROR_CALL_NOT_IMPLEMENTED;
4093 }
4094
4095
4096 /******************************************************************************
4097 * RegQueryValueExA [ADVAPI32.@]
4098 *
4099 * Get the type and contents of a specified value under with a key.
4100 *
4101 * PARAMS
4102 * hkey [I] Handle of the key to query
4103 * name [I] Name of value under hkey to query
4104 * reserved [I] Reserved - must be NULL
4105 * type [O] Destination for the value type, or NULL if not required
4106 * data [O] Destination for the values contents, or NULL if not required
4107 * count [I/O] Size of data, updated with the number of bytes returned
4108 *
4109 * RETURNS
4110 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
4111 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4112 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4113 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4114 *
4115 * NOTES
4116 * MSDN states that if data is too small it is partially filled. In reality
4117 * it remains untouched.
4118 */
4119 LONG
4120 WINAPI
4121 RegQueryValueExA(HKEY hkeyorg,
4122 LPCSTR name,
4123 LPDWORD reserved,
4124 LPDWORD type,
4125 LPBYTE data,
4126 LPDWORD count)
4127 {
4128 HANDLE hkey;
4129 NTSTATUS status;
4130 ANSI_STRING nameA;
4131 UNICODE_STRING nameW;
4132 DWORD total_size, datalen = 0;
4133 char buffer[256], *buf_ptr = buffer;
4134 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
4135 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4136
4137 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4138 hkeyorg, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
4139
4140 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4141 status = MapDefaultKey(&hkey, hkeyorg);
4142 if (!NT_SUCCESS(status))
4143 {
4144 return RtlNtStatusToDosError(status);
4145 }
4146
4147 if (count) datalen = *count;
4148 if (!data && count) *count = 0;
4149
4150 RtlInitAnsiString( &nameA, name );
4151 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
4152 {
4153 ClosePredefKey(hkey);
4154 return RtlNtStatusToDosError(status);
4155 }
4156
4157 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
4158 buffer, sizeof(buffer), &total_size );
4159 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
4160
4161 /* we need to fetch the contents for a string type even if not requested,
4162 * because we need to compute the length of the ASCII string. */
4163 if (data || is_string(info->Type))
4164 {
4165 /* retry with a dynamically allocated buffer */
4166 while (status == STATUS_BUFFER_OVERFLOW)
4167 {
4168 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4169 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4170 {
4171 status = STATUS_NO_MEMORY;
4172 goto done;
4173 }
4174 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4175 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
4176 buf_ptr, total_size, &total_size );
4177 }
4178
4179 if (status) goto done;
4180
4181 if (is_string(info->Type))
4182 {
4183 DWORD len;
4184
4185 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
4186 total_size - info_size );
4187 if (data && len)
4188 {
4189 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
4190 else
4191 {
4192 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
4193 total_size - info_size );
4194 /* if the type is REG_SZ and data is not 0-terminated
4195 * and there is enough space in the buffer NT appends a \0 */
4196 if (len < datalen && data[len-1]) data[len] = 0;
4197 }
4198 }
4199 total_size = len + info_size;
4200 }
4201 else if (data)
4202 {
4203 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
4204 else memcpy( data, buf_ptr + info_size, total_size - info_size );
4205 }
4206 }
4207 else status = STATUS_SUCCESS;
4208
4209 if (type) *type = info->Type;
4210 if (count) *count = total_size - info_size;
4211
4212 done:
4213 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4214 RtlFreeUnicodeString( &nameW );
4215 ClosePredefKey(hkey);
4216 return RtlNtStatusToDosError(status);
4217 }
4218
4219
4220 /************************************************************************
4221 * RegQueryValueExW
4222 *
4223 * @implemented
4224 */
4225 LONG
4226 WINAPI
4227 RegQueryValueExW(HKEY hkeyorg,
4228 LPCWSTR name,
4229 LPDWORD reserved,
4230 LPDWORD type,
4231 LPBYTE data,
4232 LPDWORD count)
4233 {
4234 HANDLE hkey;
4235 NTSTATUS status;
4236 UNICODE_STRING name_str;
4237 DWORD total_size;
4238 char buffer[256], *buf_ptr = buffer;
4239 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
4240 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4241
4242 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4243 hkeyorg, debugstr_w(name), reserved, type, data, count,
4244 (count && data) ? *count : 0 );
4245
4246 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4247
4248 status = MapDefaultKey(&hkey, hkeyorg);
4249 if (!NT_SUCCESS(status))
4250 {
4251 return RtlNtStatusToDosError(status);
4252 }
4253
4254 RtlInitUnicodeString( &name_str, name );
4255
4256 if (data) total_size = min( sizeof(buffer), *count + info_size );
4257 else
4258 {
4259 total_size = info_size;
4260 if (count) *count = 0;
4261 }
4262
4263 /* this matches Win9x behaviour - NT sets *type to a random value */
4264 if (type) *type = REG_NONE;
4265
4266 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4267 buffer, total_size, &total_size );
4268 if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) goto done;
4269
4270 if (data)
4271 {
4272 /* retry with a dynamically allocated buffer */
4273 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
4274 {
4275 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4276 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4277 {
4278 ClosePredefKey(hkey);
4279 return ERROR_NOT_ENOUGH_MEMORY;
4280 }
4281 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4282 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4283 buf_ptr, total_size, &total_size );
4284 }
4285
4286 if (NT_SUCCESS(status))
4287 {
4288 memcpy( data, buf_ptr + info_size, total_size - info_size );
4289 /* if the type is REG_SZ and data is not 0-terminated
4290 * and there is enough space in the buffer NT appends a \0 */
4291 if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR))
4292 {
4293 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
4294 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
4295 }
4296 }
4297 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
4298 }
4299 else status = STATUS_SUCCESS;
4300
4301 if (type) *type = info->Type;
4302 if (count) *count = total_size - info_size;
4303
4304 done:
4305 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4306 ClosePredefKey(hkey);
4307 return RtlNtStatusToDosError(status);
4308 }
4309
4310
4311 /************************************************************************
4312 * RegQueryValueA
4313 *
4314 * @implemented
4315 */
4316 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
4317 {
4318 DWORD ret;
4319 HKEY subkey = hkey;
4320
4321 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
4322
4323 if (name && name[0])
4324 {
4325 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
4326 }
4327 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4328 if (subkey != hkey) RegCloseKey( subkey );
4329 if (ret == ERROR_FILE_NOT_FOUND)
4330 {
4331 /* return empty string if default value not found */
4332 if (data) *data = 0;
4333 if (count) *count = 1;
4334 ret = ERROR_SUCCESS;
4335 }
4336 return ret;
4337 }
4338
4339
4340 /************************************************************************
4341 * RegQueryValueW
4342 *
4343 * @implemented
4344 */
4345 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
4346 {
4347 DWORD ret;
4348 HKEY subkey = hkey;
4349
4350 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
4351 if (hkey == NULL)
4352 {
4353 return ERROR_INVALID_HANDLE;
4354 }
4355 if (name && name[0])
4356 {
4357 ret = RegOpenKeyW( hkey, name, &subkey);
4358 if (ret != ERROR_SUCCESS)
4359 {
4360 return ret;
4361 }
4362 }
4363
4364 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4365
4366 if (subkey != hkey)
4367 {
4368 RegCloseKey( subkey );
4369 }
4370
4371 if (ret == ERROR_FILE_NOT_FOUND)
4372 {
4373 /* return empty string if default value not found */
4374 if (data)
4375 *data = 0;
4376 if (count)
4377 *count = sizeof(WCHAR);
4378 ret = ERROR_SUCCESS;
4379 }
4380 return ret;
4381 }
4382
4383
4384 /************************************************************************
4385 * RegReplaceKeyA
4386 *
4387 * @implemented
4388 */
4389 LONG WINAPI
4390 RegReplaceKeyA(HKEY hKey,
4391 LPCSTR lpSubKey,
4392 LPCSTR lpNewFile,
4393 LPCSTR lpOldFile)
4394 {
4395 UNICODE_STRING SubKey;
4396 UNICODE_STRING NewFile;
4397 UNICODE_STRING OldFile;
4398 LONG ErrorCode;
4399
4400 RtlCreateUnicodeStringFromAsciiz(&SubKey,
4401 (PCSZ)lpSubKey);
4402 RtlCreateUnicodeStringFromAsciiz(&OldFile,
4403 (PCSZ)lpOldFile);
4404 RtlCreateUnicodeStringFromAsciiz(&NewFile,
4405 (PCSZ)lpNewFile);
4406
4407 ErrorCode = RegReplaceKeyW(hKey,
4408 SubKey.Buffer,
4409 NewFile.Buffer,
4410 OldFile.Buffer);
4411
4412 RtlFreeUnicodeString(&OldFile);
4413 RtlFreeUnicodeString(&NewFile);
4414 RtlFreeUnicodeString(&SubKey);
4415
4416 return ErrorCode;
4417 }
4418
4419
4420 /************************************************************************
4421 * RegReplaceKeyW
4422 *
4423 * @unimplemented
4424 */
4425 LONG WINAPI
4426 RegReplaceKeyW(HKEY hKey,
4427 LPCWSTR lpSubKey,
4428 LPCWSTR lpNewFile,
4429 LPCWSTR lpOldFile)
4430 {
4431 OBJECT_ATTRIBUTES KeyObjectAttributes;
4432 OBJECT_ATTRIBUTES NewObjectAttributes;
4433 OBJECT_ATTRIBUTES OldObjectAttributes;
4434 UNICODE_STRING SubKeyName;
4435 UNICODE_STRING NewFileName;
4436 UNICODE_STRING OldFileName;
4437 BOOLEAN CloseRealKey;
4438 HANDLE RealKeyHandle;
4439 HANDLE KeyHandle;
4440 NTSTATUS Status;
4441 LONG ErrorCode = ERROR_SUCCESS;
4442
4443 if (hKey == HKEY_PERFORMANCE_DATA)
4444 {
4445 return ERROR_INVALID_HANDLE;
4446 }
4447
4448 Status = MapDefaultKey(&KeyHandle,
4449 hKey);
4450 if (!NT_SUCCESS(Status))
4451 {
4452 return RtlNtStatusToDosError(Status);
4453 }
4454
4455 /* Open the real key */
4456 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
4457 {
4458 RtlInitUnicodeString(&SubKeyName,
4459 (PWSTR)lpSubKey);
4460 InitializeObjectAttributes(&KeyObjectAttributes,
4461 &SubKeyName,
4462 OBJ_CASE_INSENSITIVE,
4463 KeyHandle,
4464 NULL);
4465 Status = NtOpenKey(&RealKeyHandle,
4466 MAXIMUM_ALLOWED,
4467 &KeyObjectAttributes);
4468 if (!NT_SUCCESS(Status))
4469 {
4470 ErrorCode = RtlNtStatusToDosError(Status);
4471 goto Cleanup;
4472 }
4473
4474 CloseRealKey = TRUE;
4475 }
4476 else
4477 {
4478 RealKeyHandle = KeyHandle;
4479 CloseRealKey = FALSE;
4480 }
4481
4482 /* Convert new file name */
4483 if (!RtlDosPathNameToNtPathName_U(lpNewFile,
4484 &NewFileName,
4485 NULL,
4486 NULL))
4487 {
4488 if (CloseRealKey)
4489 {
4490 NtClose(RealKeyHandle);
4491 }
4492
4493 ErrorCode = ERROR_INVALID_PARAMETER;
4494 goto Cleanup;
4495 }
4496
4497 InitializeObjectAttributes(&NewObjectAttributes,
4498 &NewFileName,
4499 OBJ_CASE_INSENSITIVE,
4500 NULL,
4501 NULL);
4502
4503 /* Convert old file name */
4504 if (!RtlDosPathNameToNtPathName_U(lpOldFile,
4505 &OldFileName,
4506 NULL,
4507 NULL))
4508 {
4509 RtlFreeHeap(RtlGetProcessHeap (),
4510 0,
4511 NewFileName.Buffer);
4512 if (CloseRealKey)
4513 {
4514 NtClose(RealKeyHandle);
4515 }
4516
4517 ErrorCode = ERROR_INVALID_PARAMETER;
4518 goto Cleanup;
4519 }
4520
4521 InitializeObjectAttributes(&OldObjectAttributes,
4522 &OldFileName,
4523 OBJ_CASE_INSENSITIVE,
4524 NULL,
4525 NULL);
4526
4527 Status = NtReplaceKey(&NewObjectAttributes,
4528 RealKeyHandle,
4529 &OldObjectAttributes);
4530
4531 RtlFreeHeap(RtlGetProcessHeap(),
4532 0,
4533 OldFileName.Buffer);
4534 RtlFreeHeap(RtlGetProcessHeap(),
4535 0,
4536 NewFileName.Buffer);
4537
4538 if (CloseRealKey)
4539 {
4540 NtClose(RealKeyHandle);
4541 }
4542
4543 if (!NT_SUCCESS(Status))
4544 {
4545 return RtlNtStatusToDosError(Status);
4546 }
4547
4548 Cleanup:
4549 ClosePredefKey(KeyHandle);
4550
4551 return ErrorCode;
4552 }
4553
4554
4555 /************************************************************************
4556 * RegRestoreKeyA
4557 *
4558 * @implemented
4559 */
4560 LONG WINAPI
4561 RegRestoreKeyA(HKEY hKey,
4562 LPCSTR lpFile,
4563 DWORD dwFlags)
4564 {
4565 UNICODE_STRING FileName;
4566 LONG ErrorCode;
4567
4568 RtlCreateUnicodeStringFromAsciiz(&FileName,
4569 (PCSZ)lpFile);
4570
4571 ErrorCode = RegRestoreKeyW(hKey,
4572 FileName.Buffer,
4573 dwFlags);
4574
4575 RtlFreeUnicodeString(&FileName);
4576
4577 return ErrorCode;
4578 }
4579
4580
4581 /************************************************************************
4582 * RegRestoreKeyW
4583 *
4584 * @implemented
4585 */
4586 LONG WINAPI
4587 RegRestoreKeyW(HKEY hKey,
4588 LPCWSTR lpFile,
4589 DWORD dwFlags)
4590 {
4591 OBJECT_ATTRIBUTES ObjectAttributes;
4592 IO_STATUS_BLOCK IoStatusBlock;
4593 UNICODE_STRING FileName;
4594 HANDLE FileHandle;
4595 HANDLE KeyHandle;
4596 NTSTATUS Status;
4597
4598 if (hKey == HKEY_PERFORMANCE_DATA)
4599 {
4600 return ERROR_INVALID_HANDLE;
4601 }
4602
4603 Status = MapDefaultKey(&KeyHandle,
4604 hKey);
4605 if (!NT_SUCCESS(Status))
4606 {
4607 return RtlNtStatusToDosError(Status);
4608 }
4609
4610 if (!RtlDosPathNameToNtPathName_U(lpFile,
4611 &FileName,
4612 NULL,
4613 NULL))
4614 {
4615 Status = STATUS_INVALID_PARAMETER;
4616 goto Cleanup;
4617 }
4618
4619 InitializeObjectAttributes(&ObjectAttributes,
4620 &FileName,
4621 OBJ_CASE_INSENSITIVE,
4622 NULL,
4623 NULL);
4624
4625 Status = NtOpenFile(&FileHandle,
4626 FILE_GENERIC_READ,
4627 &ObjectAttributes,
4628 &IoStatusBlock,
4629 FILE_SHARE_READ,
4630 FILE_SYNCHRONOUS_IO_NONALERT);
4631 RtlFreeHeap(RtlGetProcessHeap(),
4632 0,
4633 FileName.Buffer);
4634 if (!NT_SUCCESS(Status))
4635 {
4636 goto Cleanup;
4637 }
4638
4639 Status = NtRestoreKey(KeyHandle,
4640 FileHandle,
4641 (ULONG)dwFlags);
4642 NtClose (FileHandle);
4643
4644 Cleanup:
4645 ClosePredefKey(KeyHandle);
4646
4647 if (!NT_SUCCESS(Status))
4648 {
4649 return RtlNtStatusToDosError(Status);
4650 }
4651
4652 return ERROR_SUCCESS;
4653 }
4654
4655
4656 /************************************************************************
4657 * RegSaveKeyA
4658 *
4659 * @implemented
4660 */
4661 LONG WINAPI
4662 RegSaveKeyA(HKEY hKey,
4663 LPCSTR lpFile,
4664 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4665 {
4666 UNICODE_STRING FileName;
4667 LONG ErrorCode;
4668
4669 RtlCreateUnicodeStringFromAsciiz(&FileName,
4670 (LPSTR)lpFile);
4671 ErrorCode = RegSaveKeyW(hKey,
4672 FileName.Buffer,
4673 lpSecurityAttributes);
4674 RtlFreeUnicodeString(&FileName);
4675
4676 return ErrorCode;
4677 }
4678
4679
4680 /************************************************************************
4681 * RegSaveKeyW
4682 *
4683 * @implemented
4684 */
4685 LONG WINAPI
4686 RegSaveKeyW(HKEY hKey,
4687 LPCWSTR lpFile,
4688 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4689 {
4690 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
4691 OBJECT_ATTRIBUTES ObjectAttributes;
4692 UNICODE_STRING FileName;
4693 IO_STATUS_BLOCK IoStatusBlock;
4694 HANDLE FileHandle;
4695 HANDLE KeyHandle;
4696 NTSTATUS Status;
4697
4698 Status = MapDefaultKey(&KeyHandle,
4699 hKey);
4700 if (!NT_SUCCESS(Status))
4701 {
4702 return RtlNtStatusToDosError(Status);
4703 }
4704
4705 if (!RtlDosPathNameToNtPathName_U(lpFile,
4706 &FileName,
4707 NULL,
4708 NULL))
4709 {
4710 Status = STATUS_INVALID_PARAMETER;
4711 goto Cleanup;
4712 }
4713
4714 if (lpSecurityAttributes != NULL)
4715 {
4716 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4717 }
4718
4719 InitializeObjectAttributes(&ObjectAttributes,
4720 &FileName,
4721 OBJ_CASE_INSENSITIVE,
4722 NULL,
4723 SecurityDescriptor);
4724 Status = NtCreateFile(&FileHandle,
4725 GENERIC_WRITE | SYNCHRONIZE,
4726 &ObjectAttributes,
4727 &IoStatusBlock,
4728 NULL,
4729 FILE_ATTRIBUTE_NORMAL,
4730 FILE_SHARE_READ,
4731 FILE_CREATE,
4732 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
4733 NULL,
4734 0);
4735 RtlFreeHeap(RtlGetProcessHeap(),
4736 0,
4737 FileName.Buffer);
4738 if (!NT_SUCCESS(Status))
4739 {
4740 goto Cleanup;
4741 }
4742
4743 Status = NtSaveKey(KeyHandle,
4744 FileHandle);
4745 NtClose (FileHandle);
4746
4747 Cleanup:
4748 ClosePredefKey(KeyHandle);
4749
4750 if (!NT_SUCCESS(Status))
4751 {
4752 return RtlNtStatusToDosError(Status);
4753 }
4754
4755 return ERROR_SUCCESS;
4756 }
4757
4758
4759 /************************************************************************
4760 * RegSaveKeyExA
4761 *
4762 * @implemented
4763 */
4764 LONG
4765 WINAPI
4766 RegSaveKeyExA(HKEY hKey,
4767 LPCSTR lpFile,
4768 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4769 DWORD Flags)
4770 {
4771 UNICODE_STRING FileName;
4772 LONG ErrorCode;
4773
4774 RtlCreateUnicodeStringFromAsciiz(&FileName,
4775 (LPSTR)lpFile);
4776 ErrorCode = RegSaveKeyExW(hKey,
4777 FileName.Buffer,
4778 lpSecurityAttributes,
4779 Flags);
4780 RtlFreeUnicodeString(&FileName);
4781
4782 return ErrorCode;
4783 }
4784
4785
4786 /************************************************************************
4787 * RegSaveKeyExW
4788 *
4789 * @unimplemented
4790 */
4791 LONG
4792 WINAPI
4793 RegSaveKeyExW(HKEY hKey,
4794 LPCWSTR lpFile,
4795 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4796 DWORD Flags)
4797 {
4798 switch (Flags)
4799 {
4800 case REG_STANDARD_FORMAT:
4801 case REG_LATEST_FORMAT:
4802 case REG_NO_COMPRESSION:
4803 break;
4804 default:
4805 return ERROR_INVALID_PARAMETER;
4806 }
4807
4808 FIXME("RegSaveKeyExW(): Flags ignored!\n");
4809
4810 return RegSaveKeyW(hKey,
4811 lpFile,
4812 lpSecurityAttributes);
4813 }
4814
4815
4816 /************************************************************************
4817 * RegSetKeySecurity
4818 *
4819 * @implemented
4820 */
4821 LONG WINAPI
4822 RegSetKeySecurity(HKEY hKey,
4823 SECURITY_INFORMATION SecurityInformation,
4824 PSECURITY_DESCRIPTOR pSecurityDescriptor)
4825 {
4826 HANDLE KeyHandle;
4827 NTSTATUS Status;
4828
4829 if (hKey == HKEY_PERFORMANCE_DATA)
4830 {
4831 return ERROR_INVALID_HANDLE;
4832 }
4833
4834 Status = MapDefaultKey(&KeyHandle,
4835 hKey);
4836 if (!NT_SUCCESS(Status))
4837 {
4838 return RtlNtStatusToDosError(Status);
4839 }
4840
4841 Status = NtSetSecurityObject(KeyHandle,
4842 SecurityInformation,
4843 pSecurityDescriptor);
4844
4845 ClosePredefKey(KeyHandle);
4846
4847 if (!NT_SUCCESS(Status))
4848 {
4849 return RtlNtStatusToDosError(Status);
4850 }
4851
4852 return ERROR_SUCCESS;
4853 }
4854
4855
4856 /************************************************************************
4857 * RegSetValueExA
4858 *
4859 * @implemented
4860 */
4861 LONG WINAPI
4862 RegSetValueExA(HKEY hKey,
4863 LPCSTR lpValueName,
4864 DWORD Reserved,
4865 DWORD dwType,
4866 CONST BYTE* lpData,
4867 DWORD cbData)
4868 {
4869 UNICODE_STRING ValueName;
4870 LPWSTR pValueName;
4871 ANSI_STRING AnsiString;
4872 UNICODE_STRING Data;
4873 LONG ErrorCode;
4874 LPBYTE pData;
4875 DWORD DataSize;
4876 NTSTATUS Status;
4877
4878 /* Convert SubKey name to Unicode */
4879 if (lpValueName != NULL && lpValueName[0] != '\0')
4880 {
4881 BOOL bConverted;
4882 bConverted = RtlCreateUnicodeStringFromAsciiz(&ValueName,
4883 (PSTR)lpValueName);
4884 if(!bConverted)
4885 return ERROR_NOT_ENOUGH_MEMORY;
4886 }
4887 else
4888 {
4889 ValueName.Buffer = NULL;
4890 }
4891
4892 pValueName = (LPWSTR)ValueName.Buffer;
4893
4894
4895 if (is_string(dwType) && (cbData != 0))
4896 {
4897 /* Convert ANSI string Data to Unicode */
4898 /* If last character NOT zero then increment length */
4899 LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0);
4900 AnsiString.Buffer = (PSTR)lpData;
4901 AnsiString.Length = cbData + bNoNulledStr;
4902 AnsiString.MaximumLength = cbData + bNoNulledStr;
4903 Status = RtlAnsiStringToUnicodeString(&Data,
4904 &AnsiString,
4905 TRUE);
4906
4907 if (!NT_SUCCESS(Status))
4908 {
4909 if (pValueName != NULL)
4910 RtlFreeUnicodeString(&ValueName);
4911
4912 return RtlNtStatusToDosError(Status);
4913 }
4914 pData = (LPBYTE)Data.Buffer;
4915 DataSize = cbData * sizeof(WCHAR);
4916 }
4917 else
4918 {
4919 Data.Buffer = NULL;
4920 pData = (LPBYTE)lpData;
4921 DataSize = cbData;
4922 }
4923
4924 ErrorCode = RegSetValueExW(hKey,
4925 pValueName,
4926 Reserved,
4927 dwType,
4928 pData,
4929 DataSize);
4930
4931 if (pValueName != NULL)
4932 RtlFreeUnicodeString(&ValueName);
4933
4934 if (Data.Buffer != NULL)
4935 RtlFreeUnicodeString(&Data);
4936
4937 return ErrorCode;
4938 }
4939
4940
4941 /************************************************************************
4942 * RegSetValueExW
4943 *
4944 * @implemented
4945 */
4946 LONG WINAPI
4947 RegSetValueExW(HKEY hKey,
4948 LPCWSTR lpValueName,
4949 DWORD Reserved,
4950 DWORD dwType,
4951 CONST BYTE* lpData,
4952 DWORD cbData)
4953 {
4954 UNICODE_STRING ValueName;
4955 HANDLE KeyHandle;
4956 NTSTATUS Status;
4957
4958 if (is_string(dwType) && (cbData != 0))
4959 {
4960 PWSTR pwsData = (PWSTR)lpData;
4961
4962 _SEH2_TRY
4963 {
4964 if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
4965 (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
4966 {
4967 /* Increment length if last character is not zero and next is zero */
4968 cbData += sizeof(WCHAR);
4969 }
4970 }
4971 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4972 {
4973 _SEH2_YIELD(return ERROR_NOACCESS);
4974 }
4975 _SEH2_END;
4976 }
4977
4978 Status = MapDefaultKey(&KeyHandle,
4979 hKey);
4980 if (!NT_SUCCESS(Status))
4981 {
4982 return RtlNtStatusToDosError(Status);
4983 }
4984
4985 RtlInitUnicodeString(&ValueName, lpValueName);
4986
4987 Status = NtSetValueKey(KeyHandle,
4988 &ValueName,
4989 0,
4990 dwType,
4991 (PVOID)lpData,
4992 (ULONG)cbData);
4993
4994 ClosePredefKey(KeyHandle);
4995
4996 if (!NT_SUCCESS(Status))
4997 {
4998 return RtlNtStatusToDosError(Status);
4999 }
5000
5001 return ERROR_SUCCESS;
5002 }
5003
5004
5005 /************************************************************************
5006 * RegSetValueA
5007 *
5008 * @implemented
5009 */
5010 LONG WINAPI
5011 RegSetValueA(HKEY hKeyOriginal,
5012 LPCSTR lpSubKey,
5013 DWORD dwType,
5014 LPCSTR lpData,
5015 DWORD cbData)
5016 {
5017 HKEY subkey;
5018 HANDLE hKey;
5019 DWORD ret;
5020 NTSTATUS Status;
5021
5022 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData );
5023
5024 if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER;
5025
5026 Status = MapDefaultKey(&hKey, hKeyOriginal);
5027 if (!NT_SUCCESS(Status))
5028 {
5029 return RtlNtStatusToDosError (Status);
5030 }
5031 subkey = hKey;
5032
5033 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
5034 {
5035 ret = RegCreateKeyA(hKey, lpSubKey, &subkey);
5036 if (ret != ERROR_SUCCESS)
5037 goto Cleanup;
5038 }
5039
5040 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 );
5041 if (subkey != hKey)
5042 RegCloseKey(subkey);
5043
5044 Cleanup:
5045 ClosePredefKey(hKey);
5046
5047 return ret;
5048 }
5049
5050
5051 /************************************************************************
5052 * RegSetValueW
5053 *
5054 * @implemented
5055 */
5056 LONG WINAPI
5057 RegSetValueW(HKEY hKeyOriginal,
5058 LPCWSTR lpSubKey,
5059 DWORD dwType,
5060 LPCWSTR lpData,
5061 DWORD cbData)
5062 {
5063 HKEY subkey;
5064 HANDLE hKey;
5065 DWORD ret;
5066 NTSTATUS Status;
5067
5068 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData );
5069
5070 if (dwType != REG_SZ || !lpData)
5071 return ERROR_INVALID_PARAMETER;
5072
5073 Status = MapDefaultKey(&hKey,
5074 hKeyOriginal);
5075 if (!NT_SUCCESS(Status))
5076 {
5077 return RtlNtStatusToDosError(Status);
5078 }
5079 subkey = hKey;
5080
5081 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
5082 {
5083 ret = RegCreateKeyW(hKey, lpSubKey, &subkey);
5084 if (ret != ERROR_SUCCESS)
5085 goto Cleanup;
5086 }
5087
5088 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData,
5089 (wcslen( lpData ) + 1) * sizeof(WCHAR) );
5090 if (subkey != hKey)
5091 RegCloseKey(subkey);
5092
5093 Cleanup:
5094 ClosePredefKey(hKey);
5095
5096 return ret;
5097 }
5098
5099
5100 /************************************************************************
5101 * RegUnLoadKeyA
5102 *
5103 * @implemented
5104 */
5105 LONG WINAPI
5106 RegUnLoadKeyA(HKEY hKey,
5107 LPCSTR lpSubKey)
5108 {
5109 UNICODE_STRING KeyName;
5110 DWORD ErrorCode;
5111
5112 RtlCreateUnicodeStringFromAsciiz(&KeyName,
5113 (LPSTR)lpSubKey);
5114
5115 ErrorCode = RegUnLoadKeyW(hKey,
5116 KeyName.Buffer);
5117
5118 RtlFreeUnicodeString (&KeyName);
5119
5120 return ErrorCode;
5121 }
5122
5123
5124 /************************************************************************
5125 * RegUnLoadKeyW
5126 *
5127 * @implemented
5128 */
5129 LONG WINAPI
5130 RegUnLoadKeyW(HKEY hKey,
5131 LPCWSTR lpSubKey)
5132 {
5133 OBJECT_ATTRIBUTES ObjectAttributes;
5134 UNICODE_STRING KeyName;
5135 HANDLE KeyHandle;
5136 NTSTATUS Status;
5137
5138 if (hKey == HKEY_PERFORMANCE_DATA)
5139 {
5140 return ERROR_INVALID_HANDLE;
5141 }
5142
5143 Status = MapDefaultKey(&KeyHandle, hKey);
5144 if (!NT_SUCCESS(Status))
5145 {
5146 return RtlNtStatusToDosError(Status);
5147 }
5148
5149 RtlInitUnicodeString(&KeyName,
5150 (LPWSTR)lpSubKey);
5151
5152 InitializeObjectAttributes(&ObjectAttributes,
5153 &KeyName,
5154 OBJ_CASE_INSENSITIVE,
5155 KeyHandle,
5156 NULL);
5157
5158 Status = NtUnloadKey(&ObjectAttributes);
5159
5160 ClosePredefKey(KeyHandle);
5161
5162 if (!NT_SUCCESS(Status))
5163 {
5164 return RtlNtStatusToDosError(Status);
5165 }
5166
5167 return ERROR_SUCCESS;
5168 }
5169
5170
5171 /******************************************************************************
5172 * load_string [Internal]
5173 *
5174 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5175 * avoid importing user32, which is higher level than advapi32. Helper for
5176 * RegLoadMUIString.
5177 */
5178 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
5179 {
5180 HGLOBAL hMemory;
5181 HRSRC hResource;
5182 WCHAR *pString;
5183 int idxString;
5184
5185 /* Negative values have to be inverted. */
5186 if (HIWORD(resId) == 0xffff)
5187 resId = (UINT)(-((INT)resId));
5188
5189 /* Load the resource into memory and get a pointer to it. */
5190 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
5191 if (!hResource) return 0;
5192 hMemory = LoadResource(hModule, hResource);
5193 if (!hMemory) return 0;
5194 pString = LockResource(hMemory);
5195
5196 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5197 idxString = resId & 0xf;
5198 while (idxString--) pString += *pString + 1;
5199
5200 /* If no buffer is given, return length of the string. */
5201 if (!pwszBuffer) return *pString;
5202
5203 /* Else copy over the string, respecting the buffer size. */
5204 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
5205 if (cMaxChars >= 0)
5206 {
5207 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
5208 pwszBuffer[cMaxChars] = L'\0';
5209 }
5210
5211 return cMaxChars;
5212 }
5213
5214
5215 /************************************************************************
5216 * RegLoadMUIStringW
5217 *
5218 * @implemented
5219 */
5220 LONG WINAPI
5221 RegLoadMUIStringW(IN HKEY hKey,
5222 IN LPCWSTR pszValue OPTIONAL,
5223 OUT LPWSTR pszOutBuf,
5224 IN DWORD cbOutBuf,
5225 OUT LPDWORD pcbData OPTIONAL,
5226 IN DWORD Flags,
5227 IN LPCWSTR pszDirectory OPTIONAL)
5228 {
5229 DWORD dwValueType, cbData;
5230 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
5231 LONG result;
5232
5233 /* Parameter sanity checks. */
5234 if (!hKey || !pszOutBuf)
5235 return ERROR_INVALID_PARAMETER;
5236
5237 if (pszDirectory && *pszDirectory)
5238 {
5239 FIXME("BaseDir parameter not yet supported!\n");
5240 return ERROR_INVALID_PARAMETER;
5241 }
5242
5243 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5244 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
5245 if (result != ERROR_SUCCESS) goto cleanup;
5246 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
5247 {
5248 result = ERROR_FILE_NOT_FOUND;
5249 goto cleanup;
5250 }
5251 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5252 if (!pwszTempBuffer)
5253 {
5254 result = ERROR_NOT_ENOUGH_MEMORY;
5255 goto cleanup;
5256 }
5257 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
5258 if (result != ERROR_SUCCESS) goto cleanup;
5259
5260 /* Expand environment variables, if appropriate, or copy the original string over. */
5261 if (dwValueType == REG_EXPAND_SZ)
5262 {
5263 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
5264 if (!cbData) goto cleanup;
5265 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5266 if (!pwszExpandedBuffer)
5267 {
5268 result = ERROR_NOT_ENOUGH_MEMORY;
5269 goto cleanup;
5270 }
5271 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
5272 }
5273 else
5274 {
5275 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5276 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
5277 }
5278
5279 /* If the value references a resource based string, parse the value and load the string.
5280 * Else just copy over the original value. */
5281 result = ERROR_SUCCESS;
5282 if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
5283 {
5284 lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
5285 }
5286 else
5287 {
5288 WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
5289 UINT uiStringId;
5290 HMODULE hModule;
5291
5292 /* Format of the expanded value is 'path_to_dll,-resId' */
5293 if (!pComma || pComma[1] != L'-')
5294 {
5295 result = ERROR_BADKEY;
5296 goto cleanup;
5297 }
5298
5299 uiStringId = _wtoi(pComma+2);
5300 *pComma = L'\0';
5301
5302 hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
5303 if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
5304 result = ERROR_BADKEY;
5305 FreeLibrary(hModule);
5306 }
5307
5308 cleanup:
5309 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
5310 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
5311 return result;
5312 }
5313
5314
5315 /************************************************************************
5316 * RegLoadMUIStringA
5317 *
5318 * @implemented
5319 */
5320 LONG WINAPI
5321 RegLoadMUIStringA(IN HKEY hKey,
5322 IN LPCSTR pszValue OPTIONAL,
5323 OUT LPSTR pszOutBuf,
5324 IN DWORD cbOutBuf,
5325 OUT LPDWORD pcbData OPTIONAL,
5326 IN DWORD Flags,
5327 IN LPCSTR pszDirectory OPTIONAL)
5328 {
5329 UNICODE_STRING valueW, baseDirW;
5330 WCHAR *pwszBuffer;
5331 DWORD cbData = cbOutBuf * sizeof(WCHAR);
5332 LONG result;
5333
5334 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
5335 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
5336 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
5337 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
5338 {
5339 result = ERROR_NOT_ENOUGH_MEMORY;
5340 goto cleanup;
5341 }
5342
5343 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
5344 baseDirW.Buffer);
5345
5346 if (result == ERROR_SUCCESS)
5347 {
5348 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
5349 if (pcbData)
5350 *pcbData = cbData;
5351 }
5352
5353 cleanup:
5354 HeapFree(GetProcessHeap(), 0, pwszBuffer);
5355 RtlFreeUnicodeString(&baseDirW);
5356 RtlFreeUnicodeString(&valueW);
5357
5358 return result;
5359 }
5360
5361 /* EOF */