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