sync with trunk r46493
[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 #include <wine/debug.h>
18
19 WINE_DEFAULT_DEBUG_CHANNEL(reg);
20
21 /* DEFINES ******************************************************************/
22
23 #define MAX_DEFAULT_HANDLES 6
24 #define REG_MAX_NAME_SIZE 256
25 #define REG_MAX_DATA_SIZE 2048
26
27 /* GLOBALS ******************************************************************/
28
29 static RTL_CRITICAL_SECTION HandleTableCS;
30 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
31 static HANDLE ProcessHeap;
32 static BOOLEAN DefaultHandlesDisabled = FALSE;
33 static BOOLEAN DefaultHandleHKUDisabled = FALSE;
34 static BOOLEAN DllInitialized = FALSE; /* HACK */
35
36 /* PROTOTYPES ***************************************************************/
37
38 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
39 static VOID CloseDefaultKeys(VOID);
40 #define ClosePredefKey(Handle) \
41 if ((ULONG_PTR)Handle & 0x1) { \
42 NtClose(Handle); \
43 }
44 #define IsPredefKey(HKey) \
45 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
46 #define GetPredefKeyIndex(HKey) \
47 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
48
49 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
50 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
51 static NTSTATUS OpenUsersKey (PHANDLE KeyHandle);
52 static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
53
54
55 /* FUNCTIONS ****************************************************************/
56 /* check if value type needs string conversion (Ansi<->Unicode) */
57 __inline static int is_string( DWORD type )
58 {
59 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
60 }
61
62 /************************************************************************
63 * RegInitDefaultHandles
64 */
65 BOOL
66 RegInitialize(VOID)
67 {
68 TRACE("RegInitialize()\n");
69
70 /* Lazy init hack */
71 if (!DllInitialized)
72 {
73 ProcessHeap = RtlGetProcessHeap();
74 RtlZeroMemory(DefaultHandleTable,
75 MAX_DEFAULT_HANDLES * sizeof(HANDLE));
76 RtlInitializeCriticalSection(&HandleTableCS);
77
78 DllInitialized = TRUE;
79 }
80
81 return TRUE;
82 }
83
84
85 /************************************************************************
86 * RegInit
87 */
88 BOOL
89 RegCleanup(VOID)
90 {
91 TRACE("RegCleanup()\n");
92
93 CloseDefaultKeys();
94 RtlDeleteCriticalSection(&HandleTableCS);
95
96 return TRUE;
97 }
98
99
100 static NTSTATUS
101 OpenPredefinedKey(IN ULONG Index,
102 OUT HANDLE Handle)
103 {
104 NTSTATUS Status;
105
106 switch (Index)
107 {
108 case 0: /* HKEY_CLASSES_ROOT */
109 Status = OpenClassesRootKey (Handle);
110 break;
111
112 case 1: /* HKEY_CURRENT_USER */
113 Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
114 Handle);
115 break;
116
117 case 2: /* HKEY_LOCAL_MACHINE */
118 Status = OpenLocalMachineKey (Handle);
119 break;
120
121 case 3: /* HKEY_USERS */
122 Status = OpenUsersKey (Handle);
123 break;
124 #if 0
125 case 4: /* HKEY_PERFORMANCE_DATA */
126 Status = OpenPerformanceDataKey (Handle);
127 break;
128 #endif
129
130 case 5: /* HKEY_CURRENT_CONFIG */
131 Status = OpenCurrentConfigKey (Handle);
132 break;
133
134 case 6: /* HKEY_DYN_DATA */
135 Status = STATUS_NOT_IMPLEMENTED;
136 break;
137
138 default:
139 WARN("MapDefaultHandle() no handle creator\n");
140 Status = STATUS_INVALID_PARAMETER;
141 break;
142 }
143
144 return Status;
145 }
146
147
148 static NTSTATUS
149 MapDefaultKey(OUT PHANDLE RealKey,
150 IN HKEY Key)
151 {
152 PHANDLE Handle;
153 ULONG Index;
154 BOOLEAN DoOpen, DefDisabled;
155 NTSTATUS Status = STATUS_SUCCESS;
156
157 TRACE("MapDefaultKey (Key %x)\n", Key);
158
159 if (!IsPredefKey(Key))
160 {
161 *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
162 return STATUS_SUCCESS;
163 }
164
165 /* Handle special cases here */
166 Index = GetPredefKeyIndex(Key);
167 if (Index >= MAX_DEFAULT_HANDLES)
168 {
169 return STATUS_INVALID_PARAMETER;
170 }
171 RegInitialize(); /* HACK until delay-loading is implemented */
172 RtlEnterCriticalSection (&HandleTableCS);
173
174 if (Key == HKEY_CURRENT_USER)
175 DefDisabled = DefaultHandleHKUDisabled;
176 else
177 DefDisabled = DefaultHandlesDisabled;
178
179 if (!DefDisabled)
180 {
181 Handle = &DefaultHandleTable[Index];
182 DoOpen = (*Handle == NULL);
183 }
184 else
185 {
186 Handle = RealKey;
187 DoOpen = TRUE;
188 }
189
190 if (DoOpen)
191 {
192 /* create/open the default handle */
193 Status = OpenPredefinedKey(Index,
194 Handle);
195 }
196
197 if (NT_SUCCESS(Status))
198 {
199 if (!DefDisabled)
200 *RealKey = *Handle;
201 else
202 *(PULONG_PTR)Handle |= 0x1;
203 }
204
205 RtlLeaveCriticalSection (&HandleTableCS);
206
207 return Status;
208 }
209
210
211 static VOID
212 CloseDefaultKeys(VOID)
213 {
214 ULONG i;
215 RegInitialize(); /* HACK until delay-loading is implemented */
216 RtlEnterCriticalSection(&HandleTableCS);
217
218 for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
219 {
220 if (DefaultHandleTable[i] != NULL)
221 {
222 NtClose(DefaultHandleTable[i]);
223 DefaultHandleTable[i] = NULL;
224 }
225 }
226
227 RtlLeaveCriticalSection(&HandleTableCS);
228 }
229
230
231 static NTSTATUS
232 OpenClassesRootKey(PHANDLE KeyHandle)
233 {
234 OBJECT_ATTRIBUTES Attributes;
235 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
236
237 TRACE("OpenClassesRootKey()\n");
238
239 InitializeObjectAttributes(&Attributes,
240 &KeyName,
241 OBJ_CASE_INSENSITIVE,
242 NULL,
243 NULL);
244 return NtOpenKey(KeyHandle,
245 MAXIMUM_ALLOWED,
246 &Attributes);
247 }
248
249
250 static NTSTATUS
251 OpenLocalMachineKey(PHANDLE KeyHandle)
252 {
253 OBJECT_ATTRIBUTES Attributes;
254 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
255 NTSTATUS Status;
256
257 TRACE("OpenLocalMachineKey()\n");
258
259 InitializeObjectAttributes(&Attributes,
260 &KeyName,
261 OBJ_CASE_INSENSITIVE,
262 NULL,
263 NULL);
264 Status = NtOpenKey(KeyHandle,
265 MAXIMUM_ALLOWED,
266 &Attributes);
267
268 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
269
270 return Status;
271 }
272
273
274 static NTSTATUS
275 OpenUsersKey(PHANDLE KeyHandle)
276 {
277 OBJECT_ATTRIBUTES Attributes;
278 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User");
279
280 TRACE("OpenUsersKey()\n");
281
282 InitializeObjectAttributes(&Attributes,
283 &KeyName,
284 OBJ_CASE_INSENSITIVE,
285 NULL,
286 NULL);
287 return NtOpenKey(KeyHandle,
288 MAXIMUM_ALLOWED,
289 &Attributes);
290 }
291
292
293 static NTSTATUS
294 OpenCurrentConfigKey (PHANDLE KeyHandle)
295 {
296 OBJECT_ATTRIBUTES Attributes;
297 UNICODE_STRING KeyName =
298 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
299
300 TRACE("OpenCurrentConfigKey()\n");
301
302 InitializeObjectAttributes(&Attributes,
303 &KeyName,
304 OBJ_CASE_INSENSITIVE,
305 NULL,
306 NULL);
307 return NtOpenKey(KeyHandle,
308 MAXIMUM_ALLOWED,
309 &Attributes);
310 }
311
312
313 /************************************************************************
314 * RegDisablePredefinedCache
315 *
316 * @implemented
317 */
318 LONG WINAPI
319 RegDisablePredefinedCache(VOID)
320 {
321 RegInitialize(); /* HACK until delay-loading is implemented */
322 RtlEnterCriticalSection(&HandleTableCS);
323 DefaultHandleHKUDisabled = TRUE;
324 RtlLeaveCriticalSection(&HandleTableCS);
325 return ERROR_SUCCESS;
326 }
327
328
329 /************************************************************************
330 * RegDisablePredefinedCacheEx
331 *
332 * @implemented
333 */
334 LONG WINAPI
335 RegDisablePredefinedCacheEx(VOID)
336 {
337 RegInitialize(); /* HACK until delay-loading is implemented */
338 RtlEnterCriticalSection(&HandleTableCS);
339 DefaultHandlesDisabled = TRUE;
340 DefaultHandleHKUDisabled = TRUE;
341 RtlLeaveCriticalSection(&HandleTableCS);
342 return ERROR_SUCCESS;
343 }
344
345
346 /************************************************************************
347 * RegOverridePredefKey
348 *
349 * @implemented
350 */
351 LONG WINAPI
352 RegOverridePredefKey(IN HKEY hKey,
353 IN HKEY hNewHKey OPTIONAL)
354 {
355 LONG ErrorCode = ERROR_SUCCESS;
356
357 if ((hKey == HKEY_CLASSES_ROOT ||
358 hKey == HKEY_CURRENT_CONFIG ||
359 hKey == HKEY_CURRENT_USER ||
360 hKey == HKEY_LOCAL_MACHINE ||
361 hKey == HKEY_PERFORMANCE_DATA ||
362 hKey == HKEY_USERS) &&
363 !IsPredefKey(hNewHKey))
364 {
365 PHANDLE Handle;
366 ULONG Index;
367
368 Index = GetPredefKeyIndex(hKey);
369 Handle = &DefaultHandleTable[Index];
370
371 if (hNewHKey == NULL)
372 {
373 /* restore the default mapping */
374 NTSTATUS Status = OpenPredefinedKey(Index,
375 &hNewHKey);
376 if (!NT_SUCCESS(Status))
377 {
378 return RtlNtStatusToDosError(Status);
379 }
380
381 ASSERT(hNewHKey != NULL);
382 }
383 RegInitialize(); /* HACK until delay-loading is implemented */
384 RtlEnterCriticalSection(&HandleTableCS);
385
386 /* close the currently mapped handle if existing */
387 if (*Handle != NULL)
388 {
389 NtClose(*Handle);
390 }
391
392 /* update the mapping */
393 *Handle = hNewHKey;
394
395 RtlLeaveCriticalSection(&HandleTableCS);
396 }
397 else
398 ErrorCode = ERROR_INVALID_HANDLE;
399
400 return ErrorCode;
401 }
402
403
404 /************************************************************************
405 * RegCloseKey
406 *
407 * @implemented
408 */
409 LONG WINAPI
410 RegCloseKey(HKEY hKey)
411 {
412 NTSTATUS Status;
413
414 /* don't close null handle or a pseudo handle */
415 if ((!hKey) || (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000))
416 {
417 return ERROR_INVALID_HANDLE;
418 }
419
420 Status = NtClose(hKey);
421 if (!NT_SUCCESS(Status))
422 {
423 return RtlNtStatusToDosError(Status);
424 }
425
426 return ERROR_SUCCESS;
427 }
428
429
430 static NTSTATUS
431 RegpCopyTree(IN HKEY hKeySrc,
432 IN HKEY hKeyDest)
433 {
434 typedef struct
435 {
436 LIST_ENTRY ListEntry;
437 HANDLE hKeySrc;
438 HANDLE hKeyDest;
439 } REGP_COPY_KEYS, *PREGP_COPY_KEYS;
440
441 LIST_ENTRY copyQueueHead;
442 PREGP_COPY_KEYS copyKeys, newCopyKeys;
443 union
444 {
445 KEY_VALUE_FULL_INFORMATION *KeyValue;
446 KEY_NODE_INFORMATION *KeyNode;
447 PVOID Buffer;
448 } Info;
449 ULONG Index, BufferSizeRequired, BufferSize = 0x200;
450 NTSTATUS Status = STATUS_SUCCESS;
451 NTSTATUS Status2 = STATUS_SUCCESS;
452
453 InitializeListHead(&copyQueueHead);
454
455 Info.Buffer = RtlAllocateHeap(ProcessHeap,
456 0,
457 BufferSize);
458 if (Info.Buffer == NULL)
459 {
460 return STATUS_INSUFFICIENT_RESOURCES;
461 }
462
463 copyKeys = RtlAllocateHeap(ProcessHeap,
464 0,
465 sizeof(REGP_COPY_KEYS));
466 if (copyKeys != NULL)
467 {
468 copyKeys->hKeySrc = hKeySrc;
469 copyKeys->hKeyDest = hKeyDest;
470 InsertHeadList(&copyQueueHead,
471 &copyKeys->ListEntry);
472
473 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
474
475 do
476 {
477 copyKeys = CONTAINING_RECORD(copyQueueHead.Flink,
478 REGP_COPY_KEYS,
479 ListEntry);
480
481 /* enumerate all values and copy them */
482 Index = 0;
483 for (;;)
484 {
485 Status2 = NtEnumerateValueKey(copyKeys->hKeySrc,
486 Index,
487 KeyValueFullInformation,
488 Info.KeyValue,
489 BufferSize,
490 &BufferSizeRequired);
491 if (NT_SUCCESS(Status2))
492 {
493 UNICODE_STRING ValueName;
494 PVOID Data;
495
496 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
497 ValueName.Length = Info.KeyValue->NameLength;
498 ValueName.MaximumLength = ValueName.Length;
499 ValueName.Buffer = Info.KeyValue->Name;
500
501 Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset);
502
503 Status2 = NtSetValueKey(copyKeys->hKeyDest,
504 &ValueName,
505 Info.KeyValue->TitleIndex,
506 Info.KeyValue->Type,
507 Data,
508 Info.KeyValue->DataLength);
509
510 /* don't break, let's try to copy as many values as possible */
511 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
512 {
513 Status = Status2;
514 }
515
516 Index++;
517 }
518 else if (Status2 == STATUS_BUFFER_OVERFLOW)
519 {
520 PVOID Buffer;
521
522 ASSERT(BufferSize < BufferSizeRequired);
523
524 Buffer = RtlReAllocateHeap(ProcessHeap,
525 0,
526 Info.Buffer,
527 BufferSizeRequired);
528 if (Buffer != NULL)
529 {
530 Info.Buffer = Buffer;
531 /* try again */
532 }
533 else
534 {
535 /* don't break, let's try to copy as many values as possible */
536 Status2 = STATUS_INSUFFICIENT_RESOURCES;
537 Index++;
538
539 if (NT_SUCCESS(Status))
540 {
541 Status = Status2;
542 }
543 }
544 }
545 else
546 {
547 /* break to avoid an infinite loop in case of denied access or
548 other errors! */
549 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
550 {
551 Status = Status2;
552 }
553
554 break;
555 }
556 }
557
558 /* enumerate all subkeys and open and enqueue them */
559 Index = 0;
560 for (;;)
561 {
562 Status2 = NtEnumerateKey(copyKeys->hKeySrc,
563 Index,
564 KeyNodeInformation,
565 Info.KeyNode,
566 BufferSize,
567 &BufferSizeRequired);
568 if (NT_SUCCESS(Status2))
569 {
570 HANDLE KeyHandle, NewKeyHandle;
571 OBJECT_ATTRIBUTES ObjectAttributes;
572 UNICODE_STRING SubKeyName, ClassName;
573
574 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
575 SubKeyName.Length = Info.KeyNode->NameLength;
576 SubKeyName.MaximumLength = SubKeyName.Length;
577 SubKeyName.Buffer = Info.KeyNode->Name;
578 ClassName.Length = Info.KeyNode->ClassLength;
579 ClassName.MaximumLength = ClassName.Length;
580 ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset);
581
582 /* open the subkey with sufficient rights */
583
584 InitializeObjectAttributes(&ObjectAttributes,
585 &SubKeyName,
586 OBJ_CASE_INSENSITIVE,
587 copyKeys->hKeySrc,
588 NULL);
589
590 Status2 = NtOpenKey(&KeyHandle,
591 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
592 &ObjectAttributes);
593 if (NT_SUCCESS(Status2))
594 {
595 /* FIXME - attempt to query the security information */
596
597 InitializeObjectAttributes(&ObjectAttributes,
598 &SubKeyName,
599 OBJ_CASE_INSENSITIVE,
600 copyKeys->hKeyDest,
601 NULL);
602
603 Status2 = NtCreateKey(&NewKeyHandle,
604 KEY_ALL_ACCESS,
605 &ObjectAttributes,
606 Info.KeyNode->TitleIndex,
607 &ClassName,
608 0,
609 NULL);
610 if (NT_SUCCESS(Status2))
611 {
612 newCopyKeys = RtlAllocateHeap(ProcessHeap,
613 0,
614 sizeof(REGP_COPY_KEYS));
615 if (newCopyKeys != NULL)
616 {
617 /* save the handles and enqueue the subkey */
618 newCopyKeys->hKeySrc = KeyHandle;
619 newCopyKeys->hKeyDest = NewKeyHandle;
620 InsertTailList(&copyQueueHead,
621 &newCopyKeys->ListEntry);
622 }
623 else
624 {
625 NtClose(KeyHandle);
626 NtClose(NewKeyHandle);
627
628 Status2 = STATUS_INSUFFICIENT_RESOURCES;
629 }
630 }
631 else
632 {
633 NtClose(KeyHandle);
634 }
635 }
636
637 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
638 {
639 Status = Status2;
640 }
641
642 Index++;
643 }
644 else if (Status2 == STATUS_BUFFER_OVERFLOW)
645 {
646 PVOID Buffer;
647
648 ASSERT(BufferSize < BufferSizeRequired);
649
650 Buffer = RtlReAllocateHeap(ProcessHeap,
651 0,
652 Info.Buffer,
653 BufferSizeRequired);
654 if (Buffer != NULL)
655 {
656 Info.Buffer = Buffer;
657 /* try again */
658 }
659 else
660 {
661 /* don't break, let's try to copy as many keys as possible */
662 Status2 = STATUS_INSUFFICIENT_RESOURCES;
663 Index++;
664
665 if (NT_SUCCESS(Status))
666 {
667 Status = Status2;
668 }
669 }
670 }
671 else
672 {
673 /* break to avoid an infinite loop in case of denied access or
674 other errors! */
675 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
676 {
677 Status = Status2;
678 }
679
680 break;
681 }
682 }
683
684 /* close the handles and remove the entry from the list */
685 if (copyKeys->hKeySrc != hKeySrc)
686 {
687 NtClose(copyKeys->hKeySrc);
688 }
689 if (copyKeys->hKeyDest != hKeyDest)
690 {
691 NtClose(copyKeys->hKeyDest);
692 }
693
694 RemoveEntryList(&copyKeys->ListEntry);
695
696 RtlFreeHeap(ProcessHeap,
697 0,
698 copyKeys);
699 } while (!IsListEmpty(&copyQueueHead));
700 }
701 else
702 Status = STATUS_INSUFFICIENT_RESOURCES;
703
704 RtlFreeHeap(ProcessHeap,
705 0,
706 Info.Buffer);
707
708 return Status;
709 }
710
711
712 /************************************************************************
713 * RegCopyTreeW
714 *
715 * @implemented
716 */
717 LONG WINAPI
718 RegCopyTreeW(IN HKEY hKeySrc,
719 IN LPCWSTR lpSubKey OPTIONAL,
720 IN HKEY hKeyDest)
721 {
722 HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
723 NTSTATUS Status;
724
725 Status = MapDefaultKey(&KeyHandle,
726 hKeySrc);
727 if (!NT_SUCCESS(Status))
728 {
729 return RtlNtStatusToDosError(Status);
730 }
731
732 Status = MapDefaultKey(&DestKeyHandle,
733 hKeyDest);
734 if (!NT_SUCCESS(Status))
735 {
736 goto Cleanup2;
737 }
738
739 if (lpSubKey != NULL)
740 {
741 OBJECT_ATTRIBUTES ObjectAttributes;
742 UNICODE_STRING SubKeyName;
743
744 RtlInitUnicodeString(&SubKeyName,
745 (LPWSTR)lpSubKey);
746
747 InitializeObjectAttributes(&ObjectAttributes,
748 &SubKeyName,
749 OBJ_CASE_INSENSITIVE,
750 KeyHandle,
751 NULL);
752
753 Status = NtOpenKey(&SubKeyHandle,
754 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
755 &ObjectAttributes);
756 if (!NT_SUCCESS(Status))
757 {
758 goto Cleanup;
759 }
760
761 CurKey = SubKeyHandle;
762 }
763 else
764 CurKey = KeyHandle;
765
766 Status = RegpCopyTree(CurKey,
767 hKeyDest);
768
769 if (SubKeyHandle != NULL)
770 {
771 NtClose(SubKeyHandle);
772 }
773
774 Cleanup:
775 ClosePredefKey(DestKeyHandle);
776 Cleanup2:
777 ClosePredefKey(KeyHandle);
778
779 if (!NT_SUCCESS(Status))
780 {
781 return RtlNtStatusToDosError(Status);
782 }
783
784 return ERROR_SUCCESS;
785 }
786
787
788 /************************************************************************
789 * RegCopyTreeA
790 *
791 * @implemented
792 */
793 LONG WINAPI
794 RegCopyTreeA(IN HKEY hKeySrc,
795 IN LPCSTR lpSubKey OPTIONAL,
796 IN HKEY hKeyDest)
797 {
798 UNICODE_STRING SubKeyName = { 0, 0, NULL };
799 LONG Ret;
800
801 if (lpSubKey != NULL &&
802 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
803 (LPSTR)lpSubKey))
804 {
805 return ERROR_NOT_ENOUGH_MEMORY;
806 }
807
808 Ret = RegCopyTreeW(hKeySrc,
809 SubKeyName.Buffer,
810 hKeyDest);
811
812 RtlFreeUnicodeString(&SubKeyName);
813
814 return Ret;
815 }
816
817
818 /************************************************************************
819 * RegConnectRegistryA
820 *
821 * @implemented
822 */
823 LONG WINAPI
824 RegConnectRegistryA(IN LPCSTR lpMachineName,
825 IN HKEY hKey,
826 OUT PHKEY phkResult)
827 {
828 UNICODE_STRING MachineName = { 0, 0, NULL };
829 LONG Ret;
830
831 if (lpMachineName != NULL &&
832 !RtlCreateUnicodeStringFromAsciiz(&MachineName,
833 (LPSTR)lpMachineName))
834 {
835 return ERROR_NOT_ENOUGH_MEMORY;
836 }
837
838 Ret = RegConnectRegistryW(MachineName.Buffer,
839 hKey,
840 phkResult);
841
842 RtlFreeUnicodeString(&MachineName);
843
844 return Ret;
845 }
846
847
848 /************************************************************************
849 * RegConnectRegistryW
850 *
851 * @unimplemented
852 */
853 LONG WINAPI
854 RegConnectRegistryW(LPCWSTR lpMachineName,
855 HKEY hKey,
856 PHKEY phkResult)
857 {
858 LONG ret;
859
860 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
861
862 if (!lpMachineName || !*lpMachineName)
863 {
864 /* Use the local machine name */
865 ret = RegOpenKeyW( hKey, NULL, phkResult );
866 }
867 else
868 {
869 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
870 DWORD len = sizeof(compName) / sizeof(WCHAR);
871
872 /* MSDN says lpMachineName must start with \\ : not so */
873 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
874 lpMachineName += 2;
875
876 if (GetComputerNameW(compName, &len))
877 {
878 if (!_wcsicmp(lpMachineName, compName))
879 ret = RegOpenKeyW(hKey, NULL, phkResult);
880 else
881 {
882 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
883 ret = ERROR_BAD_NETPATH;
884 }
885 }
886 else
887 ret = GetLastError();
888 }
889
890 return ret;
891 }
892
893
894 /************************************************************************
895 * CreateNestedKey
896 *
897 * Create key and all necessary intermediate keys
898 */
899 static NTSTATUS
900 CreateNestedKey(PHKEY KeyHandle,
901 POBJECT_ATTRIBUTES ObjectAttributes,
902 PUNICODE_STRING ClassString,
903 DWORD dwOptions,
904 REGSAM samDesired,
905 DWORD *lpdwDisposition)
906 {
907 OBJECT_ATTRIBUTES LocalObjectAttributes;
908 UNICODE_STRING LocalKeyName;
909 ULONG Disposition;
910 NTSTATUS Status;
911 ULONG FullNameLength;
912 ULONG Length;
913 PWCHAR Ptr;
914 HANDLE LocalKeyHandle;
915
916 Status = NtCreateKey((PHANDLE) KeyHandle,
917 samDesired,
918 ObjectAttributes,
919 0,
920 ClassString,
921 dwOptions,
922 (PULONG)lpdwDisposition);
923 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
924 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
925 return Status;
926
927 /* Copy object attributes */
928 RtlCopyMemory(&LocalObjectAttributes,
929 ObjectAttributes,
930 sizeof(OBJECT_ATTRIBUTES));
931 RtlCreateUnicodeString(&LocalKeyName,
932 ObjectAttributes->ObjectName->Buffer);
933 LocalObjectAttributes.ObjectName = &LocalKeyName;
934 FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
935
936 LocalKeyHandle = NULL;
937
938 /* Remove the last part of the key name and try to create the key again. */
939 while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
940 {
941 Ptr = wcsrchr(LocalKeyName.Buffer, '\\');
942 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
943 {
944 Status = STATUS_UNSUCCESSFUL;
945 break;
946 }
947
948 *Ptr = (WCHAR)0;
949 LocalKeyName.Length = wcslen(LocalKeyName.Buffer) * sizeof(WCHAR);
950
951 Status = NtCreateKey(&LocalKeyHandle,
952 KEY_CREATE_SUB_KEY,
953 &LocalObjectAttributes,
954 0,
955 NULL,
956 0,
957 &Disposition);
958 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
959 }
960
961 if (!NT_SUCCESS(Status))
962 {
963 RtlFreeUnicodeString(&LocalKeyName);
964 return Status;
965 }
966
967 /* Add removed parts of the key name and create them too. */
968 Length = wcslen(LocalKeyName.Buffer);
969 while (TRUE)
970 {
971 if (LocalKeyHandle)
972 NtClose (LocalKeyHandle);
973
974 LocalKeyName.Buffer[Length] = L'\\';
975 Length = wcslen (LocalKeyName.Buffer);
976 LocalKeyName.Length = Length * sizeof(WCHAR);
977
978 if (Length == FullNameLength)
979 {
980 Status = NtCreateKey((PHANDLE) KeyHandle,
981 samDesired,
982 ObjectAttributes,
983 0,
984 ClassString,
985 dwOptions,
986 (PULONG)lpdwDisposition);
987 break;
988 }
989
990 Status = NtCreateKey(&LocalKeyHandle,
991 KEY_CREATE_SUB_KEY,
992 &LocalObjectAttributes,
993 0,
994 NULL,
995 0,
996 &Disposition);
997 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
998 if (!NT_SUCCESS(Status))
999 break;
1000 }
1001
1002 RtlFreeUnicodeString(&LocalKeyName);
1003
1004 return Status;
1005 }
1006
1007
1008 /************************************************************************
1009 * RegCreateKeyExA
1010 *
1011 * @implemented
1012 */
1013 LONG WINAPI
1014 RegCreateKeyExA(HKEY hKey,
1015 LPCSTR lpSubKey,
1016 DWORD Reserved,
1017 LPSTR lpClass,
1018 DWORD dwOptions,
1019 REGSAM samDesired,
1020 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1021 PHKEY phkResult,
1022 LPDWORD lpdwDisposition)
1023 {
1024 UNICODE_STRING SubKeyString;
1025 UNICODE_STRING ClassString;
1026 OBJECT_ATTRIBUTES Attributes;
1027 HANDLE ParentKey;
1028 NTSTATUS Status;
1029
1030 TRACE("RegCreateKeyExA() called\n");
1031
1032 if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
1033 return ERROR_INVALID_USER_BUFFER;
1034
1035 /* get the real parent key */
1036 Status = MapDefaultKey(&ParentKey,
1037 hKey);
1038 if (!NT_SUCCESS(Status))
1039 {
1040 return RtlNtStatusToDosError(Status);
1041 }
1042
1043 TRACE("ParentKey %p\n", ParentKey);
1044
1045 if (lpClass != NULL)
1046 {
1047 RtlCreateUnicodeStringFromAsciiz(&ClassString,
1048 lpClass);
1049 }
1050
1051 RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
1052 (LPSTR)lpSubKey);
1053 InitializeObjectAttributes(&Attributes,
1054 &SubKeyString,
1055 OBJ_CASE_INSENSITIVE,
1056 (HANDLE)ParentKey,
1057 lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
1058 Status = CreateNestedKey(phkResult,
1059 &Attributes,
1060 (lpClass == NULL)? NULL : &ClassString,
1061 dwOptions,
1062 samDesired,
1063 lpdwDisposition);
1064 RtlFreeUnicodeString(&SubKeyString);
1065 if (lpClass != NULL)
1066 {
1067 RtlFreeUnicodeString(&ClassString);
1068 }
1069
1070 ClosePredefKey(ParentKey);
1071
1072 TRACE("Status %x\n", Status);
1073 if (!NT_SUCCESS(Status))
1074 {
1075 return RtlNtStatusToDosError(Status);
1076 }
1077
1078 return ERROR_SUCCESS;
1079 }
1080
1081
1082 /************************************************************************
1083 * RegCreateKeyExW
1084 *
1085 * @implemented
1086 */
1087 LONG WINAPI
1088 RegCreateKeyExW(HKEY hKey,
1089 LPCWSTR lpSubKey,
1090 DWORD Reserved,
1091 LPWSTR lpClass,
1092 DWORD dwOptions,
1093 REGSAM samDesired,
1094 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1095 PHKEY phkResult,
1096 LPDWORD lpdwDisposition)
1097 {
1098 UNICODE_STRING SubKeyString;
1099 UNICODE_STRING ClassString;
1100 OBJECT_ATTRIBUTES Attributes;
1101 HANDLE ParentKey;
1102 NTSTATUS Status;
1103
1104 TRACE("RegCreateKeyExW() called\n");
1105
1106 if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
1107 return ERROR_INVALID_USER_BUFFER;
1108
1109 /* get the real parent key */
1110 Status = MapDefaultKey(&ParentKey,
1111 hKey);
1112 if (!NT_SUCCESS(Status))
1113 {
1114 return RtlNtStatusToDosError(Status);
1115 }
1116
1117 TRACE("ParentKey %p\n", ParentKey);
1118
1119 RtlInitUnicodeString(&ClassString,
1120 lpClass);
1121 RtlInitUnicodeString(&SubKeyString,
1122 lpSubKey);
1123 InitializeObjectAttributes(&Attributes,
1124 &SubKeyString,
1125 OBJ_CASE_INSENSITIVE,
1126 (HANDLE)ParentKey,
1127 lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
1128 Status = CreateNestedKey(phkResult,
1129 &Attributes,
1130 (lpClass == NULL)? NULL : &ClassString,
1131 dwOptions,
1132 samDesired,
1133 lpdwDisposition);
1134
1135 ClosePredefKey(ParentKey);
1136
1137 TRACE("Status %x\n", Status);
1138 if (!NT_SUCCESS(Status))
1139 {
1140 return RtlNtStatusToDosError(Status);
1141 }
1142
1143 return ERROR_SUCCESS;
1144 }
1145
1146
1147 /************************************************************************
1148 * RegCreateKeyA
1149 *
1150 * @implemented
1151 */
1152 LONG WINAPI
1153 RegCreateKeyA(HKEY hKey,
1154 LPCSTR lpSubKey,
1155 PHKEY phkResult)
1156 {
1157 return RegCreateKeyExA(hKey,
1158 lpSubKey,
1159 0,
1160 NULL,
1161 0,
1162 MAXIMUM_ALLOWED,
1163 NULL,
1164 phkResult,
1165 NULL);
1166 }
1167
1168
1169 /************************************************************************
1170 * RegCreateKeyW
1171 *
1172 * @implemented
1173 */
1174 LONG WINAPI
1175 RegCreateKeyW(HKEY hKey,
1176 LPCWSTR lpSubKey,
1177 PHKEY phkResult)
1178 {
1179 return RegCreateKeyExW(hKey,
1180 lpSubKey,
1181 0,
1182 NULL,
1183 0,
1184 MAXIMUM_ALLOWED,
1185 NULL,
1186 phkResult,
1187 NULL);
1188 }
1189
1190
1191 /************************************************************************
1192 * RegDeleteKeyA
1193 *
1194 * @implemented
1195 */
1196 LONG WINAPI
1197 RegDeleteKeyA(HKEY hKey,
1198 LPCSTR lpSubKey)
1199 {
1200 OBJECT_ATTRIBUTES ObjectAttributes;
1201 UNICODE_STRING SubKeyName;
1202 HANDLE ParentKey;
1203 HANDLE TargetKey;
1204 NTSTATUS Status;
1205
1206 /* Make sure we got a subkey */
1207 if (!lpSubKey)
1208 {
1209 /* Fail */
1210 return ERROR_INVALID_PARAMETER;
1211 }
1212
1213 Status = MapDefaultKey(&ParentKey,
1214 hKey);
1215 if (!NT_SUCCESS(Status))
1216 {
1217 return RtlNtStatusToDosError(Status);
1218 }
1219
1220 RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1221 (LPSTR)lpSubKey);
1222 InitializeObjectAttributes(&ObjectAttributes,
1223 &SubKeyName,
1224 OBJ_CASE_INSENSITIVE,
1225 ParentKey,
1226 NULL);
1227
1228 Status = NtOpenKey(&TargetKey,
1229 DELETE,
1230 &ObjectAttributes);
1231 RtlFreeUnicodeString(&SubKeyName);
1232 if (!NT_SUCCESS(Status))
1233 {
1234 goto Cleanup;
1235 }
1236
1237 Status = NtDeleteKey(TargetKey);
1238 NtClose (TargetKey);
1239
1240 Cleanup:
1241 ClosePredefKey(ParentKey);
1242
1243 if (!NT_SUCCESS(Status))
1244 {
1245 return RtlNtStatusToDosError(Status);
1246 }
1247
1248 return ERROR_SUCCESS;
1249 }
1250
1251
1252 /************************************************************************
1253 * RegDeleteKeyW
1254 *
1255 * @implemented
1256 */
1257 LONG WINAPI
1258 RegDeleteKeyW(HKEY hKey,
1259 LPCWSTR lpSubKey)
1260 {
1261 OBJECT_ATTRIBUTES ObjectAttributes;
1262 UNICODE_STRING SubKeyName;
1263 HANDLE ParentKey;
1264 HANDLE TargetKey;
1265 NTSTATUS Status;
1266
1267 /* Make sure we got a subkey */
1268 if (!lpSubKey)
1269 {
1270 /* Fail */
1271 return ERROR_INVALID_PARAMETER;
1272 }
1273
1274 Status = MapDefaultKey(&ParentKey,
1275 hKey);
1276 if (!NT_SUCCESS(Status))
1277 {
1278 return RtlNtStatusToDosError(Status);
1279 }
1280
1281 RtlInitUnicodeString(&SubKeyName,
1282 (LPWSTR)lpSubKey);
1283 InitializeObjectAttributes(&ObjectAttributes,
1284 &SubKeyName,
1285 OBJ_CASE_INSENSITIVE,
1286 ParentKey,
1287 NULL);
1288 Status = NtOpenKey(&TargetKey,
1289 DELETE,
1290 &ObjectAttributes);
1291 if (!NT_SUCCESS(Status))
1292 {
1293 goto Cleanup;
1294 }
1295
1296 Status = NtDeleteKey(TargetKey);
1297 NtClose(TargetKey);
1298
1299 Cleanup:
1300 ClosePredefKey(ParentKey);
1301
1302 if (!NT_SUCCESS(Status))
1303 {
1304 return RtlNtStatusToDosError(Status);
1305 }
1306
1307 return ERROR_SUCCESS;
1308 }
1309
1310
1311 /************************************************************************
1312 * RegDeleteKeyExA
1313 *
1314 * @unimplemented
1315 */
1316 LONG
1317 WINAPI
1318 RegDeleteKeyExA(HKEY hKey,
1319 LPCSTR lpSubKey,
1320 REGSAM samDesired,
1321 DWORD Reserved)
1322 {
1323 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1324 return ERROR_CALL_NOT_IMPLEMENTED;
1325 }
1326
1327
1328 /************************************************************************
1329 * RegDeleteKeyExW
1330 *
1331 * @unimplemented
1332 */
1333 LONG
1334 WINAPI
1335 RegDeleteKeyExW(HKEY hKey,
1336 LPCWSTR lpSubKey,
1337 REGSAM samDesired,
1338 DWORD Reserved)
1339 {
1340 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1341 return ERROR_CALL_NOT_IMPLEMENTED;
1342 }
1343
1344
1345 /************************************************************************
1346 * RegDeleteKeyValueW
1347 *
1348 * @implemented
1349 */
1350 LONG WINAPI
1351 RegDeleteKeyValueW(IN HKEY hKey,
1352 IN LPCWSTR lpSubKey OPTIONAL,
1353 IN LPCWSTR lpValueName OPTIONAL)
1354 {
1355 UNICODE_STRING ValueName;
1356 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1357 NTSTATUS Status;
1358
1359 Status = MapDefaultKey(&KeyHandle,
1360 hKey);
1361 if (!NT_SUCCESS(Status))
1362 {
1363 return RtlNtStatusToDosError(Status);
1364 }
1365
1366 if (lpSubKey != NULL)
1367 {
1368 OBJECT_ATTRIBUTES ObjectAttributes;
1369 UNICODE_STRING SubKeyName;
1370
1371 RtlInitUnicodeString(&SubKeyName,
1372 (LPWSTR)lpSubKey);
1373
1374 InitializeObjectAttributes(&ObjectAttributes,
1375 &SubKeyName,
1376 OBJ_CASE_INSENSITIVE,
1377 KeyHandle,
1378 NULL);
1379
1380 Status = NtOpenKey(&SubKeyHandle,
1381 KEY_SET_VALUE,
1382 &ObjectAttributes);
1383 if (!NT_SUCCESS(Status))
1384 {
1385 goto Cleanup;
1386 }
1387
1388 CurKey = SubKeyHandle;
1389 }
1390 else
1391 CurKey = KeyHandle;
1392
1393 RtlInitUnicodeString(&ValueName,
1394 (LPWSTR)lpValueName);
1395
1396 Status = NtDeleteValueKey(CurKey,
1397 &ValueName);
1398
1399 if (SubKeyHandle != NULL)
1400 {
1401 NtClose(SubKeyHandle);
1402 }
1403
1404 Cleanup:
1405 ClosePredefKey(KeyHandle);
1406
1407 if (!NT_SUCCESS(Status))
1408 {
1409 return RtlNtStatusToDosError(Status);
1410 }
1411
1412 return ERROR_SUCCESS;
1413 }
1414
1415
1416 /************************************************************************
1417 * RegDeleteKeyValueA
1418 *
1419 * @implemented
1420 */
1421 LONG WINAPI
1422 RegDeleteKeyValueA(IN HKEY hKey,
1423 IN LPCSTR lpSubKey OPTIONAL,
1424 IN LPCSTR lpValueName OPTIONAL)
1425 {
1426 UNICODE_STRING SubKey = { 0, 0, NULL }, ValueName = { 0, 0, NULL };
1427 LONG Ret;
1428
1429 if (lpSubKey != NULL &&
1430 !RtlCreateUnicodeStringFromAsciiz(&SubKey,
1431 (LPSTR)lpSubKey))
1432 {
1433 return ERROR_NOT_ENOUGH_MEMORY;
1434 }
1435
1436 if (lpValueName != NULL &&
1437 !RtlCreateUnicodeStringFromAsciiz(&ValueName,
1438 (LPSTR)lpValueName))
1439 {
1440 RtlFreeUnicodeString(&SubKey);
1441 return ERROR_NOT_ENOUGH_MEMORY;
1442 }
1443
1444 Ret = RegDeleteKeyValueW(hKey,
1445 SubKey.Buffer,
1446 SubKey.Buffer);
1447
1448 RtlFreeUnicodeString(&SubKey);
1449 RtlFreeUnicodeString(&ValueName);
1450
1451 return Ret;
1452 }
1453
1454 #if 0
1455 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1456 static NTSTATUS
1457 RegpDeleteTree(IN HKEY hKey)
1458 {
1459 typedef struct
1460 {
1461 LIST_ENTRY ListEntry;
1462 HANDLE KeyHandle;
1463 } REGP_DEL_KEYS, *PREG_DEL_KEYS;
1464
1465 LIST_ENTRY delQueueHead;
1466 PREG_DEL_KEYS delKeys, newDelKeys;
1467 HANDLE ProcessHeap;
1468 ULONG BufferSize;
1469 PKEY_BASIC_INFORMATION BasicInfo;
1470 PREG_DEL_KEYS KeyDelRoot;
1471 NTSTATUS Status = STATUS_SUCCESS;
1472 NTSTATUS Status2 = STATUS_SUCCESS;
1473
1474 InitializeListHead(&delQueueHead);
1475
1476 ProcessHeap = RtlGetProcessHeap();
1477
1478 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1479 structure for the root key, we only do that for subkeys as we need to
1480 allocate REGP_DEL_KEYS structures anyway! */
1481 KeyDelRoot = RtlAllocateHeap(ProcessHeap,
1482 0,
1483 sizeof(REGP_DEL_KEYS));
1484 if (KeyDelRoot != NULL)
1485 {
1486 KeyDelRoot->KeyHandle = hKey;
1487 InsertTailList(&delQueueHead,
1488 &KeyDelRoot->ListEntry);
1489
1490 do
1491 {
1492 delKeys = CONTAINING_RECORD(delQueueHead.Flink,
1493 REGP_DEL_KEYS,
1494 ListEntry);
1495
1496 BufferSize = 0;
1497 BasicInfo = NULL;
1498 newDelKeys = NULL;
1499
1500 ReadFirstSubKey:
1501 /* check if this key contains subkeys and delete them first by queuing
1502 them at the head of the list */
1503 Status2 = NtEnumerateKey(delKeys->KeyHandle,
1504 0,
1505 KeyBasicInformation,
1506 BasicInfo,
1507 BufferSize,
1508 &BufferSize);
1509
1510 if (NT_SUCCESS(Status2))
1511 {
1512 OBJECT_ATTRIBUTES ObjectAttributes;
1513 UNICODE_STRING SubKeyName;
1514
1515 ASSERT(newDelKeys != NULL);
1516 ASSERT(BasicInfo != NULL);
1517
1518 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1519 SubKeyName.Length = BasicInfo->NameLength;
1520 SubKeyName.MaximumLength = BasicInfo->NameLength;
1521 SubKeyName.Buffer = BasicInfo->Name;
1522
1523 InitializeObjectAttributes(&ObjectAttributes,
1524 &SubKeyName,
1525 OBJ_CASE_INSENSITIVE,
1526 delKeys->KeyHandle,
1527 NULL);
1528
1529 /* open the subkey */
1530 Status2 = NtOpenKey(&newDelKeys->KeyHandle,
1531 DELETE | KEY_ENUMERATE_SUB_KEYS,
1532 &ObjectAttributes);
1533 if (!NT_SUCCESS(Status2))
1534 {
1535 goto SubKeyFailure;
1536 }
1537
1538 /* enqueue this key to the head of the deletion queue */
1539 InsertHeadList(&delQueueHead,
1540 &newDelKeys->ListEntry);
1541
1542 /* try again from the head of the list */
1543 continue;
1544 }
1545 else
1546 {
1547 if (Status2 == STATUS_BUFFER_TOO_SMALL)
1548 {
1549 newDelKeys = RtlAllocateHeap(ProcessHeap,
1550 0,
1551 BufferSize + sizeof(REGP_DEL_KEYS));
1552 if (newDelKeys != NULL)
1553 {
1554 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1555
1556 /* try again */
1557 goto ReadFirstSubKey;
1558 }
1559 else
1560 {
1561 /* don't break, let's try to delete as many keys as possible */
1562 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1563 goto SubKeyFailureNoFree;
1564 }
1565 }
1566 else if (Status2 == STATUS_BUFFER_OVERFLOW)
1567 {
1568 PREG_DEL_KEYS newDelKeys2;
1569
1570 ASSERT(newDelKeys != NULL);
1571
1572 /* we need more memory to query the key name */
1573 newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
1574 0,
1575 newDelKeys,
1576 BufferSize + sizeof(REGP_DEL_KEYS));
1577 if (newDelKeys2 != NULL)
1578 {
1579 newDelKeys = newDelKeys2;
1580 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1581
1582 /* try again */
1583 goto ReadFirstSubKey;
1584 }
1585 else
1586 {
1587 /* don't break, let's try to delete as many keys as possible */
1588 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1589 }
1590 }
1591 else if (Status2 == STATUS_NO_MORE_ENTRIES)
1592 {
1593 /* in some race conditions where another thread would delete
1594 the same tree at the same time, newDelKeys could actually
1595 be != NULL! */
1596 if (newDelKeys != NULL)
1597 {
1598 RtlFreeHeap(ProcessHeap,
1599 0,
1600 newDelKeys);
1601 }
1602 break;
1603 }
1604
1605 SubKeyFailure:
1606 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1607 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1608 if (newDelKeys != NULL)
1609 {
1610 RtlFreeHeap(ProcessHeap,
1611 0,
1612 newDelKeys);
1613 }
1614
1615 SubKeyFailureNoFree:
1616 /* don't break, let's try to delete as many keys as possible */
1617 if (NT_SUCCESS(Status))
1618 {
1619 Status = Status2;
1620 }
1621 }
1622
1623 Status2 = NtDeleteKey(delKeys->KeyHandle);
1624
1625 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1626
1627 if (!NT_SUCCESS(Status2))
1628 {
1629 /* close the key handle so we don't leak handles for keys we were
1630 unable to delete. But only do this for handles not supplied
1631 by the caller! */
1632
1633 if (delKeys->KeyHandle != hKey)
1634 {
1635 NtClose(delKeys->KeyHandle);
1636 }
1637
1638 if (NT_SUCCESS(Status))
1639 {
1640 /* don't break, let's try to delete as many keys as possible */
1641 Status = Status2;
1642 }
1643 }
1644
1645 /* remove the entry from the list */
1646 RemoveEntryList(&delKeys->ListEntry);
1647
1648 RtlFreeHeap(ProcessHeap,
1649 0,
1650 delKeys);
1651 } while (!IsListEmpty(&delQueueHead));
1652 }
1653 else
1654 Status = STATUS_INSUFFICIENT_RESOURCES;
1655
1656 return Status;
1657 }
1658
1659
1660 /************************************************************************
1661 * RegDeleteTreeW
1662 *
1663 * @implemented
1664 */
1665 LONG WINAPI
1666 RegDeleteTreeW(IN HKEY hKey,
1667 IN LPCWSTR lpSubKey OPTIONAL)
1668 {
1669 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1670 NTSTATUS Status;
1671
1672 Status = MapDefaultKey(&KeyHandle,
1673 hKey);
1674 if (!NT_SUCCESS(Status))
1675 {
1676 return RtlNtStatusToDosError(Status);
1677 }
1678
1679 if (lpSubKey != NULL)
1680 {
1681 OBJECT_ATTRIBUTES ObjectAttributes;
1682 UNICODE_STRING SubKeyName;
1683
1684 RtlInitUnicodeString(&SubKeyName,
1685 (LPWSTR)lpSubKey);
1686
1687 InitializeObjectAttributes(&ObjectAttributes,
1688 &SubKeyName,
1689 OBJ_CASE_INSENSITIVE,
1690 KeyHandle,
1691 NULL);
1692
1693 Status = NtOpenKey(&SubKeyHandle,
1694 DELETE | KEY_ENUMERATE_SUB_KEYS,
1695 &ObjectAttributes);
1696 if (!NT_SUCCESS(Status))
1697 {
1698 goto Cleanup;
1699 }
1700
1701 CurKey = SubKeyHandle;
1702 }
1703 else
1704 CurKey = KeyHandle;
1705
1706 Status = RegpDeleteTree(CurKey);
1707
1708 if (NT_SUCCESS(Status))
1709 {
1710 /* make sure we only close hKey (KeyHandle) when the caller specified a
1711 subkey, because the handle would be invalid already! */
1712 if (CurKey != KeyHandle)
1713 {
1714 ClosePredefKey(KeyHandle);
1715 }
1716
1717 return ERROR_SUCCESS;
1718 }
1719 else
1720 {
1721 /* make sure we close all handles we created! */
1722 if (SubKeyHandle != NULL)
1723 {
1724 NtClose(SubKeyHandle);
1725 }
1726
1727 Cleanup:
1728 ClosePredefKey(KeyHandle);
1729
1730 return RtlNtStatusToDosError(Status);
1731 }
1732 }
1733 #endif
1734
1735
1736 /************************************************************************
1737 * RegDeleteTreeW
1738 *
1739 * @implemented
1740 */
1741 LSTATUS
1742 WINAPI
1743 RegDeleteTreeW(HKEY hKey,
1744 LPCWSTR lpszSubKey)
1745 {
1746 LONG ret;
1747 DWORD dwMaxSubkeyLen, dwMaxValueLen;
1748 DWORD dwMaxLen, dwSize;
1749 NTSTATUS Status;
1750 HANDLE KeyHandle;
1751 HKEY hSubKey;
1752 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1753
1754 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
1755
1756 Status = MapDefaultKey(&KeyHandle,
1757 hKey);
1758 if (!NT_SUCCESS(Status))
1759 {
1760 return RtlNtStatusToDosError(Status);
1761 }
1762
1763 hSubKey = KeyHandle;
1764
1765 if(lpszSubKey)
1766 {
1767 ret = RegOpenKeyExW(KeyHandle, lpszSubKey, 0, KEY_READ, &hSubKey);
1768 if (ret)
1769 {
1770 ClosePredefKey(KeyHandle);
1771 return ret;
1772 }
1773 }
1774
1775 /* Get highest length for keys, values */
1776 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
1777 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
1778 if (ret) goto cleanup;
1779
1780 dwMaxSubkeyLen++;
1781 dwMaxValueLen++;
1782 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
1783 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
1784 {
1785 /* Name too big: alloc a buffer for it */
1786 if (!(lpszName = RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
1787 {
1788 ret = ERROR_NOT_ENOUGH_MEMORY;
1789 goto cleanup;
1790 }
1791 }
1792
1793
1794 /* Recursively delete all the subkeys */
1795 while (TRUE)
1796 {
1797 dwSize = dwMaxLen;
1798 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
1799 NULL, NULL, NULL)) break;
1800
1801 ret = RegDeleteTreeW(hSubKey, lpszName);
1802 if (ret) goto cleanup;
1803 }
1804
1805 if (lpszSubKey)
1806 ret = RegDeleteKeyW(KeyHandle, lpszSubKey);
1807 else
1808 while (TRUE)
1809 {
1810 dwSize = dwMaxLen;
1811 if (RegEnumValueW(KeyHandle, 0, lpszName, &dwSize,
1812 NULL, NULL, NULL, NULL)) break;
1813
1814 ret = RegDeleteValueW(KeyHandle, lpszName);
1815 if (ret) goto cleanup;
1816 }
1817
1818 cleanup:
1819 /* Free buffer if allocated */
1820 if (lpszName != szNameBuf)
1821 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName);
1822 if(lpszSubKey)
1823 RegCloseKey(hSubKey);
1824
1825 ClosePredefKey(KeyHandle);
1826
1827 return ret;
1828 }
1829
1830
1831 /************************************************************************
1832 * RegDeleteTreeA
1833 *
1834 * @implemented
1835 */
1836 LONG WINAPI
1837 RegDeleteTreeA(IN HKEY hKey,
1838 IN LPCSTR lpSubKey OPTIONAL)
1839 {
1840 UNICODE_STRING SubKeyName = { 0, 0, NULL };
1841 LONG Ret;
1842
1843 if (lpSubKey != NULL &&
1844 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1845 (LPSTR)lpSubKey))
1846 {
1847 return ERROR_NOT_ENOUGH_MEMORY;
1848 }
1849
1850 Ret = RegDeleteTreeW(hKey,
1851 SubKeyName.Buffer);
1852
1853 RtlFreeUnicodeString(&SubKeyName);
1854
1855 return Ret;
1856 }
1857
1858
1859 /************************************************************************
1860 * RegDisableReflectionKey
1861 *
1862 * @unimplemented
1863 */
1864 LONG WINAPI
1865 RegDisableReflectionKey(IN HKEY hBase)
1866 {
1867 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1868 return ERROR_CALL_NOT_IMPLEMENTED;
1869 }
1870
1871
1872 /************************************************************************
1873 * RegEnableReflectionKey
1874 *
1875 * @unimplemented
1876 */
1877 LONG WINAPI
1878 RegEnableReflectionKey(IN HKEY hBase)
1879 {
1880 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
1881 return ERROR_CALL_NOT_IMPLEMENTED;
1882 }
1883
1884
1885 /******************************************************************************
1886 * RegpApplyRestrictions [internal]
1887 *
1888 * Helper function for RegGetValueA/W.
1889 */
1890 static VOID
1891 RegpApplyRestrictions(DWORD dwFlags,
1892 DWORD dwType,
1893 DWORD cbData,
1894 PLONG ret)
1895 {
1896 /* Check if the type is restricted by the passed flags */
1897 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1898 {
1899 DWORD dwMask = 0;
1900
1901 switch (dwType)
1902 {
1903 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1904 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1905 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1906 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1907 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1908 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1909 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1910 }
1911
1912 if (dwFlags & dwMask)
1913 {
1914 /* Type is not restricted, check for size mismatch */
1915 if (dwType == REG_BINARY)
1916 {
1917 DWORD cbExpect = 0;
1918
1919 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1920 cbExpect = 4;
1921 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1922 cbExpect = 8;
1923
1924 if (cbExpect && cbData != cbExpect)
1925 *ret = ERROR_DATATYPE_MISMATCH;
1926 }
1927 }
1928 else *ret = ERROR_UNSUPPORTED_TYPE;
1929 }
1930 }
1931
1932
1933 /******************************************************************************
1934 * RegGetValueW [ADVAPI32.@]
1935 *
1936 * Retrieves the type and data for a value name associated with a key,
1937 * optionally expanding its content and restricting its type.
1938 *
1939 * PARAMS
1940 * hKey [I] Handle to an open key.
1941 * pszSubKey [I] Name of the subkey of hKey.
1942 * pszValue [I] Name of value under hKey/szSubKey to query.
1943 * dwFlags [I] Flags restricting the value type to retrieve.
1944 * pdwType [O] Destination for the values type, may be NULL.
1945 * pvData [O] Destination for the values content, may be NULL.
1946 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1947 * retrieve the whole content, including the trailing '\0'
1948 * for strings.
1949 *
1950 * RETURNS
1951 * Success: ERROR_SUCCESS
1952 * Failure: nonzero error code from Winerror.h
1953 *
1954 * NOTES
1955 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1956 * expanded and pdwType is set to REG_SZ instead.
1957 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1958 * without RRF_NOEXPAND is thus not allowed.
1959 * An exception is the case where RRF_RT_ANY is specified, because then
1960 * RRF_NOEXPAND is allowed.
1961 */
1962 LSTATUS WINAPI
1963 RegGetValueW(HKEY hKey,
1964 LPCWSTR pszSubKey,
1965 LPCWSTR pszValue,
1966 DWORD dwFlags,
1967 LPDWORD pdwType,
1968 PVOID pvData,
1969 LPDWORD pcbData)
1970 {
1971 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1972 PVOID pvBuf = NULL;
1973 LONG ret;
1974
1975 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1976 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1977 pvData, pcbData, cbData);
1978
1979 if (pvData && !pcbData)
1980 return ERROR_INVALID_PARAMETER;
1981 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1982 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1983 return ERROR_INVALID_PARAMETER;
1984
1985 if (pszSubKey && pszSubKey[0])
1986 {
1987 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1988 if (ret != ERROR_SUCCESS) return ret;
1989 }
1990
1991 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1992
1993 /* If we are going to expand we need to read in the whole the value even
1994 * if the passed buffer was too small as the expanded string might be
1995 * smaller than the unexpanded one and could fit into cbData bytes. */
1996 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1997 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1998 {
1999 do
2000 {
2001 HeapFree(GetProcessHeap(), 0, pvBuf);
2002
2003 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2004 if (!pvBuf)
2005 {
2006 ret = ERROR_NOT_ENOUGH_MEMORY;
2007 break;
2008 }
2009
2010 if (ret == ERROR_MORE_DATA || !pvData)
2011 ret = RegQueryValueExW(hKey, pszValue, NULL,
2012 &dwType, pvBuf, &cbData);
2013 else
2014 {
2015 /* Even if cbData was large enough we have to copy the
2016 * string since ExpandEnvironmentStrings can't handle
2017 * overlapping buffers. */
2018 CopyMemory(pvBuf, pvData, cbData);
2019 }
2020
2021 /* Both the type or the value itself could have been modified in
2022 * between so we have to keep retrying until the buffer is large
2023 * enough or we no longer have to expand the value. */
2024 }
2025 while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2026
2027 if (ret == ERROR_SUCCESS)
2028 {
2029 /* Recheck dwType in case it changed since the first call */
2030 if (dwType == REG_EXPAND_SZ)
2031 {
2032 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
2033 pcbData ? *pcbData : 0) * sizeof(WCHAR);
2034 dwType = REG_SZ;
2035 if (pvData && pcbData && cbData > *pcbData)
2036 ret = ERROR_MORE_DATA;
2037 }
2038 else if (pvData)
2039 CopyMemory(pvData, pvBuf, *pcbData);
2040 }
2041
2042 HeapFree(GetProcessHeap(), 0, pvBuf);
2043 }
2044
2045 if (pszSubKey && pszSubKey[0])
2046 RegCloseKey(hKey);
2047
2048 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2049
2050 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
2051 ZeroMemory(pvData, *pcbData);
2052
2053 if (pdwType)
2054 *pdwType = dwType;
2055
2056 if (pcbData)
2057 *pcbData = cbData;
2058
2059 return ret;
2060 }
2061
2062
2063 /******************************************************************************
2064 * RegGetValueA [ADVAPI32.@]
2065 *
2066 * See RegGetValueW.
2067 */
2068 LSTATUS WINAPI
2069 RegGetValueA(HKEY hKey,
2070 LPCSTR pszSubKey,
2071 LPCSTR pszValue,
2072 DWORD dwFlags,
2073 LPDWORD pdwType,
2074 PVOID pvData,
2075 LPDWORD pcbData)
2076 {
2077 DWORD dwType, cbData = pcbData ? *pcbData : 0;
2078 PVOID pvBuf = NULL;
2079 LONG ret;
2080
2081 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2082 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
2083 cbData);
2084
2085 if (pvData && !pcbData)
2086 return ERROR_INVALID_PARAMETER;
2087 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
2088 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
2089 return ERROR_INVALID_PARAMETER;
2090
2091 if (pszSubKey && pszSubKey[0])
2092 {
2093 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
2094 if (ret != ERROR_SUCCESS) return ret;
2095 }
2096
2097 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
2098
2099 /* If we are going to expand we need to read in the whole the value even
2100 * if the passed buffer was too small as the expanded string might be
2101 * smaller than the unexpanded one and could fit into cbData bytes. */
2102 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
2103 (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
2104 {
2105 do {
2106 HeapFree(GetProcessHeap(), 0, pvBuf);
2107
2108 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
2109 if (!pvBuf)
2110 {
2111 ret = ERROR_NOT_ENOUGH_MEMORY;
2112 break;
2113 }
2114
2115 if (ret == ERROR_MORE_DATA || !pvData)
2116 ret = RegQueryValueExA(hKey, pszValue, NULL,
2117 &dwType, pvBuf, &cbData);
2118 else
2119 {
2120 /* Even if cbData was large enough we have to copy the
2121 * string since ExpandEnvironmentStrings can't handle
2122 * overlapping buffers. */
2123 CopyMemory(pvBuf, pvData, cbData);
2124 }
2125
2126 /* Both the type or the value itself could have been modified in
2127 * between so we have to keep retrying until the buffer is large
2128 * enough or we no longer have to expand the value. */
2129 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
2130
2131 if (ret == ERROR_SUCCESS)
2132 {
2133 /* Recheck dwType in case it changed since the first call */
2134 if (dwType == REG_EXPAND_SZ)
2135 {
2136 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
2137 pcbData ? *pcbData : 0);
2138 dwType = REG_SZ;
2139 if(pvData && pcbData && cbData > *pcbData)
2140 ret = ERROR_MORE_DATA;
2141 }
2142 else if (pvData)
2143 CopyMemory(pvData, pvBuf, *pcbData);
2144 }
2145
2146 HeapFree(GetProcessHeap(), 0, pvBuf);
2147 }
2148
2149 if (pszSubKey && pszSubKey[0])
2150 RegCloseKey(hKey);
2151
2152 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
2153
2154 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
2155 ZeroMemory(pvData, *pcbData);
2156
2157 if (pdwType) *pdwType = dwType;
2158 if (pcbData) *pcbData = cbData;
2159
2160 return ret;
2161 }
2162
2163
2164 /************************************************************************
2165 * RegSetKeyValueW
2166 *
2167 * @implemented
2168 */
2169 LONG WINAPI
2170 RegSetKeyValueW(IN HKEY hKey,
2171 IN LPCWSTR lpSubKey OPTIONAL,
2172 IN LPCWSTR lpValueName OPTIONAL,
2173 IN DWORD dwType,
2174 IN LPCVOID lpData OPTIONAL,
2175 IN DWORD cbData)
2176 {
2177 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2178 NTSTATUS Status;
2179 LONG Ret;
2180
2181 Status = MapDefaultKey(&KeyHandle,
2182 hKey);
2183 if (!NT_SUCCESS(Status))
2184 {
2185 return RtlNtStatusToDosError(Status);
2186 }
2187
2188 if (lpSubKey != NULL)
2189 {
2190 OBJECT_ATTRIBUTES ObjectAttributes;
2191 UNICODE_STRING SubKeyName;
2192
2193 RtlInitUnicodeString(&SubKeyName,
2194 (LPWSTR)lpSubKey);
2195
2196 InitializeObjectAttributes(&ObjectAttributes,
2197 &SubKeyName,
2198 OBJ_CASE_INSENSITIVE,
2199 KeyHandle,
2200 NULL);
2201
2202 Status = NtOpenKey(&SubKeyHandle,
2203 KEY_SET_VALUE,
2204 &ObjectAttributes);
2205 if (!NT_SUCCESS(Status))
2206 {
2207 Ret = RtlNtStatusToDosError(Status);
2208 goto Cleanup;
2209 }
2210
2211 CurKey = SubKeyHandle;
2212 }
2213 else
2214 CurKey = KeyHandle;
2215
2216 Ret = RegSetValueExW(CurKey,
2217 lpValueName,
2218 0,
2219 dwType,
2220 lpData,
2221 cbData);
2222
2223 if (SubKeyHandle != NULL)
2224 {
2225 NtClose(SubKeyHandle);
2226 }
2227
2228 Cleanup:
2229 ClosePredefKey(KeyHandle);
2230
2231 return Ret;
2232 }
2233
2234
2235 /************************************************************************
2236 * RegSetKeyValueA
2237 *
2238 * @implemented
2239 */
2240 LONG WINAPI
2241 RegSetKeyValueA(IN HKEY hKey,
2242 IN LPCSTR lpSubKey OPTIONAL,
2243 IN LPCSTR lpValueName OPTIONAL,
2244 IN DWORD dwType,
2245 IN LPCVOID lpData OPTIONAL,
2246 IN DWORD cbData)
2247 {
2248 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
2249 NTSTATUS Status;
2250 LONG Ret;
2251
2252 Status = MapDefaultKey(&KeyHandle,
2253 hKey);
2254 if (!NT_SUCCESS(Status))
2255 {
2256 return RtlNtStatusToDosError(Status);
2257 }
2258
2259 if (lpSubKey != NULL)
2260 {
2261 OBJECT_ATTRIBUTES ObjectAttributes;
2262 UNICODE_STRING SubKeyName;
2263
2264 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
2265 (LPSTR)lpSubKey))
2266 {
2267 Ret = ERROR_NOT_ENOUGH_MEMORY;
2268 goto Cleanup;
2269 }
2270
2271 InitializeObjectAttributes(&ObjectAttributes,
2272 &SubKeyName,
2273 OBJ_CASE_INSENSITIVE,
2274 KeyHandle,
2275 NULL);
2276
2277 Status = NtOpenKey(&SubKeyHandle,
2278 KEY_SET_VALUE,
2279 &ObjectAttributes);
2280
2281 RtlFreeUnicodeString(&SubKeyName);
2282
2283 if (!NT_SUCCESS(Status))
2284 {
2285 Ret = RtlNtStatusToDosError(Status);
2286 goto Cleanup;
2287 }
2288
2289 CurKey = SubKeyHandle;
2290 }
2291 else
2292 CurKey = KeyHandle;
2293
2294 Ret = RegSetValueExA(CurKey,
2295 lpValueName,
2296 0,
2297 dwType,
2298 lpData,
2299 cbData);
2300
2301 if (SubKeyHandle != NULL)
2302 {
2303 NtClose(SubKeyHandle);
2304 }
2305
2306 Cleanup:
2307 ClosePredefKey(KeyHandle);
2308
2309 return Ret;
2310 }
2311
2312
2313 /************************************************************************
2314 * RegDeleteValueA
2315 *
2316 * @implemented
2317 */
2318 LONG WINAPI
2319 RegDeleteValueA(HKEY hKey,
2320 LPCSTR lpValueName)
2321 {
2322 UNICODE_STRING ValueName;
2323 HANDLE KeyHandle;
2324 NTSTATUS Status;
2325
2326 Status = MapDefaultKey(&KeyHandle,
2327 hKey);
2328 if (!NT_SUCCESS(Status))
2329 {
2330 return RtlNtStatusToDosError(Status);
2331 }
2332
2333 RtlCreateUnicodeStringFromAsciiz(&ValueName,
2334 (LPSTR)lpValueName);
2335 Status = NtDeleteValueKey(KeyHandle,
2336 &ValueName);
2337 RtlFreeUnicodeString (&ValueName);
2338
2339 ClosePredefKey(KeyHandle);
2340
2341 if (!NT_SUCCESS(Status))
2342 {
2343 return RtlNtStatusToDosError(Status);
2344 }
2345
2346 return ERROR_SUCCESS;
2347 }
2348
2349
2350 /************************************************************************
2351 * RegDeleteValueW
2352 *
2353 * @implemented
2354 */
2355 LONG WINAPI
2356 RegDeleteValueW(HKEY hKey,
2357 LPCWSTR lpValueName)
2358 {
2359 UNICODE_STRING ValueName;
2360 NTSTATUS Status;
2361 HANDLE KeyHandle;
2362
2363 Status = MapDefaultKey(&KeyHandle,
2364 hKey);
2365 if (!NT_SUCCESS(Status))
2366 {
2367 return RtlNtStatusToDosError(Status);
2368 }
2369
2370 RtlInitUnicodeString(&ValueName,
2371 (LPWSTR)lpValueName);
2372
2373 Status = NtDeleteValueKey(KeyHandle,
2374 &ValueName);
2375
2376 ClosePredefKey(KeyHandle);
2377
2378 if (!NT_SUCCESS(Status))
2379 {
2380 return RtlNtStatusToDosError(Status);
2381 }
2382
2383 return ERROR_SUCCESS;
2384 }
2385
2386
2387 /************************************************************************
2388 * RegEnumKeyA
2389 *
2390 * @implemented
2391 */
2392 LONG WINAPI
2393 RegEnumKeyA(HKEY hKey,
2394 DWORD dwIndex,
2395 LPSTR lpName,
2396 DWORD cbName)
2397 {
2398 DWORD dwLength;
2399
2400 dwLength = cbName;
2401 return RegEnumKeyExA(hKey,
2402 dwIndex,
2403 lpName,
2404 &dwLength,
2405 NULL,
2406 NULL,
2407 NULL,
2408 NULL);
2409 }
2410
2411
2412 /************************************************************************
2413 * RegEnumKeyW
2414 *
2415 * @implemented
2416 */
2417 LONG WINAPI
2418 RegEnumKeyW(HKEY hKey,
2419 DWORD dwIndex,
2420 LPWSTR lpName,
2421 DWORD cbName)
2422 {
2423 DWORD dwLength;
2424
2425 dwLength = cbName;
2426 return RegEnumKeyExW(hKey,
2427 dwIndex,
2428 lpName,
2429 &dwLength,
2430 NULL,
2431 NULL,
2432 NULL,
2433 NULL);
2434 }
2435
2436
2437 /************************************************************************
2438 * RegEnumKeyExA
2439 *
2440 * @implemented
2441 */
2442 LONG WINAPI
2443 RegEnumKeyExA(HKEY hKey,
2444 DWORD dwIndex,
2445 LPSTR lpName,
2446 LPDWORD lpcbName,
2447 LPDWORD lpReserved,
2448 LPSTR lpClass,
2449 LPDWORD lpcbClass,
2450 PFILETIME lpftLastWriteTime)
2451 {
2452 union
2453 {
2454 KEY_NODE_INFORMATION Node;
2455 KEY_BASIC_INFORMATION Basic;
2456 } *KeyInfo;
2457
2458 UNICODE_STRING StringU;
2459 ANSI_STRING StringA;
2460 LONG ErrorCode = ERROR_SUCCESS;
2461 DWORD NameLength;
2462 DWORD ClassLength = 0;
2463 DWORD BufferSize;
2464 ULONG ResultSize;
2465 HANDLE KeyHandle;
2466 NTSTATUS Status;
2467
2468 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2469 hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
2470
2471 if ((lpClass) && (!lpcbClass))
2472 {
2473 return ERROR_INVALID_PARAMETER;
2474 }
2475
2476 Status = MapDefaultKey(&KeyHandle, hKey);
2477 if (!NT_SUCCESS(Status))
2478 {
2479 return RtlNtStatusToDosError(Status);
2480 }
2481
2482 if (*lpcbName > 0)
2483 {
2484 NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
2485 }
2486 else
2487 {
2488 NameLength = 0;
2489 }
2490
2491 if (lpClass)
2492 {
2493 if (*lpcbClass > 0)
2494 {
2495 ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2496 }
2497 else
2498 {
2499 ClassLength = 0;
2500 }
2501
2502 /* The class name should start at a dword boundary */
2503 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
2504 }
2505 else
2506 {
2507 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
2508 }
2509
2510 KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
2511 if (KeyInfo == NULL)
2512 {
2513 ErrorCode = ERROR_OUTOFMEMORY;
2514 goto Cleanup;
2515 }
2516
2517 Status = NtEnumerateKey(KeyHandle,
2518 (ULONG)dwIndex,
2519 lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
2520 KeyInfo,
2521 BufferSize,
2522 &ResultSize);
2523 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
2524 if (!NT_SUCCESS(Status))
2525 {
2526 ErrorCode = RtlNtStatusToDosError (Status);
2527 }
2528 else
2529 {
2530 if (lpClass == NULL)
2531 {
2532 if (KeyInfo->Basic.NameLength > NameLength)
2533 {
2534 ErrorCode = ERROR_BUFFER_OVERFLOW;
2535 }
2536 else
2537 {
2538 StringU.Buffer = KeyInfo->Basic.Name;
2539 StringU.Length = KeyInfo->Basic.NameLength;
2540 StringU.MaximumLength = KeyInfo->Basic.NameLength;
2541 }
2542 }
2543 else
2544 {
2545 if (KeyInfo->Node.NameLength > NameLength ||
2546 KeyInfo->Node.ClassLength > ClassLength)
2547 {
2548 ErrorCode = ERROR_BUFFER_OVERFLOW;
2549 }
2550 else
2551 {
2552 StringA.Buffer = lpClass;
2553 StringA.Length = 0;
2554 StringA.MaximumLength = *lpcbClass;
2555 StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
2556 StringU.Length = KeyInfo->Node.ClassLength;
2557 StringU.MaximumLength = KeyInfo->Node.ClassLength;
2558 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
2559 lpClass[StringA.Length] = 0;
2560 *lpcbClass = StringA.Length;
2561 StringU.Buffer = KeyInfo->Node.Name;
2562 StringU.Length = KeyInfo->Node.NameLength;
2563 StringU.MaximumLength = KeyInfo->Node.NameLength;
2564 }
2565 }
2566
2567 if (ErrorCode == ERROR_SUCCESS)
2568 {
2569 StringA.Buffer = lpName;
2570 StringA.Length = 0;
2571 StringA.MaximumLength = *lpcbName;
2572 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
2573 lpName[StringA.Length] = 0;
2574 *lpcbName = StringA.Length;
2575 if (lpftLastWriteTime != NULL)
2576 {
2577 if (lpClass == NULL)
2578 {
2579 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
2580 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
2581 }
2582 else
2583 {
2584 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
2585 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
2586 }
2587 }
2588 }
2589 }
2590
2591 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2592 TRACE("Key Name1 Length %d\n", NameLength);
2593 TRACE("Key Name Length %d\n", *lpcbName);
2594 TRACE("Key Name %s\n", lpName);
2595
2596 RtlFreeHeap(ProcessHeap,
2597 0,
2598 KeyInfo);
2599
2600 Cleanup:
2601 ClosePredefKey(KeyHandle);
2602
2603 return ErrorCode;
2604 }
2605
2606
2607 /************************************************************************
2608 * RegEnumKeyExW
2609 *
2610 * @implemented
2611 */
2612 LONG WINAPI
2613 RegEnumKeyExW(HKEY hKey,
2614 DWORD dwIndex,
2615 LPWSTR lpName,
2616 LPDWORD lpcbName,
2617 LPDWORD lpReserved,
2618 LPWSTR lpClass,
2619 LPDWORD lpcbClass,
2620 PFILETIME lpftLastWriteTime)
2621 {
2622 union
2623 {
2624 KEY_NODE_INFORMATION Node;
2625 KEY_BASIC_INFORMATION Basic;
2626 } *KeyInfo;
2627
2628 ULONG BufferSize;
2629 ULONG ResultSize;
2630 ULONG NameLength;
2631 ULONG ClassLength = 0;
2632 HANDLE KeyHandle;
2633 LONG ErrorCode = ERROR_SUCCESS;
2634 NTSTATUS Status;
2635
2636 Status = MapDefaultKey(&KeyHandle,
2637 hKey);
2638 if (!NT_SUCCESS(Status))
2639 {
2640 return RtlNtStatusToDosError(Status);
2641 }
2642
2643 if (*lpcbName > 0)
2644 {
2645 NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
2646 }
2647 else
2648 {
2649 NameLength = 0;
2650 }
2651
2652 if (lpClass)
2653 {
2654 if (*lpcbClass > 0)
2655 {
2656 ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2657 }
2658 else
2659 {
2660 ClassLength = 0;
2661 }
2662
2663 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
2664 }
2665 else
2666 {
2667 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
2668 }
2669
2670 KeyInfo = RtlAllocateHeap(ProcessHeap,
2671 0,
2672 BufferSize);
2673 if (KeyInfo == NULL)
2674 {
2675 ErrorCode = ERROR_OUTOFMEMORY;
2676 goto Cleanup;
2677 }
2678
2679 Status = NtEnumerateKey(KeyHandle,
2680 (ULONG)dwIndex,
2681 lpClass ? KeyNodeInformation : KeyBasicInformation,
2682 KeyInfo,
2683 BufferSize,
2684 &ResultSize);
2685 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
2686 if (!NT_SUCCESS(Status))
2687 {
2688 ErrorCode = RtlNtStatusToDosError (Status);
2689 }
2690 else
2691 {
2692 if (lpClass == NULL)
2693 {
2694 if (KeyInfo->Basic.NameLength > NameLength)
2695 {
2696 ErrorCode = ERROR_BUFFER_OVERFLOW;
2697 }
2698 else
2699 {
2700 RtlCopyMemory(lpName,
2701 KeyInfo->Basic.Name,
2702 KeyInfo->Basic.NameLength);
2703 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
2704 lpName[*lpcbName] = 0;
2705 }
2706 }
2707 else
2708 {
2709 if (KeyInfo->Node.NameLength > NameLength ||
2710 KeyInfo->Node.ClassLength > ClassLength)
2711 {
2712 ErrorCode = ERROR_BUFFER_OVERFLOW;
2713 }
2714 else
2715 {
2716 RtlCopyMemory(lpName,
2717 KeyInfo->Node.Name,
2718 KeyInfo->Node.NameLength);
2719 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
2720 lpName[*lpcbName] = 0;
2721 RtlCopyMemory(lpClass,
2722 (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
2723 KeyInfo->Node.ClassLength);
2724 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
2725 lpClass[*lpcbClass] = 0;
2726 }
2727 }
2728
2729 if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
2730 {
2731 if (lpClass == NULL)
2732 {
2733 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
2734 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
2735 }
2736 else
2737 {
2738 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
2739 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
2740 }
2741 }
2742 }
2743
2744 RtlFreeHeap(ProcessHeap,
2745 0,
2746 KeyInfo);
2747
2748 Cleanup:
2749 ClosePredefKey(KeyHandle);
2750
2751 return ErrorCode;
2752 }
2753
2754
2755 /************************************************************************
2756 * RegEnumValueA
2757 *
2758 * @implemented
2759 */
2760 LONG WINAPI
2761 RegEnumValueA(HKEY hKey,
2762 DWORD index,
2763 LPSTR value,
2764 LPDWORD val_count,
2765 LPDWORD reserved,
2766 LPDWORD type,
2767 LPBYTE data,
2768 LPDWORD count)
2769 {
2770 HANDLE KeyHandle;
2771 NTSTATUS status;
2772 ULONG total_size;
2773 char buffer[256], *buf_ptr = buffer;
2774 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2775 static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
2776
2777 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2778 // hkey, index, value, val_count, reserved, type, data, count );
2779
2780 /* NT only checks count, not val_count */
2781 if ((data && !count) || reserved)
2782 return ERROR_INVALID_PARAMETER;
2783
2784 status = MapDefaultKey(&KeyHandle, hKey);
2785 if (!NT_SUCCESS(status))
2786 {
2787 return RtlNtStatusToDosError(status);
2788 }
2789
2790 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2791 if (data) total_size += *count;
2792 total_size = min( sizeof(buffer), total_size );
2793
2794 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2795 buffer, total_size, &total_size );
2796 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
2797
2798 /* we need to fetch the contents for a string type even if not requested,
2799 * because we need to compute the length of the ASCII string. */
2800 if (value || data || is_string(info->Type))
2801 {
2802 /* retry with a dynamically allocated buffer */
2803 while (status == STATUS_BUFFER_OVERFLOW)
2804 {
2805 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2806 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2807 {
2808 status = STATUS_INSUFFICIENT_RESOURCES;
2809 goto done;
2810 }
2811 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2812 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2813 buf_ptr, total_size, &total_size );
2814 }
2815
2816 if (status) goto done;
2817
2818 if (is_string(info->Type))
2819 {
2820 ULONG len;
2821 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2822 total_size - info->DataOffset );
2823 if (data && len)
2824 {
2825 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2826 else
2827 {
2828 RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2829 total_size - info->DataOffset );
2830 /* if the type is REG_SZ and data is not 0-terminated
2831 * and there is enough space in the buffer NT appends a \0 */
2832 if (len < *count && data[len-1]) data[len] = 0;
2833 }
2834 }
2835 info->DataLength = len;
2836 }
2837 else if (data)
2838 {
2839 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
2840 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2841 }
2842
2843 if (value && !status)
2844 {
2845 ULONG len;
2846
2847 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2848 if (len >= *val_count)
2849 {
2850 status = STATUS_BUFFER_OVERFLOW;
2851 if (*val_count)
2852 {
2853 len = *val_count - 1;
2854 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2855 value[len] = 0;
2856 }
2857 }
2858 else
2859 {
2860 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2861 value[len] = 0;
2862 *val_count = len;
2863 }
2864 }
2865 }
2866 else status = STATUS_SUCCESS;
2867
2868 if (type) *type = info->Type;
2869 if (count) *count = info->DataLength;
2870
2871 done:
2872 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2873 ClosePredefKey(KeyHandle);
2874 return RtlNtStatusToDosError(status);
2875 }
2876
2877
2878 /******************************************************************************
2879 * RegEnumValueW [ADVAPI32.@]
2880 * @implemented
2881 *
2882 * PARAMS
2883 * hkey [I] Handle to key to query
2884 * index [I] Index of value to query
2885 * value [O] Value string
2886 * val_count [I/O] Size of value buffer (in wchars)
2887 * reserved [I] Reserved
2888 * type [O] Type code
2889 * data [O] Value data
2890 * count [I/O] Size of data buffer (in bytes)
2891 *
2892 * RETURNS
2893 * Success: ERROR_SUCCESS
2894 * Failure: nonzero error code from Winerror.h
2895 */
2896 LONG WINAPI
2897 RegEnumValueW(HKEY hKey,
2898 DWORD index,
2899 LPWSTR value,
2900 PDWORD val_count,
2901 PDWORD reserved,
2902 PDWORD type,
2903 LPBYTE data,
2904 PDWORD count)
2905 {
2906 HANDLE KeyHandle;
2907 NTSTATUS status;
2908 ULONG total_size;
2909 char buffer[256], *buf_ptr = buffer;
2910 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2911 static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
2912
2913 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2914 // hkey, index, value, val_count, reserved, type, data, count );
2915
2916 /* NT only checks count, not val_count */
2917 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
2918
2919 status = MapDefaultKey(&KeyHandle, hKey);
2920 if (!NT_SUCCESS(status))
2921 {
2922 return RtlNtStatusToDosError(status);
2923 }
2924
2925 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2926 if (data) total_size += *count;
2927 total_size = min( sizeof(buffer), total_size );
2928
2929 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2930 buffer, total_size, &total_size );
2931 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
2932
2933 if (value || data)
2934 {
2935 /* retry with a dynamically allocated buffer */
2936 while (status == STATUS_BUFFER_OVERFLOW)
2937 {
2938 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2939 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2940 {
2941 status = ERROR_NOT_ENOUGH_MEMORY;
2942 goto done;
2943 }
2944 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2945 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2946 buf_ptr, total_size, &total_size );
2947 }
2948
2949 if (status) goto done;
2950
2951 if (value)
2952 {
2953 if (info->NameLength/sizeof(WCHAR) >= *val_count)
2954 {
2955 status = STATUS_BUFFER_OVERFLOW;
2956 goto overflow;
2957 }
2958 memcpy( value, info->Name, info->NameLength );
2959 *val_count = info->NameLength / sizeof(WCHAR);
2960 value[*val_count] = 0;
2961 }
2962
2963 if (data)
2964 {
2965 if (total_size - info->DataOffset > *count)
2966 {
2967 status = STATUS_BUFFER_OVERFLOW;
2968 goto overflow;
2969 }
2970 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2971 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
2972 {
2973 /* if the type is REG_SZ and data is not 0-terminated
2974 * and there is enough space in the buffer NT appends a \0 */
2975 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
2976 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
2977 }
2978 }
2979 }
2980 else status = STATUS_SUCCESS;
2981
2982 overflow:
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 * RegFlushKey
2995 *
2996 * @implemented
2997 */
2998 LONG WINAPI
2999 RegFlushKey(HKEY hKey)
3000 {
3001 HANDLE KeyHandle;
3002 NTSTATUS Status;
3003
3004 if (hKey == HKEY_PERFORMANCE_DATA)
3005 {
3006 return ERROR_SUCCESS;
3007 }
3008
3009 Status = MapDefaultKey(&KeyHandle,
3010 hKey);
3011 if (!NT_SUCCESS(Status))
3012 {
3013 return RtlNtStatusToDosError(Status);
3014 }
3015
3016 Status = NtFlushKey(KeyHandle);
3017
3018 ClosePredefKey(KeyHandle);
3019
3020 if (!NT_SUCCESS(Status))
3021 {
3022 return RtlNtStatusToDosError(Status);
3023 }
3024
3025 return ERROR_SUCCESS;
3026 }
3027
3028
3029 /************************************************************************
3030 * RegGetKeySecurity
3031 *
3032 * @implemented
3033 */
3034 LONG WINAPI
3035 RegGetKeySecurity(HKEY hKey,
3036 SECURITY_INFORMATION SecurityInformation,
3037 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3038 LPDWORD lpcbSecurityDescriptor)
3039 {
3040 HANDLE KeyHandle;
3041 NTSTATUS Status;
3042
3043 if (hKey == HKEY_PERFORMANCE_DATA)
3044 {
3045 return ERROR_INVALID_HANDLE;
3046 }
3047
3048 Status = MapDefaultKey(&KeyHandle,
3049 hKey);
3050 if (!NT_SUCCESS(Status))
3051 {
3052 TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
3053 return RtlNtStatusToDosError(Status);
3054 }
3055
3056 #if 0
3057 Status = NtQuerySecurityObject(KeyHandle,
3058 SecurityInformation,
3059 pSecurityDescriptor,
3060 *lpcbSecurityDescriptor,
3061 lpcbSecurityDescriptor);
3062 #endif
3063
3064 ClosePredefKey(KeyHandle);
3065
3066 if (!NT_SUCCESS(Status))
3067 {
3068 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
3069 return RtlNtStatusToDosError(Status);
3070 }
3071
3072 return ERROR_SUCCESS;
3073 }
3074
3075
3076 /************************************************************************
3077 * RegLoadKeyA
3078 *
3079 * @implemented
3080 */
3081 LONG WINAPI
3082 RegLoadKeyA(HKEY hKey,
3083 LPCSTR lpSubKey,
3084 LPCSTR lpFile)
3085 {
3086 UNICODE_STRING FileName;
3087 UNICODE_STRING KeyName;
3088 LONG ErrorCode;
3089
3090 RtlCreateUnicodeStringFromAsciiz(&KeyName,
3091 (LPSTR)lpSubKey);
3092 RtlCreateUnicodeStringFromAsciiz(&FileName,
3093 (LPSTR)lpFile);
3094
3095 ErrorCode = RegLoadKeyW(hKey,
3096 KeyName.Buffer,
3097 FileName.Buffer);
3098
3099 RtlFreeUnicodeString(&FileName);
3100 RtlFreeUnicodeString(&KeyName);
3101
3102 return ErrorCode;
3103 }
3104
3105
3106 /************************************************************************
3107 * RegLoadKeyW
3108 *
3109 * @implemented
3110 */
3111 LONG WINAPI
3112 RegLoadKeyW(HKEY hKey,
3113 LPCWSTR lpSubKey,
3114 LPCWSTR lpFile)
3115 {
3116 OBJECT_ATTRIBUTES FileObjectAttributes;
3117 OBJECT_ATTRIBUTES KeyObjectAttributes;
3118 UNICODE_STRING FileName;
3119 UNICODE_STRING KeyName;
3120 HANDLE KeyHandle;
3121 NTSTATUS Status;
3122 LONG ErrorCode = ERROR_SUCCESS;
3123
3124 if (hKey == HKEY_PERFORMANCE_DATA)
3125 {
3126 return ERROR_INVALID_HANDLE;
3127 }
3128
3129 Status = MapDefaultKey(&KeyHandle,
3130 hKey);
3131 if (!NT_SUCCESS(Status))
3132 {
3133 return RtlNtStatusToDosError(Status);
3134 }
3135
3136 if (!RtlDosPathNameToNtPathName_U(lpFile,
3137 &FileName,
3138 NULL,
3139 NULL))
3140 {
3141 ErrorCode = ERROR_BAD_PATHNAME;
3142 goto Cleanup;
3143 }
3144
3145 InitializeObjectAttributes(&FileObjectAttributes,
3146 &FileName,
3147 OBJ_CASE_INSENSITIVE,
3148 NULL,
3149 NULL);
3150
3151 RtlInitUnicodeString(&KeyName,
3152 (LPWSTR)lpSubKey);
3153
3154 InitializeObjectAttributes(&KeyObjectAttributes,
3155 &KeyName,
3156 OBJ_CASE_INSENSITIVE,
3157 KeyHandle,
3158 NULL);
3159
3160 Status = NtLoadKey(&KeyObjectAttributes,
3161 &FileObjectAttributes);
3162
3163 RtlFreeHeap(RtlGetProcessHeap(),
3164 0,
3165 FileName.Buffer);
3166
3167 if (!NT_SUCCESS(Status))
3168 {
3169 ErrorCode = RtlNtStatusToDosError(Status);
3170 goto Cleanup;
3171 }
3172
3173 Cleanup:
3174 ClosePredefKey(KeyHandle);
3175
3176 return ErrorCode;
3177 }
3178
3179
3180 /************************************************************************
3181 * RegNotifyChangeKeyValue
3182 *
3183 * @unimplemented
3184 */
3185 LONG WINAPI
3186 RegNotifyChangeKeyValue(HKEY hKey,
3187 BOOL bWatchSubtree,
3188 DWORD dwNotifyFilter,
3189 HANDLE hEvent,
3190 BOOL fAsynchronous)
3191 {
3192 IO_STATUS_BLOCK IoStatusBlock;
3193 HANDLE KeyHandle;
3194 NTSTATUS Status;
3195 LONG ErrorCode = ERROR_SUCCESS;
3196
3197 if (hKey == HKEY_PERFORMANCE_DATA)
3198 {
3199 return ERROR_INVALID_HANDLE;
3200 }
3201
3202 if (fAsynchronous == TRUE && hEvent == NULL)
3203 {
3204 return ERROR_INVALID_PARAMETER;
3205 }
3206
3207 Status = MapDefaultKey(&KeyHandle,
3208 hKey);
3209 if (!NT_SUCCESS(Status))
3210 {
3211 return RtlNtStatusToDosError(Status);
3212 }
3213
3214 /* FIXME: Remote key handles must fail */
3215
3216 Status = NtNotifyChangeKey(KeyHandle,
3217 hEvent,
3218 0,
3219 0,
3220 &IoStatusBlock,
3221 dwNotifyFilter,
3222 bWatchSubtree,
3223 0,
3224 0,
3225 fAsynchronous);
3226 if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
3227 {
3228 ErrorCode = RtlNtStatusToDosError(Status);
3229 }
3230
3231 ClosePredefKey(KeyHandle);
3232
3233 return ErrorCode;
3234 }
3235
3236
3237 /************************************************************************
3238 * RegOpenCurrentUser
3239 *
3240 * @implemented
3241 */
3242 LONG WINAPI
3243 RegOpenCurrentUser(IN REGSAM samDesired,
3244 OUT PHKEY phkResult)
3245 {
3246 NTSTATUS Status;
3247
3248 Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
3249 (PHANDLE)phkResult);
3250 if (!NT_SUCCESS(Status))
3251 {
3252 /* NOTE - don't set the last error code! just return the error! */
3253 return RtlNtStatusToDosError(Status);
3254 }
3255
3256 return ERROR_SUCCESS;
3257 }
3258
3259
3260 /************************************************************************
3261 * RegOpenKeyA
3262 *
3263 * 20050503 Fireball - imported from WINE
3264 *
3265 * @implemented
3266 */
3267 LONG WINAPI
3268 RegOpenKeyA(HKEY hKey,
3269 LPCSTR lpSubKey,
3270 PHKEY phkResult)
3271 {
3272 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3273 hKey, lpSubKey, phkResult);
3274
3275 if (!phkResult)
3276 return ERROR_INVALID_PARAMETER;
3277
3278 if (!hKey && lpSubKey && phkResult)
3279 {
3280 return ERROR_INVALID_HANDLE;
3281 }
3282
3283 if (!lpSubKey || !*lpSubKey)
3284 {
3285 *phkResult = hKey;
3286 return ERROR_SUCCESS;
3287 }
3288
3289 return RegOpenKeyExA(hKey,
3290 lpSubKey,
3291 0,
3292 MAXIMUM_ALLOWED,
3293 phkResult);
3294 }
3295
3296
3297 /************************************************************************
3298 * RegOpenKeyW
3299 *
3300 * 19981101 Ariadne
3301 * 19990525 EA
3302 * 20050503 Fireball - imported from WINE
3303 *
3304 * @implemented
3305 */
3306 LONG WINAPI
3307 RegOpenKeyW(HKEY hKey,
3308 LPCWSTR lpSubKey,
3309 PHKEY phkResult)
3310 {
3311 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3312 hKey, lpSubKey, phkResult);
3313
3314 if (!phkResult)
3315 return ERROR_INVALID_PARAMETER;
3316
3317 if (!hKey && lpSubKey && phkResult)
3318 {
3319 return ERROR_INVALID_HANDLE;
3320 }
3321
3322 if (!lpSubKey || !*lpSubKey)
3323 {
3324 *phkResult = hKey;
3325 return ERROR_SUCCESS;
3326 }
3327
3328 return RegOpenKeyExW(hKey,
3329 lpSubKey,
3330 0,
3331 MAXIMUM_ALLOWED,
3332 phkResult);
3333 }
3334
3335
3336 /************************************************************************
3337 * RegOpenKeyExA
3338 *
3339 * @implemented
3340 */
3341 LONG WINAPI
3342 RegOpenKeyExA(HKEY hKey,
3343 LPCSTR lpSubKey,
3344 DWORD ulOptions,
3345 REGSAM samDesired,
3346 PHKEY phkResult)
3347 {
3348 OBJECT_ATTRIBUTES ObjectAttributes;
3349 UNICODE_STRING SubKeyString;
3350 HANDLE KeyHandle;
3351 NTSTATUS Status;
3352 LONG ErrorCode = ERROR_SUCCESS;
3353
3354 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3355 hKey, lpSubKey, ulOptions, samDesired, phkResult);
3356 if (!phkResult)
3357 {
3358 return ERROR_INVALID_PARAMETER;
3359 }
3360
3361 Status = MapDefaultKey(&KeyHandle,
3362 hKey);
3363 if (!NT_SUCCESS(Status))
3364 {
3365 return RtlNtStatusToDosError(Status);
3366 }
3367
3368 RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
3369 (LPSTR)lpSubKey);
3370 InitializeObjectAttributes(&ObjectAttributes,
3371 &SubKeyString,
3372 OBJ_CASE_INSENSITIVE,
3373 KeyHandle,
3374 NULL);
3375
3376 Status = NtOpenKey((PHANDLE)phkResult,
3377 samDesired,
3378 &ObjectAttributes);
3379 RtlFreeUnicodeString(&SubKeyString);
3380 if (!NT_SUCCESS(Status))
3381 {
3382 ErrorCode = RtlNtStatusToDosError(Status);
3383 }
3384
3385 ClosePredefKey(KeyHandle);
3386
3387 return ErrorCode;
3388 }
3389
3390
3391 /************************************************************************
3392 * RegOpenKeyExW
3393 *
3394 * @implemented
3395 */
3396 LONG WINAPI
3397 RegOpenKeyExW(HKEY hKey,
3398 LPCWSTR lpSubKey,
3399 DWORD ulOptions,
3400 REGSAM samDesired,
3401 PHKEY phkResult)
3402 {
3403 OBJECT_ATTRIBUTES ObjectAttributes;
3404 UNICODE_STRING SubKeyString;
3405 HANDLE KeyHandle;
3406 NTSTATUS Status;
3407 LONG ErrorCode = ERROR_SUCCESS;
3408
3409 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3410 hKey, lpSubKey, ulOptions, samDesired, phkResult);
3411 if (!phkResult)
3412 {
3413 return ERROR_INVALID_PARAMETER;
3414 }
3415
3416 Status = MapDefaultKey(&KeyHandle, hKey);
3417 if (!NT_SUCCESS(Status))
3418 {
3419 return RtlNtStatusToDosError(Status);
3420 }
3421
3422 if (lpSubKey != NULL)
3423 RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
3424 else
3425 RtlInitUnicodeString(&SubKeyString, (LPWSTR)L"");
3426
3427 InitializeObjectAttributes(&ObjectAttributes,
3428 &SubKeyString,
3429 OBJ_CASE_INSENSITIVE,
3430 KeyHandle,
3431 NULL);
3432
3433 Status = NtOpenKey((PHANDLE)phkResult,
3434 samDesired,
3435 &ObjectAttributes);
3436 if (!NT_SUCCESS(Status))
3437 {
3438 ErrorCode = RtlNtStatusToDosError(Status);
3439 }
3440
3441 ClosePredefKey(KeyHandle);
3442
3443 return ErrorCode;
3444 }
3445
3446
3447 /************************************************************************
3448 * RegOpenUserClassesRoot
3449 *
3450 * @implemented
3451 */
3452 LONG WINAPI
3453 RegOpenUserClassesRoot(IN HANDLE hToken,
3454 IN DWORD dwOptions,
3455 IN REGSAM samDesired,
3456 OUT PHKEY phkResult)
3457 {
3458 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
3459 const WCHAR UserClassesKeySuffix[] = L"_Classes";
3460 PTOKEN_USER TokenUserData;
3461 ULONG RequiredLength;
3462 UNICODE_STRING UserSidString, UserClassesKeyRoot;
3463 OBJECT_ATTRIBUTES ObjectAttributes;
3464 NTSTATUS Status;
3465
3466 /* check parameters */
3467 if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
3468 {
3469 return ERROR_INVALID_PARAMETER;
3470 }
3471
3472 /*
3473 * Get the user sid from the token
3474 */
3475
3476 ReadTokenSid:
3477 /* determine how much memory we need */
3478 Status = NtQueryInformationToken(hToken,
3479 TokenUser,
3480 NULL,
3481 0,
3482 &RequiredLength);
3483 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
3484 {
3485 /* NOTE - as opposed to all other registry functions windows does indeed
3486 change the last error code in case the caller supplied a invalid
3487 handle for example! */
3488 return RtlNtStatusToDosError(Status);
3489 }
3490 RegInitialize(); /* HACK until delay-loading is implemented */
3491 TokenUserData = RtlAllocateHeap(ProcessHeap,
3492 0,
3493 RequiredLength);
3494 if (TokenUserData == NULL)
3495 {
3496 return ERROR_NOT_ENOUGH_MEMORY;
3497 }
3498
3499 /* attempt to read the information */
3500 Status = NtQueryInformationToken(hToken,
3501 TokenUser,
3502 TokenUserData,
3503 RequiredLength,
3504 &RequiredLength);
3505 if (!NT_SUCCESS(Status))
3506 {
3507 RtlFreeHeap(ProcessHeap,
3508 0,
3509 TokenUserData);
3510 if (Status == STATUS_BUFFER_TOO_SMALL)
3511 {
3512 /* the information appears to have changed?! try again */
3513 goto ReadTokenSid;
3514 }
3515