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