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