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