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