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