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