reshuffling of dlls
[reactos.git] / reactos / dll / 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 (!lpSubKey || !*lpSubKey)
2777 {
2778 *phkResult = hKey;
2779 return ERROR_SUCCESS;
2780 }
2781
2782 return RegOpenKeyExA( hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
2783 }
2784
2785
2786 /************************************************************************
2787 * RegOpenKeyW
2788 *
2789 * 19981101 Ariadne
2790 * 19990525 EA
2791 * 20050503 Fireball - imported from WINE
2792 *
2793 * @implemented
2794 */
2795 LONG STDCALL
2796 RegOpenKeyW (HKEY hKey,
2797 LPCWSTR lpSubKey,
2798 PHKEY phkResult)
2799 {
2800 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey, lpSubKey, phkResult);
2801
2802 if (!lpSubKey || !*lpSubKey)
2803 {
2804 *phkResult = hKey;
2805 return ERROR_SUCCESS;
2806 }
2807 return RegOpenKeyExW(hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
2808 }
2809
2810
2811 /************************************************************************
2812 * RegOpenKeyExA
2813 *
2814 * @implemented
2815 */
2816 LONG STDCALL
2817 RegOpenKeyExA (HKEY hKey,
2818 LPCSTR lpSubKey,
2819 DWORD ulOptions,
2820 REGSAM samDesired,
2821 PHKEY phkResult)
2822 {
2823 OBJECT_ATTRIBUTES ObjectAttributes;
2824 UNICODE_STRING SubKeyString;
2825 HANDLE KeyHandle;
2826 NTSTATUS Status;
2827 LONG ErrorCode = ERROR_SUCCESS;
2828
2829 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2830 hKey, lpSubKey, ulOptions, samDesired, phkResult);
2831
2832 Status = MapDefaultKey (&KeyHandle, hKey);
2833 if (!NT_SUCCESS(Status))
2834 {
2835 return RtlNtStatusToDosError (Status);
2836 }
2837
2838 RtlCreateUnicodeStringFromAsciiz (&SubKeyString, (LPSTR)lpSubKey);
2839 InitializeObjectAttributes (&ObjectAttributes,
2840 &SubKeyString,
2841 OBJ_CASE_INSENSITIVE,
2842 KeyHandle,
2843 NULL);
2844
2845 Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
2846 RtlFreeUnicodeString (&SubKeyString);
2847 if (!NT_SUCCESS(Status))
2848 {
2849 ErrorCode = RtlNtStatusToDosError (Status);
2850 }
2851
2852 ClosePredefKey(KeyHandle);
2853
2854 return ErrorCode;
2855 }
2856
2857
2858 /************************************************************************
2859 * RegOpenKeyExW
2860 *
2861 * @implemented
2862 */
2863 LONG STDCALL
2864 RegOpenKeyExW (HKEY hKey,
2865 LPCWSTR lpSubKey,
2866 DWORD ulOptions,
2867 REGSAM samDesired,
2868 PHKEY phkResult)
2869 {
2870 OBJECT_ATTRIBUTES ObjectAttributes;
2871 UNICODE_STRING SubKeyString;
2872 HANDLE KeyHandle;
2873 NTSTATUS Status;
2874 LONG ErrorCode = ERROR_SUCCESS;
2875
2876 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2877 hKey, lpSubKey, ulOptions, samDesired, phkResult);
2878
2879 Status = MapDefaultKey (&KeyHandle, hKey);
2880 if (!NT_SUCCESS(Status))
2881 {
2882 return RtlNtStatusToDosError (Status);
2883 }
2884
2885 if (lpSubKey != NULL)
2886 RtlInitUnicodeString (&SubKeyString, (LPWSTR)lpSubKey);
2887 else
2888 RtlInitUnicodeString (&SubKeyString, (LPWSTR)L"");
2889
2890 InitializeObjectAttributes (&ObjectAttributes,
2891 &SubKeyString,
2892 OBJ_CASE_INSENSITIVE,
2893 KeyHandle,
2894 NULL);
2895
2896 Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
2897
2898 if (!NT_SUCCESS(Status))
2899 {
2900 ErrorCode = RtlNtStatusToDosError (Status);
2901 }
2902
2903 ClosePredefKey(KeyHandle);
2904
2905 return ErrorCode;
2906 }
2907
2908
2909 /************************************************************************
2910 * RegOpenUserClassesRoot
2911 *
2912 * @implemented
2913 */
2914 LONG STDCALL
2915 RegOpenUserClassesRoot (IN HANDLE hToken,
2916 IN DWORD dwOptions,
2917 IN REGSAM samDesired,
2918 OUT PHKEY phkResult)
2919 {
2920 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
2921 const WCHAR UserClassesKeySuffix[] = L"_Classes";
2922 PTOKEN_USER TokenUserData;
2923 ULONG RequiredLength;
2924 UNICODE_STRING UserSidString, UserClassesKeyRoot;
2925 OBJECT_ATTRIBUTES ObjectAttributes;
2926 NTSTATUS Status;
2927
2928 /* check parameters */
2929 if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
2930 {
2931 return ERROR_INVALID_PARAMETER;
2932 }
2933
2934 /*
2935 * Get the user sid from the token
2936 */
2937
2938 ReadTokenSid:
2939 /* determine how much memory we need */
2940 Status = NtQueryInformationToken(hToken,
2941 TokenUser,
2942 NULL,
2943 0,
2944 &RequiredLength);
2945 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
2946 {
2947 /* NOTE - as opposed to all other registry functions windows does indeed
2948 change the last error code in case the caller supplied a invalid
2949 handle for example! */
2950 return RtlNtStatusToDosError (Status);
2951 }
2952
2953 TokenUserData = RtlAllocateHeap(ProcessHeap,
2954 0,
2955 RequiredLength);
2956 if (TokenUserData == NULL)
2957 {
2958 return ERROR_NOT_ENOUGH_MEMORY;
2959 }
2960
2961 /* attempt to read the information */
2962 Status = NtQueryInformationToken(hToken,
2963 TokenUser,
2964 TokenUserData,
2965 RequiredLength,
2966 &RequiredLength);
2967 if (!NT_SUCCESS(Status))
2968 {
2969 RtlFreeHeap(ProcessHeap,
2970 0,
2971 TokenUserData);
2972 if (Status == STATUS_BUFFER_TOO_SMALL)
2973 {
2974 /* the information appears to have changed?! try again */
2975 goto ReadTokenSid;
2976 }
2977
2978 /* NOTE - as opposed to all other registry functions windows does indeed
2979 change the last error code in case the caller supplied a invalid
2980 handle for example! */
2981 return RtlNtStatusToDosError (Status);
2982 }
2983
2984 /*
2985 * Build the absolute path for the user's registry in the form
2986 * "\Registry\User\<SID>_Classes"
2987 */
2988 Status = RtlConvertSidToUnicodeString(&UserSidString,
2989 TokenUserData->User.Sid,
2990 TRUE);
2991
2992 /* we don't need the user data anymore, free it */
2993 RtlFreeHeap(ProcessHeap,
2994 0,
2995 TokenUserData);
2996
2997 if (!NT_SUCCESS(Status))
2998 {
2999 return RtlNtStatusToDosError (Status);
3000 }
3001
3002 /* allocate enough memory for the entire key string */
3003 UserClassesKeyRoot.Length = 0;
3004 UserClassesKeyRoot.MaximumLength = UserSidString.Length +
3005 sizeof(UserClassesKeyPrefix) +
3006 sizeof(UserClassesKeySuffix);
3007 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
3008 0,
3009 UserClassesKeyRoot.MaximumLength);
3010 if (UserClassesKeyRoot.Buffer == NULL)
3011 {
3012 RtlFreeUnicodeString(&UserSidString);
3013 return RtlNtStatusToDosError (Status);
3014 }
3015
3016 /* build the string */
3017 RtlAppendUnicodeToString(&UserClassesKeyRoot,
3018 UserClassesKeyPrefix);
3019 RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
3020 &UserSidString);
3021 RtlAppendUnicodeToString(&UserClassesKeyRoot,
3022 UserClassesKeySuffix);
3023
3024 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
3025
3026 /*
3027 * Open the key
3028 */
3029
3030 InitializeObjectAttributes (&ObjectAttributes,
3031 &UserClassesKeyRoot,
3032 OBJ_CASE_INSENSITIVE,
3033 NULL,
3034 NULL);
3035
3036 Status = NtOpenKey((PHANDLE)phkResult,
3037 samDesired,
3038 &ObjectAttributes);
3039
3040 RtlFreeUnicodeString(&UserSidString);
3041 RtlFreeUnicodeString(&UserClassesKeyRoot);
3042
3043 if (!NT_SUCCESS(Status))
3044 {
3045 return RtlNtStatusToDosError (Status);
3046 }
3047
3048 return ERROR_SUCCESS;
3049 }
3050
3051
3052 /************************************************************************
3053 * RegQueryInfoKeyA
3054 *
3055 * @implemented
3056 */
3057 LONG STDCALL
3058 RegQueryInfoKeyA (HKEY hKey,
3059 LPSTR lpClass,
3060 LPDWORD lpcbClass,
3061 LPDWORD lpReserved,
3062 LPDWORD lpcSubKeys,
3063 LPDWORD lpcbMaxSubKeyLen,
3064 LPDWORD lpcbMaxClassLen,
3065 LPDWORD lpcValues,
3066 LPDWORD lpcbMaxValueNameLen,
3067 LPDWORD lpcbMaxValueLen,
3068 LPDWORD lpcbSecurityDescriptor,
3069 PFILETIME lpftLastWriteTime)
3070 {
3071 WCHAR ClassName[MAX_PATH];
3072 UNICODE_STRING UnicodeString;
3073 ANSI_STRING AnsiString;
3074 LONG ErrorCode;
3075
3076 RtlInitUnicodeString (&UnicodeString,
3077 NULL);
3078 if (lpClass != NULL)
3079 {
3080 UnicodeString.Buffer = &ClassName[0];
3081 UnicodeString.MaximumLength = sizeof(ClassName);
3082 AnsiString.MaximumLength = *lpcbClass;
3083 }
3084
3085 ErrorCode = RegQueryInfoKeyW (hKey,
3086 UnicodeString.Buffer,
3087 lpcbClass,
3088 lpReserved,
3089 lpcSubKeys,
3090 lpcbMaxSubKeyLen,
3091 lpcbMaxClassLen,
3092 lpcValues,
3093 lpcbMaxValueNameLen,
3094 lpcbMaxValueLen,
3095 lpcbSecurityDescriptor,
3096 lpftLastWriteTime);
3097 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
3098 {
3099 AnsiString.Buffer = lpClass;
3100 AnsiString.Length = 0;
3101 UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
3102 RtlUnicodeStringToAnsiString (&AnsiString,
3103 &UnicodeString,
3104 FALSE);
3105 *lpcbClass = AnsiString.Length;
3106 lpClass[AnsiString.Length] = 0;
3107 }
3108
3109 return ErrorCode;
3110 }
3111
3112
3113 /************************************************************************
3114 * RegQueryInfoKeyW
3115 *
3116 * @implemented
3117 */
3118 LONG STDCALL
3119 RegQueryInfoKeyW (HKEY hKey,
3120 LPWSTR lpClass,
3121 LPDWORD lpcbClass,
3122 LPDWORD lpReserved,
3123 LPDWORD lpcSubKeys,
3124 LPDWORD lpcbMaxSubKeyLen,
3125 LPDWORD lpcbMaxClassLen,
3126 LPDWORD lpcValues,
3127 LPDWORD lpcbMaxValueNameLen,
3128 LPDWORD lpcbMaxValueLen,
3129 LPDWORD lpcbSecurityDescriptor,
3130 PFILETIME lpftLastWriteTime)
3131 {
3132 KEY_FULL_INFORMATION FullInfoBuffer;
3133 PKEY_FULL_INFORMATION FullInfo;
3134 ULONG FullInfoSize;
3135 ULONG ClassLength = 0;
3136 HANDLE KeyHandle;
3137 NTSTATUS Status;
3138 ULONG Length;
3139 LONG ErrorCode = ERROR_SUCCESS;
3140
3141 if ((lpClass) && (!lpcbClass))
3142 {
3143 return ERROR_INVALID_PARAMETER;
3144 }
3145
3146 Status = MapDefaultKey (&KeyHandle,
3147 hKey);
3148 if (!NT_SUCCESS(Status))
3149 {
3150 return RtlNtStatusToDosError (Status);
3151 }
3152
3153 if (lpClass != NULL)
3154 {
3155 if (*lpcbClass > 0)
3156 {
3157 ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3158 }
3159 else
3160 {
3161 ClassLength = 0;
3162 }
3163
3164 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3165 FullInfo = RtlAllocateHeap (ProcessHeap,
3166 0,
3167 FullInfoSize);
3168 if (FullInfo == NULL)
3169 {
3170 ErrorCode = ERROR_OUTOFMEMORY;
3171 goto Cleanup;
3172 }
3173
3174 FullInfo->ClassLength = ClassLength;
3175 }
3176 else
3177 {
3178 FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3179 FullInfo = &FullInfoBuffer;
3180 FullInfo->ClassLength = 0;
3181 }
3182 FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
3183
3184 Status = NtQueryKey (KeyHandle,
3185 KeyFullInformation,
3186 FullInfo,
3187 FullInfoSize,
3188 &Length);
3189 TRACE("NtQueryKey() returned status 0x%X\n", Status);
3190 if (!NT_SUCCESS(Status))
3191 {
3192 if (lpClass != NULL)
3193 {
3194 RtlFreeHeap (ProcessHeap,
3195 0,
3196 FullInfo);
3197 }
3198
3199 ErrorCode = RtlNtStatusToDosError (Status);
3200 goto Cleanup;
3201 }
3202
3203 TRACE("SubKeys %d\n", FullInfo->SubKeys);
3204 if (lpcSubKeys != NULL)
3205 {
3206 *lpcSubKeys = FullInfo->SubKeys;
3207 }
3208
3209 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3210 if (lpcbMaxSubKeyLen != NULL)
3211 {
3212 *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
3213 }
3214
3215 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3216 if (lpcbMaxClassLen != NULL)
3217 {
3218 *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
3219 }
3220
3221 TRACE("Values %lu\n", FullInfo->Values);
3222 if (lpcValues != NULL)
3223 {
3224 *lpcValues = FullInfo->Values;
3225 }
3226
3227 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3228 if (lpcbMaxValueNameLen != NULL)
3229 {
3230 *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
3231 }
3232
3233 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3234 if (lpcbMaxValueLen != NULL)
3235 {
3236 *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
3237 }
3238 #if 0
3239 if (lpcbSecurityDescriptor != NULL)
3240 {
3241 Status = NtQuerySecurityObject(KeyHandle,
3242 OWNER_SECURITY_INFORMATION |
3243 GROUP_SECURITY_INFORMATION |
3244 DACL_SECURITY_INFORMATION,
3245 NULL,
3246 0,
3247 lpcbSecurityDescriptor);
3248 if (!NT_SUCCESS(Status))
3249 {
3250 if (lpClass != NULL)
3251 {
3252 RtlFreeHeap(ProcessHeap,
3253 0,
3254 FullInfo);
3255 }
3256
3257 ErrorCode = RtlNtStatusToDosError (Status);
3258 goto Cleanup;
3259 }
3260 }
3261 #endif
3262
3263 if (lpftLastWriteTime != NULL)
3264 {
3265 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3266 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3267 }
3268
3269 if (lpClass != NULL)
3270 {
3271 if (FullInfo->ClassLength > ClassLength)
3272 {
3273 ErrorCode = ERROR_BUFFER_OVERFLOW;
3274 }
3275 else
3276 {
3277 RtlCopyMemory (lpClass,
3278 FullInfo->Class,
3279 FullInfo->ClassLength);
3280 *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
3281 lpClass[*lpcbClass] = 0;
3282 }
3283
3284 RtlFreeHeap (ProcessHeap,
3285 0,
3286 FullInfo);
3287 }
3288
3289 Cleanup:
3290 ClosePredefKey(KeyHandle);
3291
3292 return ErrorCode;
3293 }
3294
3295
3296 /************************************************************************
3297 * RegQueryMultipleValuesA
3298 *
3299 * @implemented
3300 */
3301 LONG STDCALL
3302 RegQueryMultipleValuesA (HKEY hKey,
3303 PVALENTA val_list,
3304 DWORD num_vals,
3305 LPSTR lpValueBuf,
3306 LPDWORD ldwTotsize)
3307 {
3308 ULONG i;
3309 DWORD maxBytes = *ldwTotsize;
3310 LPSTR bufptr = (LPSTR)lpValueBuf;
3311 LONG ErrorCode;
3312
3313 if (maxBytes >= (1024*1024))
3314 return ERROR_TRANSFER_TOO_LONG;
3315
3316 *ldwTotsize = 0;
3317
3318 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3319 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3320
3321 for (i = 0; i < num_vals; i++)
3322 {
3323 val_list[i].ve_valuelen = 0;
3324 ErrorCode = RegQueryValueExA (hKey,
3325 val_list[i].ve_valuename,
3326 NULL,
3327 NULL,
3328 NULL,
3329 &val_list[i].ve_valuelen);
3330 if (ErrorCode != ERROR_SUCCESS)
3331 {
3332 return ErrorCode;
3333 }
3334
3335 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3336 {
3337 ErrorCode = RegQueryValueExA (hKey,
3338 val_list[i].ve_valuename,
3339 NULL,
3340 &val_list[i].ve_type,
3341 (LPBYTE)bufptr,
3342 &val_list[i].ve_valuelen);
3343 if (ErrorCode != ERROR_SUCCESS)
3344 {
3345 return ErrorCode;
3346 }
3347
3348 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3349
3350 bufptr += val_list[i].ve_valuelen;
3351 }
3352
3353 *ldwTotsize += val_list[i].ve_valuelen;
3354 }
3355
3356 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3357 }
3358
3359
3360 /************************************************************************
3361 * RegQueryMultipleValuesW
3362 *
3363 * @implemented
3364 */
3365 LONG STDCALL
3366 RegQueryMultipleValuesW (HKEY hKey,
3367 PVALENTW val_list,
3368 DWORD num_vals,
3369 LPWSTR lpValueBuf,
3370 LPDWORD ldwTotsize)
3371 {
3372 ULONG i;
3373 DWORD maxBytes = *ldwTotsize;
3374 LPSTR bufptr = (LPSTR)lpValueBuf;
3375 LONG ErrorCode;
3376
3377 if (maxBytes >= (1024*1024))
3378 return ERROR_TRANSFER_TOO_LONG;
3379
3380 *ldwTotsize = 0;
3381
3382 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3383 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3384
3385 for (i = 0; i < num_vals; i++)
3386 {
3387 val_list[i].ve_valuelen = 0;
3388 ErrorCode = RegQueryValueExW (hKey,
3389 val_list[i].ve_valuename,
3390 NULL,
3391 NULL,
3392 NULL,
3393 &val_list[i].ve_valuelen);
3394 if (ErrorCode != ERROR_SUCCESS)
3395 {
3396 return ErrorCode;
3397 }
3398
3399 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3400 {
3401 ErrorCode = RegQueryValueExW (hKey,
3402 val_list[i].ve_valuename,
3403 NULL,
3404 &val_list[i].ve_type,
3405 (LPBYTE)bufptr,
3406 &val_list[i].ve_valuelen);
3407 if (ErrorCode != ERROR_SUCCESS)
3408 {
3409 return ErrorCode;
3410 }
3411
3412 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3413
3414 bufptr += val_list[i].ve_valuelen;
3415 }
3416
3417 *ldwTotsize += val_list[i].ve_valuelen;
3418 }
3419
3420 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3421 }
3422
3423
3424 /************************************************************************
3425 * RegQueryReflectionKey
3426 *
3427 * @unimplemented
3428 */
3429 LONG WINAPI
3430 RegQueryReflectionKey(IN HKEY hBase,
3431 OUT BOOL* bIsReflectionDisabled)
3432 {
3433 DPRINT1("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3434 hBase, bIsReflectionDisabled);
3435 return ERROR_CALL_NOT_IMPLEMENTED;
3436 }
3437
3438
3439 /************************************************************************
3440 * RegQueryValueExW
3441 *
3442 * @implemented
3443 */
3444 LONG STDCALL
3445 RegQueryValueExW (HKEY hKey,
3446 LPCWSTR lpValueName,
3447 LPDWORD lpReserved,
3448 LPDWORD lpType,
3449 LPBYTE lpData,
3450 LPDWORD lpcbData)
3451 {
3452 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
3453 UNICODE_STRING ValueName;
3454 NTSTATUS Status;
3455 ULONG BufferSize;
3456 ULONG ResultSize;
3457 HANDLE KeyHandle;
3458 LONG ErrorCode = ERROR_SUCCESS;
3459 ULONG MaxCopy = lpcbData != NULL && lpData != NULL ? *lpcbData : 0;
3460
3461 TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
3462 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
3463
3464 Status = MapDefaultKey (&KeyHandle,
3465 hKey);
3466 if (!NT_SUCCESS(Status))
3467 {
3468 return RtlNtStatusToDosError (Status);
3469 }
3470
3471 if (lpData != NULL && lpcbData == NULL)
3472 {
3473 ErrorCode = ERROR_INVALID_PARAMETER;
3474 goto Cleanup;
3475 }
3476
3477 RtlInitUnicodeString (&ValueName,
3478 lpValueName);
3479 BufferSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MaxCopy;
3480 ValueInfo = RtlAllocateHeap (ProcessHeap,
3481 0,
3482 BufferSize);
3483 if (ValueInfo == NULL)
3484 {
3485 ErrorCode = ERROR_OUTOFMEMORY;
3486 goto Cleanup;
3487 }
3488
3489 Status = NtQueryValueKey (KeyHandle,
3490 &ValueName,
3491 KeyValuePartialInformation,
3492 ValueInfo,
3493 BufferSize,
3494 &ResultSize);
3495 TRACE("Status 0x%X\n", Status);
3496 if (Status == STATUS_BUFFER_OVERFLOW)
3497 {
3498 /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
3499 MaxCopy = 0;
3500 ErrorCode = lpData ? ERROR_MORE_DATA : ERROR_SUCCESS;
3501 }
3502 else if (!NT_SUCCESS(Status))
3503 {
3504 ErrorCode = RtlNtStatusToDosError (Status);
3505 MaxCopy = 0;
3506 if (lpcbData != NULL)
3507 {
3508 ResultSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + *lpcbData;
3509 }
3510 }
3511
3512 if (lpType != NULL)
3513 {
3514 *lpType = ValueInfo->Type;
3515 }
3516
3517 if (NT_SUCCESS(Status) && lpData != NULL)
3518 {
3519 RtlMoveMemory (lpData,
3520 ValueInfo->Data,
3521 min(ValueInfo->DataLength, MaxCopy));
3522 }
3523
3524 if ((ValueInfo->Type == REG_SZ) ||
3525 (ValueInfo->Type == REG_MULTI_SZ) ||
3526 (ValueInfo->Type == REG_EXPAND_SZ))
3527 {
3528 if (lpData != NULL && MaxCopy > ValueInfo->DataLength)
3529 {
3530 ((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
3531 }
3532
3533 if (lpcbData != NULL)
3534 {
3535 *lpcbData = (ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]));
3536 TRACE("(string) Returning Size: %lu\n", *lpcbData);
3537 }
3538 }
3539 else
3540 {
3541 if (lpcbData != NULL)
3542 {
3543 *lpcbData = ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
3544 TRACE("(other) Returning Size: %lu\n", *lpcbData);
3545 }
3546 }
3547
3548 TRACE("Type %d Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
3549
3550 RtlFreeHeap (ProcessHeap,
3551 0,
3552 ValueInfo);
3553
3554 Cleanup:
3555 ClosePredefKey(KeyHandle);
3556
3557 return ErrorCode;
3558 }
3559
3560
3561 /************************************************************************
3562 * RegQueryValueExA
3563 *
3564 * @implemented
3565 */
3566 LONG STDCALL
3567 RegQueryValueExA (HKEY hKey,
3568 LPCSTR lpValueName,
3569 LPDWORD lpReserved,
3570 LPDWORD lpType,
3571 LPBYTE lpData,
3572 LPDWORD lpcbData)
3573 {
3574 UNICODE_STRING ValueName;
3575 UNICODE_STRING ValueData;
3576 ANSI_STRING AnsiString;
3577 LONG ErrorCode;
3578 DWORD Length;
3579 DWORD Type;
3580
3581 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3582 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
3583
3584 if (lpData != NULL && lpcbData == NULL)
3585 {
3586 return ERROR_INVALID_PARAMETER;
3587 }
3588
3589 if (lpData)
3590 {
3591 ValueData.Length = 0;
3592 ValueData.MaximumLength = (*lpcbData + 1) * sizeof(WCHAR);
3593 ValueData.Buffer = RtlAllocateHeap (ProcessHeap,
3594 0,
3595 ValueData.MaximumLength);
3596 if (!ValueData.Buffer)
3597 {
3598 return ERROR_OUTOFMEMORY;
3599 }
3600 }
3601 else
3602 {
3603 ValueData.Buffer = NULL;
3604 ValueData.Length = 0;
3605 ValueData.MaximumLength = 0;
3606 }
3607
3608 RtlCreateUnicodeStringFromAsciiz (&ValueName,
3609 (LPSTR)lpValueName);
3610
3611 Length = (lpcbData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
3612 ErrorCode = RegQueryValueExW (hKey,
3613 ValueName.Buffer,
3614 lpReserved,
3615 &Type,
3616 (lpData == NULL) ? NULL : (LPBYTE)ValueData.Buffer,
3617 &Length);
3618 TRACE("ErrorCode %lu\n", ErrorCode);
3619 RtlFreeUnicodeString(&ValueName);
3620
3621 if (ErrorCode == ERROR_SUCCESS ||
3622 ErrorCode == ERROR_MORE_DATA)
3623 {
3624 if (lpType != NULL)
3625 {
3626 *lpType = Type;
3627 }
3628
3629 if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ))
3630 {
3631 if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
3632 {
3633 RtlInitAnsiString(&AnsiString, NULL);
3634 AnsiString.Buffer = (LPSTR)lpData;
3635 AnsiString.MaximumLength = *lpcbData;
3636 ValueData.Length = Length;
3637 ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
3638 RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
3639 }
3640 Length = Length / sizeof(WCHAR);
3641 }
3642 else if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
3643 {
3644 if (*lpcbData < Length)
3645 {
3646 ErrorCode = ERROR_MORE_DATA;
3647 }
3648 else
3649 {
3650 RtlMoveMemory(lpData, ValueData.Buffer, Length);
3651 }
3652 }
3653
3654 if (lpcbData != NULL)
3655 {
3656 *lpcbData = Length;
3657 }
3658 }
3659
3660 if (ValueData.Buffer != NULL)
3661 {
3662 RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
3663 }
3664
3665 return ErrorCode;
3666 }
3667
3668
3669 /************************************************************************
3670 * RegQueryValueA
3671 *
3672 * @implemented
3673 */
3674 LONG STDCALL
3675 RegQueryValueA (HKEY hKey,
3676 LPCSTR lpSubKey,
3677 LPSTR lpValue,
3678 PLONG lpcbValue)
3679 {
3680 WCHAR SubKeyNameBuffer[MAX_PATH+1];
3681 UNICODE_STRING SubKeyName;
3682 UNICODE_STRING Value;
3683 ANSI_STRING AnsiString;
3684 LONG ValueSize;
3685 LONG ErrorCode;
3686
3687 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
3688 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
3689
3690 if (lpValue != NULL &&
3691 lpcbValue == NULL)
3692 {
3693 return ERROR_INVALID_PARAMETER;
3694 }
3695
3696 RtlInitUnicodeString (&SubKeyName,
3697 NULL);
3698 RtlInitUnicodeString (&Value,
3699 NULL);
3700 if (lpSubKey != NULL &&
3701 strlen(lpSubKey) != 0)
3702 {
3703 RtlInitAnsiString (&AnsiString,
3704 (LPSTR)lpSubKey);
3705 SubKeyName.Buffer = &SubKeyNameBuffer[0];
3706 SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
3707 RtlAnsiStringToUnicodeString (&SubKeyName,
3708 &AnsiString,
3709 FALSE);
3710 }
3711
3712 if (lpValue != NULL)
3713 {
3714 ValueSize = *lpcbValue * sizeof(WCHAR);
3715 Value.MaximumLength = ValueSize;
3716 Value.Buffer = RtlAllocateHeap (ProcessHeap,
3717 0,
3718 ValueSize);
3719 if (Value.Buffer == NULL)
3720 {
3721 return ERROR_OUTOFMEMORY;
3722 }
3723 }
3724 else
3725 {
3726 ValueSize = 0;
3727 }
3728
3729 ErrorCode = RegQueryValueW (hKey,
3730 (LPCWSTR)SubKeyName.Buffer,
3731 Value.Buffer,
3732 &ValueSize);
3733 if (ErrorCode == ERROR_SUCCESS)
3734 {
3735 Value.Length = ValueSize;
3736 RtlInitAnsiString (&AnsiString,
3737 NULL);
3738 AnsiString.Buffer = lpValue;
3739 AnsiString.MaximumLength = *lpcbValue;
3740 RtlUnicodeStringToAnsiString (&AnsiString,
3741 &Value,
3742 FALSE);
3743 }
3744
3745 *lpcbValue = ValueSize;
3746 if (Value.Buffer != NULL)
3747 {
3748 RtlFreeHeap (ProcessHeap,
3749 0,
3750 Value.Buffer);
3751 }
3752
3753 return ErrorCode;
3754 }
3755
3756
3757 /************************************************************************
3758 * RegQueryValueW
3759 *
3760 * @implemented
3761 */
3762 LONG STDCALL
3763 RegQueryValueW (HKEY hKey,
3764 LPCWSTR lpSubKey,
3765 LPWSTR lpValue,
3766 PLONG lpcbValue)
3767 {
3768 OBJECT_ATTRIBUTES ObjectAttributes;
3769 UNICODE_STRING SubKeyString;
3770 HANDLE KeyHandle;
3771 HANDLE RealKey;
3772 LONG ErrorCode;
3773 BOOL CloseRealKey;
3774 NTSTATUS Status;
3775
3776 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
3777 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
3778
3779 Status = MapDefaultKey (&KeyHandle,
3780 hKey);
3781 if (!NT_SUCCESS(Status))
3782 {
3783 return RtlNtStatusToDosError (Status);
3784 }
3785
3786 if (lpSubKey != NULL &&
3787 wcslen(lpSubKey) != 0)
3788 {
3789 RtlInitUnicodeString (&SubKeyString,
3790 (LPWSTR)lpSubKey);
3791 InitializeObjectAttributes (&ObjectAttributes,
3792 &SubKeyString,
3793 OBJ_CASE_INSENSITIVE,
3794 KeyHandle,
3795 NULL);
3796 Status = NtOpenKey (&RealKey,
3797 KEY_QUERY_VALUE,
3798 &ObjectAttributes);
3799 if (!NT_SUCCESS(Status))
3800 {
3801 ErrorCode = RtlNtStatusToDosError (Status);
3802 goto Cleanup;
3803 }
3804 CloseRealKey = TRUE;
3805 }
3806 else
3807 {
3808 RealKey = hKey;
3809 CloseRealKey = FALSE;
3810 }
3811
3812 ErrorCode = RegQueryValueExW (RealKey,
3813 NULL,
3814 NULL,
3815 NULL,
3816 (LPBYTE)lpValue,
3817 (LPDWORD)lpcbValue);
3818 if (CloseRealKey)
3819 {
3820 NtClose (RealKey);
3821 }
3822
3823 Cleanup:
3824 ClosePredefKey(KeyHandle);
3825
3826 return ErrorCode;
3827 }
3828
3829
3830 /************************************************************************
3831 * RegReplaceKeyA
3832 *
3833 * @implemented
3834 */
3835 LONG STDCALL
3836 RegReplaceKeyA (HKEY hKey,
3837 LPCSTR lpSubKey,
3838 LPCSTR lpNewFile,
3839 LPCSTR lpOldFile)
3840 {
3841 UNICODE_STRING SubKey;
3842 UNICODE_STRING NewFile;
3843 UNICODE_STRING OldFile;
3844 LONG ErrorCode;
3845
3846 RtlCreateUnicodeStringFromAsciiz (&SubKey,
3847 (PCSZ)lpSubKey);
3848 RtlCreateUnicodeStringFromAsciiz (&OldFile,
3849 (PCSZ)lpOldFile);
3850 RtlCreateUnicodeStringFromAsciiz (&NewFile,
3851 (PCSZ)lpNewFile);
3852
3853 ErrorCode = RegReplaceKeyW (hKey,
3854 SubKey.Buffer,
3855 NewFile.Buffer,
3856 OldFile.Buffer);
3857
3858 RtlFreeUnicodeString (&OldFile);
3859 RtlFreeUnicodeString (&NewFile);
3860 RtlFreeUnicodeString (&SubKey);
3861
3862 return ErrorCode;
3863 }
3864
3865
3866 /************************************************************************
3867 * RegReplaceKeyW
3868 *
3869 * @unimplemented
3870 */
3871 LONG STDCALL
3872 RegReplaceKeyW (HKEY hKey,
3873 LPCWSTR lpSubKey,
3874 LPCWSTR lpNewFile,
3875 LPCWSTR lpOldFile)
3876 {
3877 OBJECT_ATTRIBUTES KeyObjectAttributes;
3878 OBJECT_ATTRIBUTES NewObjectAttributes;
3879 OBJECT_ATTRIBUTES OldObjectAttributes;
3880 UNICODE_STRING SubKeyName;
3881 UNICODE_STRING NewFileName;
3882 UNICODE_STRING OldFileName;
3883 BOOLEAN CloseRealKey;
3884 HANDLE RealKeyHandle;
3885 HANDLE KeyHandle;
3886 NTSTATUS Status;
3887 LONG ErrorCode = ERROR_SUCCESS;
3888
3889 if (hKey == HKEY_PERFORMANCE_DATA)
3890 {
3891 return ERROR_INVALID_HANDLE;
3892 }
3893
3894 Status = MapDefaultKey (&KeyHandle,
3895 hKey);
3896 if (!NT_SUCCESS(Status))
3897 {
3898 return RtlNtStatusToDosError (Status);
3899 }
3900
3901 /* Open the real key */
3902 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
3903 {
3904 RtlInitUnicodeString (&SubKeyName,
3905 (PWSTR)lpSubKey);
3906 InitializeObjectAttributes (&KeyObjectAttributes,
3907 &SubKeyName,
3908 OBJ_CASE_INSENSITIVE,
3909 KeyHandle,
3910 NULL);
3911 Status = NtOpenKey (&RealKeyHandle,
3912 MAXIMUM_ALLOWED,
3913 &KeyObjectAttributes);
3914 if (!NT_SUCCESS(Status))
3915 {
3916 ErrorCode = RtlNtStatusToDosError (Status);
3917 goto Cleanup;
3918 }
3919 CloseRealKey = TRUE;
3920 }
3921 else
3922 {
3923 RealKeyHandle = KeyHandle;
3924 CloseRealKey = FALSE;
3925 }
3926
3927 /* Convert new file name */
3928 if (!RtlDosPathNameToNtPathName_U (lpNewFile,
3929 &NewFileName,
3930 NULL,
3931 NULL))
3932 {
3933 if (CloseRealKey)
3934 {
3935 NtClose (RealKeyHandle);
3936 }
3937 ErrorCode = ERROR_INVALID_PARAMETER;
3938 goto Cleanup;
3939 }
3940
3941 InitializeObjectAttributes (&NewObjectAttributes,
3942 &NewFileName,
3943 OBJ_CASE_INSENSITIVE,
3944 NULL,
3945 NULL);
3946
3947 /* Convert old file name */
3948 if (!RtlDosPathNameToNtPathName_U (lpOldFile,
3949 &OldFileName,
3950 NULL,
3951 NULL))
3952 {
3953 RtlFreeHeap (RtlGetProcessHeap (),
3954 0,
3955 NewFileName.Buffer);
3956 if (CloseRealKey)
3957 {
3958 NtClose (RealKeyHandle);
3959 }
3960 ErrorCode = ERROR_INVALID_PARAMETER;
3961 goto Cleanup;
3962 }
3963
3964 InitializeObjectAttributes (&OldObjectAttributes,
3965 &OldFileName,
3966 OBJ_CASE_INSENSITIVE,
3967 NULL,
3968 NULL);
3969
3970 Status = NtReplaceKey (&NewObjectAttributes,
3971 RealKeyHandle,
3972 &OldObjectAttributes);
3973
3974 RtlFreeHeap (RtlGetProcessHeap (),
3975 0,
3976 OldFileName.Buffer);
3977 RtlFreeHeap (RtlGetProcessHeap (),
3978 0,
3979 NewFileName.Buffer);
3980
3981 if (CloseRealKey)
3982 {
3983 NtClose (RealKeyHandle);
3984 }
3985
3986 if (!NT_SUCCESS(Status))
3987 {
3988 return RtlNtStatusToDosError (Status);
3989 }
3990
3991 Cleanup:
3992 ClosePredefKey(KeyHandle);
3993
3994 return ErrorCode;
3995 }
3996
3997
3998 /************************************************************************
3999 * RegRestoreKeyA
4000 *
4001 * @implemented
4002 */
4003 LONG STDCALL
4004 RegRestoreKeyA (HKEY hKey,
4005 LPCSTR lpFile,
4006 DWORD dwFlags)
4007 {
4008 UNICODE_STRING FileName;
4009 LONG ErrorCode;
4010
4011 RtlCreateUnicodeStringFromAsciiz (&FileName,
4012 (PCSZ)lpFile);
4013
4014 ErrorCode = RegRestoreKeyW (hKey,
4015 FileName.Buffer,
4016 dwFlags);
4017
4018 RtlFreeUnicodeString (&FileName);
4019
4020 return ErrorCode;
4021 }
4022
4023
4024 /************************************************************************
4025 * RegRestoreKeyW
4026 *
4027 * @implemented
4028 */
4029 LONG STDCALL
4030 RegRestoreKeyW (HKEY hKey,
4031 LPCWSTR lpFile,
4032 DWORD dwFlags)
4033 {
4034 OBJECT_ATTRIBUTES ObjectAttributes;
4035 IO_STATUS_BLOCK IoStatusBlock;
4036 UNICODE_STRING FileName;
4037 HANDLE FileHandle;
4038 HANDLE KeyHandle;
4039 NTSTATUS Status;
4040
4041 if (hKey == HKEY_PERFORMANCE_DATA)
4042 {
4043 return ERROR_INVALID_HANDLE;
4044 }
4045
4046 Status = MapDefaultKey (&KeyHandle,
4047 hKey);
4048 if (!NT_SUCCESS(Status))
4049 {
4050 return RtlNtStatusToDosError (Status);
4051 }
4052
4053 if (!RtlDosPathNameToNtPathName_U (lpFile,
4054 &FileName,
4055 NULL,
4056 NULL))
4057 {
4058 Status = STATUS_INVALID_PARAMETER;
4059 goto Cleanup;
4060 }
4061
4062 InitializeObjectAttributes (&ObjectAttributes,
4063 &FileName,
4064 OBJ_CASE_INSENSITIVE,
4065 NULL,
4066 NULL);
4067
4068 Status = NtOpenFile (&FileHandle,
4069 FILE_GENERIC_READ,
4070 &ObjectAttributes,
4071 &IoStatusBlock,
4072 FILE_SHARE_READ,
4073 FILE_SYNCHRONOUS_IO_NONALERT);
4074 RtlFreeHeap (RtlGetProcessHeap(),
4075 0,
4076 FileName.Buffer);
4077 if (!NT_SUCCESS(Status))
4078 {
4079 goto Cleanup;
4080 }
4081
4082 Status = NtRestoreKey (KeyHandle,
4083 FileHandle,
4084 (ULONG)dwFlags);
4085 NtClose (FileHandle);
4086
4087 Cleanup:
4088 ClosePredefKey(KeyHandle);
4089
4090 if (!NT_SUCCESS(Status))
4091 {
4092 return RtlNtStatusToDosError (Status);
4093 }
4094
4095 return ERROR_SUCCESS;
4096 }
4097
4098
4099 /************************************************************************
4100 * RegSaveKeyA
4101 *
4102 * @implemented
4103 */
4104 LONG STDCALL
4105 RegSaveKeyA (HKEY hKey,
4106 LPCSTR lpFile,
4107 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4108 {
4109 UNICODE_STRING FileName;
4110 LONG ErrorCode;
4111
4112 RtlCreateUnicodeStringFromAsciiz (&FileName,
4113 (LPSTR)lpFile);
4114 ErrorCode = RegSaveKeyW (hKey,
4115 FileName.Buffer,
4116 lpSecurityAttributes);
4117 RtlFreeUnicodeString (&FileName);
4118
4119 return ErrorCode;
4120 }
4121
4122
4123 /************************************************************************
4124 * RegSaveKeyW
4125 *
4126 * @implemented
4127 */
4128 LONG STDCALL
4129 RegSaveKeyW (HKEY hKey,
4130 LPCWSTR lpFile,
4131 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4132 {
4133 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
4134 OBJECT_ATTRIBUTES ObjectAttributes;
4135 UNICODE_STRING FileName;
4136 IO_STATUS_BLOCK IoStatusBlock;
4137 HANDLE FileHandle;
4138 HANDLE KeyHandle;
4139 NTSTATUS Status;
4140
4141 Status = MapDefaultKey (&KeyHandle,
4142 hKey);
4143 if (!NT_SUCCESS(Status))
4144 {
4145 return RtlNtStatusToDosError (Status);
4146 }
4147
4148 if (!RtlDosPathNameToNtPathName_U (lpFile,
4149 &FileName,
4150 NULL,
4151 NULL))
4152 {
4153 Status = STATUS_INVALID_PARAMETER;
4154 goto Cleanup;
4155 }
4156
4157 if (lpSecurityAttributes != NULL)
4158 {
4159 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4160 }
4161
4162 InitializeObjectAttributes (&ObjectAttributes,
4163 &FileName,
4164 OBJ_CASE_INSENSITIVE,
4165 NULL,
4166 SecurityDescriptor);
4167 Status = NtCreateFile (&FileHandle,
4168 GENERIC_WRITE | SYNCHRONIZE,
4169 &ObjectAttributes,
4170 &IoStatusBlock,
4171 NULL,
4172 FILE_ATTRIBUTE_NORMAL,
4173 FILE_SHARE_READ,
4174 FILE_CREATE,
4175 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
4176 NULL,
4177 0);
4178 RtlFreeHeap (RtlGetProcessHeap (),
4179 0,
4180 FileName.Buffer);
4181 if (!NT_SUCCESS(Status))
4182 {
4183 goto Cleanup;
4184 }
4185
4186 Status = NtSaveKey (KeyHandle,
4187 FileHandle);
4188 NtClose (FileHandle);
4189
4190 Cleanup:
4191 ClosePredefKey(KeyHandle);
4192
4193 if (!NT_SUCCESS(Status))
4194 {
4195 return RtlNtStatusToDosError (Status);
4196 }
4197
4198 return ERROR_SUCCESS;
4199 }
4200
4201
4202 /************************************************************************
4203 * RegSetKeySecurity
4204 *
4205 * @implemented
4206 */
4207 LONG STDCALL
4208 RegSetKeySecurity (HKEY hKey,
4209 SECURITY_INFORMATION SecurityInformation,
4210 PSECURITY_DESCRIPTOR pSecurityDescriptor)
4211 {
4212 HANDLE KeyHandle;
4213 NTSTATUS Status;
4214
4215 if (hKey == HKEY_PERFORMANCE_DATA)
4216 {
4217 return ERROR_INVALID_HANDLE;
4218 }
4219
4220 Status = MapDefaultKey (&KeyHandle,
4221 hKey);
4222 if (!NT_SUCCESS(Status))
4223 {
4224 return RtlNtStatusToDosError (Status);
4225 }
4226
4227 Status = NtSetSecurityObject (KeyHandle,
4228 SecurityInformation,
4229 pSecurityDescriptor);
4230
4231 ClosePredefKey(KeyHandle);
4232
4233 if (!NT_SUCCESS(Status))
4234 {
4235 return RtlNtStatusToDosError (Status);
4236 }
4237
4238 return ERROR_SUCCESS;
4239 }
4240
4241
4242 /************************************************************************
4243 * RegSetValueExA
4244 *
4245 * @implemented
4246 */
4247 LONG STDCALL
4248 RegSetValueExA (HKEY hKey,
4249 LPCSTR lpValueName,
4250 DWORD Reserved,
4251 DWORD dwType,
4252 CONST BYTE* lpData,
4253 DWORD cbData)
4254 {
4255 UNICODE_STRING ValueName;
4256 LPWSTR pValueName;
4257 ANSI_STRING AnsiString;
4258 UNICODE_STRING Data;
4259 LONG ErrorCode;
4260 LPBYTE pData;
4261 DWORD DataSize;
4262
4263 if (lpValueName != NULL &&
4264 strlen(lpValueName) != 0)
4265 {
4266 RtlCreateUnicodeStringFromAsciiz (&ValueName,
4267 (PSTR)lpValueName);
4268 pValueName = (LPWSTR)ValueName.Buffer;
4269 }
4270 else
4271 {
4272 pValueName = NULL;
4273 }
4274
4275 if (((dwType == REG_SZ) ||
4276 (dwType == REG_MULTI_SZ) ||
4277 (dwType == REG_EXPAND_SZ)) &&
4278 (cbData != 0))
4279 {
4280 /* NT adds one if the caller forgot the NULL-termination character */
4281 if (lpData[cbData - 1] != '\0')
4282 {
4283 cbData++;
4284 }
4285
4286 RtlInitAnsiString (&AnsiString,
4287 NULL);
4288 AnsiString.Buffer = (PSTR)lpData;
4289 AnsiString.Length = cbData - 1;
4290 AnsiString.MaximumLength = cbData;
4291 RtlAnsiStringToUnicodeString (&Data,
4292 &AnsiString,
4293 TRUE);
4294 pData = (LPBYTE)Data.Buffer;
4295 DataSize = cbData * sizeof(WCHAR);
4296 }
4297 else
4298 {
4299 RtlInitUnicodeString (&Data,
4300 NULL);
4301 pData = (LPBYTE)lpData;
4302 DataSize = cbData;
4303 }
4304
4305 ErrorCode = RegSetValueExW (hKey,
4306 pValueName,
4307 Reserved,
4308 dwType,
4309 pData,
4310 DataSize);
4311 if (pValueName != NULL)
4312 {
4313 RtlFreeHeap (ProcessHeap,
4314 0,
4315 ValueName.Buffer);
4316 }
4317
4318 if (Data.Buffer != NULL)
4319 {
4320 RtlFreeHeap (ProcessHeap,
4321 0,
4322 Data.Buffer);
4323 }
4324
4325 return ErrorCode;
4326 }
4327
4328
4329 /************************************************************************
4330 * RegSetValueExW
4331 *
4332 * @implemented
4333 */
4334 LONG STDCALL
4335 RegSetValueExW (HKEY hKey,
4336 LPCWSTR lpValueName,
4337 DWORD Reserved,
4338 DWORD dwType,
4339 CONST BYTE* lpData,
4340 DWORD cbData)
4341 {
4342 UNICODE_STRING ValueName;
4343 PUNICODE_STRING pValueName;
4344 HANDLE KeyHandle;
4345 NTSTATUS Status;
4346
4347 Status = MapDefaultKey (&KeyHandle,
4348 hKey);
4349 if (!NT_SUCCESS(Status))
4350 {
4351 return RtlNtStatusToDosError (Status);
4352 }
4353
4354 if (lpValueName != NULL)
4355 {
4356 RtlInitUnicodeString (&ValueName,
4357 lpValueName);
4358 }
4359 else
4360 {
4361 RtlInitUnicodeString (&ValueName, L"");
4362 }
4363 pValueName = &ValueName;
4364
4365 if (((dwType == REG_SZ) ||
4366 (dwType == REG_MULTI_SZ) ||
4367 (dwType == REG_EXPAND_SZ)) &&
4368 (cbData != 0) && (*(((PWCHAR)lpData) + (cbData / sizeof(WCHAR)) - 1) != L'\0'))
4369 {
4370 /* NT adds one if the caller forgot the NULL-termination character */
4371 cbData += sizeof(WCHAR);
4372 }
4373
4374 Status = NtSetValueKey (KeyHandle,
4375 pValueName,
4376 0,
4377 dwType,
4378 (PVOID)lpData,
4379 (ULONG)cbData);
4380
4381 ClosePredefKey(KeyHandle);
4382
4383 if (!NT_SUCCESS(Status))
4384 {
4385 return RtlNtStatusToDosError (Status);
4386 }
4387
4388 return ERROR_SUCCESS;
4389 }
4390
4391
4392 /************************************************************************
4393 * RegSetValueA
4394 *
4395 * @implemented
4396 */
4397 LONG STDCALL
4398 RegSetValueA (HKEY hKey,
4399 LPCSTR lpSubKey,
4400 DWORD dwType,
4401 LPCSTR lpData,
4402 DWORD cbData)
4403 {
4404 LONG ret;
4405 HKEY hSubKey;
4406
4407 if (dwType != REG_SZ)
4408 {
4409 return ERROR_INVALID_PARAMETER;
4410 }
4411
4412 if (lpSubKey != NULL && lpSubKey[0] != '\0')
4413 {
4414 ret = RegCreateKeyA(hKey,
4415 lpSubKey,
4416 &hSubKey);
4417
4418 if (ret != ERROR_SUCCESS)
4419 {
4420 return ret;
4421 }
4422 }
4423 else
4424 hSubKey = hKey;
4425
4426 ret = RegSetValueExA(hSubKey,
4427 NULL,
4428 0,
4429 REG_SZ,
4430 (CONST BYTE*)lpData,
4431 strlen(lpData) + 1);
4432
4433 if (hSubKey != hKey)
4434 {
4435 RegCloseKey(hSubKey);
4436 }
4437
4438 return ret;
4439 }
4440
4441
4442 /************************************************************************
4443 * RegSetValueW
4444 *
4445 * @implemented
4446 */
4447 LONG STDCALL
4448 RegSetValueW (HKEY hKey,
4449 LPCWSTR lpSubKey,
4450 DWORD dwType,
4451 LPCWSTR lpData,
4452 DWORD cbData)
4453 {
4454 OBJECT_ATTRIBUTES ObjectAttributes;
4455 UNICODE_STRING SubKeyString;
4456 HANDLE KeyHandle;
4457 HANDLE RealKey;
4458 BOOL CloseRealKey;
4459 NTSTATUS Status;
4460 LONG ErrorCode;
4461
4462 Status = MapDefaultKey (&KeyHandle,
4463 hKey);
4464 if (!NT_SUCCESS(Status))
4465 {
4466 return RtlNtStatusToDosError (Status);
4467 }
4468
4469 if ((lpSubKey) && (wcslen(lpSubKey) != 0))
4470 {
4471 RtlInitUnicodeString (&SubKeyString,
4472 (LPWSTR)lpSubKey);
4473 InitializeObjectAttributes (&ObjectAttributes,
4474 &SubKeyString,
4475 OBJ_CASE_INSENSITIVE,
4476 KeyHandle,
4477 NULL);
4478 Status = NtOpenKey (&RealKey,
4479 KEY_SET_VALUE,
4480 &ObjectAttributes);
4481 if (!NT_SUCCESS(Status))
4482 {
4483 ErrorCode = RtlNtStatusToDosError (Status);
4484 goto Cleanup;
4485 }
4486 CloseRealKey = TRUE;
4487 }
4488 else
4489 {
4490 RealKey = hKey;
4491 CloseRealKey = FALSE;
4492 }
4493
4494 ErrorCode = RegSetValueExW (RealKey,
4495 NULL,
4496 0,
4497 dwType,
4498 (LPBYTE)lpData,
4499 cbData);
4500 if (CloseRealKey == TRUE)
4501 {
4502 NtClose (RealKey);
4503 }
4504
4505 Cleanup:
4506 ClosePredefKey(KeyHandle);
4507
4508 return ErrorCode;
4509 }
4510
4511
4512 /************************************************************************
4513 * RegUnLoadKeyA
4514 *
4515 * @implemented
4516 */
4517 LONG STDCALL
4518 RegUnLoadKeyA (HKEY hKey,
4519 LPCSTR lpSubKey)
4520 {
4521 UNICODE_STRING KeyName;
4522 DWORD ErrorCode;
4523
4524 RtlCreateUnicodeStringFromAsciiz (&KeyName,
4525 (LPSTR)lpSubKey);
4526
4527 ErrorCode = RegUnLoadKeyW (hKey,
4528 KeyName.Buffer);
4529
4530 RtlFreeUnicodeString (&KeyName);
4531
4532 return ErrorCode;
4533 }
4534
4535
4536 /************************************************************************
4537 * RegUnLoadKeyW
4538 *
4539 * @implemented
4540 */
4541 LONG STDCALL
4542 RegUnLoadKeyW (HKEY hKey,
4543 LPCWSTR lpSubKey)
4544 {
4545 OBJECT_ATTRIBUTES ObjectAttributes;
4546 UNICODE_STRING KeyName;
4547 HANDLE KeyHandle;
4548 NTSTATUS Status;
4549
4550 if (hKey == HKEY_PERFORMANCE_DATA)
4551 {
4552 return ERROR_INVALID_HANDLE;
4553 }
4554
4555 Status = MapDefaultKey (&KeyHandle, hKey);
4556 if (!NT_SUCCESS(Status))
4557 {
4558 return RtlNtStatusToDosError (Status);
4559 }
4560
4561 RtlInitUnicodeString (&KeyName,
4562 (LPWSTR)lpSubKey);
4563
4564 InitializeObjectAttributes (&ObjectAttributes,
4565 &KeyName,
4566 OBJ_CASE_INSENSITIVE,
4567 KeyHandle,
4568 NULL);
4569
4570 Status = NtUnloadKey (&ObjectAttributes);
4571
4572 ClosePredefKey(KeyHandle);
4573
4574 if (!NT_SUCCESS(Status))
4575 {
4576 return RtlNtStatusToDosError (Status);
4577 }
4578
4579 return ERROR_SUCCESS;
4580 }
4581
4582
4583 /************************************************************************
4584 * RegLoadMUIStringW
4585 *
4586 * @unimplemented
4587 */
4588 LONG STDCALL
4589 RegLoadMUIStringW(IN HKEY hKey,
4590 IN LPCWSTR pszValue OPTIONAL,
4591 OUT LPWSTR pszOutBuf,
4592 IN ULONG cbOutBuf,
4593 IN ULONG Reserved,
4594 IN LPCWSTR pszDirectory OPTIONAL)
4595 {
4596 DPRINT1("RegLoadMUIStringW(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4597 hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
4598 return ERROR_CALL_NOT_IMPLEMENTED;
4599 }
4600
4601
4602 /************************************************************************
4603 * RegLoadMUIStringA
4604 *
4605 * @unimplemented
4606 */
4607 LONG STDCALL
4608 RegLoadMUIStringA(IN HKEY hKey,
4609 IN LPCSTR pszValue OPTIONAL,
4610 OUT LPSTR pszOutBuf,
4611 IN ULONG cbOutBuf,
4612 IN ULONG Reserved,
4613 IN LPCSTR pszDirectory OPTIONAL)
4614 {
4615 DPRINT1("RegLoadMUIStringA(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4616 hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
4617 return ERROR_CALL_NOT_IMPLEMENTED;
4618 }
4619
4620
4621 /* EOF */