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