Merge r68232 to get Windows' rpcrt4.dll to work under ReactOS.
[reactos.git] / reactos / dll / win32 / advapi32 / reg / reg.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 * 19990309 EA Stubs
11 * 20050502 Fireball imported some stuff from WINE
12 */
13
14 /* INCLUDES *****************************************************************/
15
16 #include <advapi32.h>
17
18 #include <ndk/cmfuncs.h>
19 #include <pseh/pseh2.h>
20
21 #include "reg.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(reg);
24
25 /* DEFINES ******************************************************************/
26
27 #define MAX_DEFAULT_HANDLES 6
28 #define REG_MAX_NAME_SIZE 256
29 #define REG_MAX_DATA_SIZE 2048
30
31 /* GLOBALS ******************************************************************/
32
33 static RTL_CRITICAL_SECTION HandleTableCS;
34 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
35 static HANDLE ProcessHeap;
36 static BOOLEAN DefaultHandlesDisabled = FALSE;
37 static BOOLEAN DefaultHandleHKUDisabled = FALSE;
38 static BOOLEAN DllInitialized = FALSE; /* HACK */
39
40 /* PROTOTYPES ***************************************************************/
41
42 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
43 static VOID CloseDefaultKeys(VOID);
44 #define ClosePredefKey(Handle) \
45 if ((ULONG_PTR)Handle & 0x1) { \
46 NtClose(Handle); \
47 }
48 #define IsPredefKey(HKey) \
49 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
50 #define GetPredefKeyIndex(HKey) \
51 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
52
53 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
54 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
55 static NTSTATUS OpenUsersKey (PHANDLE KeyHandle);
56 static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
57
58
59 /* FUNCTIONS ****************************************************************/
60 /* check if value type needs string conversion (Ansi<->Unicode) */
61 __inline static int is_string( DWORD type )
62 {
63 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
64 }
65
66 /************************************************************************
67 * RegInitDefaultHandles
68 */
69 BOOL
70 RegInitialize(VOID)
71 {
72 TRACE("RegInitialize()\n");
73
74 /* Lazy init hack */
75 if (!DllInitialized)
76 {
77 ProcessHeap = RtlGetProcessHeap();
78 RtlZeroMemory(DefaultHandleTable,
79 MAX_DEFAULT_HANDLES * sizeof(HANDLE));
80 RtlInitializeCriticalSection(&HandleTableCS);
81
82 DllInitialized = TRUE;
83 }
84
85 return TRUE;
86 }
87
88
89 /************************************************************************
90 * RegInit
91 */
92 BOOL
93 RegCleanup(VOID)
94 {
95 TRACE("RegCleanup()\n");
96
97 CloseDefaultKeys();
98 RtlDeleteCriticalSection(&HandleTableCS);
99
100 return TRUE;
101 }
102
103
104 static NTSTATUS
105 OpenPredefinedKey(IN ULONG Index,
106 OUT HANDLE Handle)
107 {
108 NTSTATUS Status;
109
110 switch (Index)
111 {
112 case 0: /* HKEY_CLASSES_ROOT */
113 Status = OpenClassesRootKey (Handle);
114 break;
115
116 case 1: /* HKEY_CURRENT_USER */
117 Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
118 Handle);
119 break;
120
121 case 2: /* HKEY_LOCAL_MACHINE */
122 Status = OpenLocalMachineKey (Handle);
123 break;
124
125 case 3: /* HKEY_USERS */
126 Status = OpenUsersKey (Handle);
127 break;
128 #if 0
129 case 4: /* HKEY_PERFORMANCE_DATA */
130 Status = OpenPerformanceDataKey (Handle);
131 break;
132 #endif
133
134 case 5: /* HKEY_CURRENT_CONFIG */
135 Status = OpenCurrentConfigKey (Handle);
136 break;
137
138 case 6: /* HKEY_DYN_DATA */
139 Status = STATUS_NOT_IMPLEMENTED;
140 break;
141
142 default:
143 WARN("MapDefaultHandle() no handle creator\n");
144 Status = STATUS_INVALID_PARAMETER;
145 break;
146 }
147
148 return Status;
149 }
150
151
152 static NTSTATUS
153 MapDefaultKey(OUT PHANDLE RealKey,
154 IN HKEY Key)
155 {
156 PHANDLE Handle;
157 ULONG Index;
158 BOOLEAN DoOpen, DefDisabled;
159 NTSTATUS Status = STATUS_SUCCESS;
160
161 TRACE("MapDefaultKey (Key %x)\n", Key);
162
163 if (!IsPredefKey(Key))
164 {
165 *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
166 return STATUS_SUCCESS;
167 }
168
169 /* Handle special cases here */
170 Index = GetPredefKeyIndex(Key);
171 if (Index >= MAX_DEFAULT_HANDLES)
172 {
173 return STATUS_INVALID_PARAMETER;
174 }
175 RegInitialize(); /* HACK until delay-loading is implemented */
176 RtlEnterCriticalSection (&HandleTableCS);
177
178 if (Key == HKEY_CURRENT_USER)
179 DefDisabled = DefaultHandleHKUDisabled;
180 else
181 DefDisabled = DefaultHandlesDisabled;
182
183 if (!DefDisabled)
184 {
185 Handle = &DefaultHandleTable[Index];
186 DoOpen = (*Handle == NULL);
187 }
188 else
189 {
190 Handle = RealKey;
191 DoOpen = TRUE;
192 }
193
194 if (DoOpen)
195 {
196 /* create/open the default handle */
197 Status = OpenPredefinedKey(Index,
198 Handle);
199 }
200
201 if (NT_SUCCESS(Status))
202 {
203 if (!DefDisabled)
204 *RealKey = *Handle;
205 else
206 *(PULONG_PTR)Handle |= 0x1;
207 }
208
209 RtlLeaveCriticalSection (&HandleTableCS);
210
211 return Status;
212 }
213
214
215 static VOID
216 CloseDefaultKeys(VOID)
217 {
218 ULONG i;
219 RegInitialize(); /* HACK until delay-loading is implemented */
220 RtlEnterCriticalSection(&HandleTableCS);
221
222 for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
223 {
224 if (DefaultHandleTable[i] != NULL)
225 {
226 NtClose(DefaultHandleTable[i]);
227 DefaultHandleTable[i] = NULL;
228 }
229 }
230
231 RtlLeaveCriticalSection(&HandleTableCS);
232 }
233
234
235 static NTSTATUS
236 OpenClassesRootKey(_Out_ PHANDLE KeyHandle)
237 {
238 OBJECT_ATTRIBUTES Attributes;
239 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
240 NTSTATUS Status;
241
242 TRACE("OpenClassesRootKey()\n");
243
244 InitializeObjectAttributes(&Attributes,
245 &KeyName,
246 OBJ_CASE_INSENSITIVE,
247 NULL,
248 NULL);
249 Status = NtOpenKey(KeyHandle,
250 MAXIMUM_ALLOWED,
251 &Attributes);
252
253 if (!NT_SUCCESS(Status))
254 return Status;
255
256 /* Mark it as HKCR */
257 MakeHKCRKey((HKEY*)KeyHandle);
258
259 return Status;
260 }
261
262
263 static NTSTATUS
264 OpenLocalMachineKey(PHANDLE KeyHandle)
265 {
266 OBJECT_ATTRIBUTES Attributes;
267 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
268 NTSTATUS Status;
269
270 TRACE("OpenLocalMachineKey()\n");
271
272 InitializeObjectAttributes(&Attributes,
273 &KeyName,
274 OBJ_CASE_INSENSITIVE,
275 NULL,
276 NULL);
277 Status = NtOpenKey(KeyHandle,
278 MAXIMUM_ALLOWED,
279 &Attributes);
280
281 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
282
283 return Status;
284 }
285
286
287 static NTSTATUS
288 OpenUsersKey(PHANDLE KeyHandle)
289 {
290 OBJECT_ATTRIBUTES Attributes;
291 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User");
292
293 TRACE("OpenUsersKey()\n");
294
295 InitializeObjectAttributes(&Attributes,
296 &KeyName,
297 OBJ_CASE_INSENSITIVE,
298 NULL,
299 NULL);
300 return NtOpenKey(KeyHandle,
301 MAXIMUM_ALLOWED,
302 &Attributes);
303 }
304
305
306 static NTSTATUS
307 OpenCurrentConfigKey (PHANDLE KeyHandle)
308 {
309 OBJECT_ATTRIBUTES Attributes;
310 UNICODE_STRING KeyName =
311 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
312
313 TRACE("OpenCurrentConfigKey()\n");
314
315 InitializeObjectAttributes(&Attributes,
316 &KeyName,
317 OBJ_CASE_INSENSITIVE,
318 NULL,
319 NULL);
320 return NtOpenKey(KeyHandle,
321 MAXIMUM_ALLOWED,
322 &Attributes);
323 }
324
325
326 /************************************************************************
327 * RegDisablePredefinedCache
328 *
329 * @implemented
330 */
331 LONG WINAPI
332 RegDisablePredefinedCache(VOID)
333 {
334 RegInitialize(); /* HACK until delay-loading is implemented */
335 RtlEnterCriticalSection(&HandleTableCS);
336 DefaultHandleHKUDisabled = TRUE;
337 RtlLeaveCriticalSection(&HandleTableCS);
338 return ERROR_SUCCESS;
339 }
340
341
342 /************************************************************************
343 * RegDisablePredefinedCacheEx
344 *
345 * @implemented
346 */
347 LONG WINAPI
348 RegDisablePredefinedCacheEx(VOID)
349 {
350 RegInitialize(); /* HACK until delay-loading is implemented */
351 RtlEnterCriticalSection(&HandleTableCS);
352 DefaultHandlesDisabled = TRUE;
353 DefaultHandleHKUDisabled = TRUE;
354 RtlLeaveCriticalSection(&HandleTableCS);
355 return ERROR_SUCCESS;
356 }
357
358
359 /************************************************************************
360 * RegOverridePredefKey
361 *
362 * @implemented
363 */
364 LONG WINAPI
365 RegOverridePredefKey(IN HKEY hKey,
366 IN HKEY hNewHKey OPTIONAL)
367 {
368 LONG ErrorCode = ERROR_SUCCESS;
369
370 if ((hKey == HKEY_CLASSES_ROOT ||
371 hKey == HKEY_CURRENT_CONFIG ||
372 hKey == HKEY_CURRENT_USER ||
373 hKey == HKEY_LOCAL_MACHINE ||
374 hKey == HKEY_PERFORMANCE_DATA ||
375 hKey == HKEY_USERS) &&
376 !IsPredefKey(hNewHKey))
377 {
378 PHANDLE Handle;
379 ULONG Index;
380
381 Index = GetPredefKeyIndex(hKey);
382 Handle = &DefaultHandleTable[Index];
383
384 if (hNewHKey == NULL)
385 {
386 /* restore the default mapping */
387 NTSTATUS Status = OpenPredefinedKey(Index,
388 &hNewHKey);
389 if (!NT_SUCCESS(Status))
390 {
391 return RtlNtStatusToDosError(Status);
392 }
393
394 ASSERT(hNewHKey != NULL);
395 }
396 RegInitialize(); /* HACK until delay-loading is implemented */
397 RtlEnterCriticalSection(&HandleTableCS);
398
399 /* close the currently mapped handle if existing */
400 if (*Handle != NULL)
401 {
402 NtClose(*Handle);
403 }
404
405 /* update the mapping */
406 *Handle = hNewHKey;
407
408 RtlLeaveCriticalSection(&HandleTableCS);
409 }
410 else
411 ErrorCode = ERROR_INVALID_HANDLE;
412
413 return ErrorCode;
414 }
415
416
417 /************************************************************************
418 * RegCloseKey
419 *
420 * @implemented
421 */
422 LONG WINAPI
423 RegCloseKey(HKEY hKey)
424 {
425 NTSTATUS Status;
426
427 /* don't close null handle or a pseudo handle */
428 if ((!hKey) || (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000))
429 {
430 return ERROR_INVALID_HANDLE;
431 }
432
433 Status = NtClose(hKey);
434 if (!NT_SUCCESS(Status))
435 {
436 return RtlNtStatusToDosError(Status);
437 }
438
439 return ERROR_SUCCESS;
440 }
441
442
443 static NTSTATUS
444 RegpCopyTree(IN HKEY hKeySrc,
445 IN HKEY hKeyDest)
446 {
447 typedef struct
448 {
449 LIST_ENTRY ListEntry;
450 HANDLE hKeySrc;
451 HANDLE hKeyDest;
452 } REGP_COPY_KEYS, *PREGP_COPY_KEYS;
453
454 LIST_ENTRY copyQueueHead;
455 PREGP_COPY_KEYS copyKeys, newCopyKeys;
456 union
457 {
458 KEY_VALUE_FULL_INFORMATION *KeyValue;
459 KEY_NODE_INFORMATION *KeyNode;
460 PVOID Buffer;
461 } Info;
462 ULONG Index, BufferSizeRequired, BufferSize = 0x200;
463 NTSTATUS Status = STATUS_SUCCESS;
464 NTSTATUS Status2 = STATUS_SUCCESS;
465
466 InitializeListHead(&copyQueueHead);
467
468 Info.Buffer = RtlAllocateHeap(ProcessHeap,
469 0,
470 BufferSize);
471 if (Info.Buffer == NULL)
472 {
473 return STATUS_INSUFFICIENT_RESOURCES;
474 }
475
476 copyKeys = RtlAllocateHeap(ProcessHeap,
477 0,
478 sizeof(REGP_COPY_KEYS));
479 if (copyKeys != NULL)
480 {
481 copyKeys->hKeySrc = hKeySrc;
482 copyKeys->hKeyDest = hKeyDest;
483 InsertHeadList(&copyQueueHead,
484 &copyKeys->ListEntry);
485
486 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
487
488 do
489 {
490 copyKeys = CONTAINING_RECORD(copyQueueHead.Flink,
491 REGP_COPY_KEYS,
492 ListEntry);
493
494 /* enumerate all values and copy them */
495 Index = 0;
496 for (;;)
497 {
498 Status2 = NtEnumerateValueKey(copyKeys->hKeySrc,
499 Index,
500 KeyValueFullInformation,
501 Info.KeyValue,
502 BufferSize,
503 &BufferSizeRequired);
504 if (NT_SUCCESS(Status2))
505 {
506 UNICODE_STRING ValueName;
507 PVOID Data;
508
509 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
510 ValueName.Length = Info.KeyValue->NameLength;
511 ValueName.MaximumLength = ValueName.Length;
512 ValueName.Buffer = Info.KeyValue->Name;
513
514 Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset);
515
516 Status2 = NtSetValueKey(copyKeys->hKeyDest,
517 &ValueName,
518 Info.KeyValue->TitleIndex,
519 Info.KeyValue->Type,
520 Data,
521 Info.KeyValue->DataLength);
522
523 /* don't break, let's try to copy as many values as possible */
524 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
525 {
526 Status = Status2;
527 }
528
529 Index++;
530 }
531 else if (Status2 == STATUS_BUFFER_OVERFLOW)
532 {
533 PVOID Buffer;
534
535 ASSERT(BufferSize < BufferSizeRequired);
536
537 Buffer = RtlReAllocateHeap(ProcessHeap,
538 0,
539 Info.Buffer,
540 BufferSizeRequired);
541 if (Buffer != NULL)
542 {
543 Info.Buffer = Buffer;
544 /* try again */
545 }
546 else
547 {
548 /* don't break, let's try to copy as many values as possible */
549 Status2 = STATUS_INSUFFICIENT_RESOURCES;
550 Index++;
551
552 if (NT_SUCCESS(Status))
553 {
554 Status = Status2;
555 }
556 }
557 }
558 else
559 {
560 /* break to avoid an infinite loop in case of denied access or
561 other errors! */
562 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
563 {
564 Status = Status2;
565 }
566
567 break;
568 }
569 }
570
571 /* enumerate all subkeys and open and enqueue them */
572 Index = 0;
573 for (;;)
574 {
575 Status2 = NtEnumerateKey(copyKeys->hKeySrc,
576 Index,
577 KeyNodeInformation,
578 Info.KeyNode,
579 BufferSize,
580 &BufferSizeRequired);
581 if (NT_SUCCESS(Status2))
582 {
583 HANDLE KeyHandle, NewKeyHandle;
584 OBJECT_ATTRIBUTES ObjectAttributes;
585 UNICODE_STRING SubKeyName, ClassName;
586
587 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
588 SubKeyName.Length = Info.KeyNode->NameLength;
589 SubKeyName.MaximumLength = SubKeyName.Length;
590 SubKeyName.Buffer = Info.KeyNode->Name;
591 ClassName.Length = Info.KeyNode->ClassLength;
592 ClassName.MaximumLength = ClassName.Length;
593 ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset);
594
595 /* open the subkey with sufficient rights */
596
597 InitializeObjectAttributes(&ObjectAttributes,
598 &SubKeyName,
599 OBJ_CASE_INSENSITIVE,
600 copyKeys->hKeySrc,
601 NULL);
602
603 Status2 = NtOpenKey(&KeyHandle,
604 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
605 &ObjectAttributes);
606 if (NT_SUCCESS(Status2))
607 {
608 /* FIXME - attempt to query the security information */
609
610 InitializeObjectAttributes(&ObjectAttributes,
611 &SubKeyName,
612 OBJ_CASE_INSENSITIVE,
613 copyKeys->hKeyDest,
614 NULL);
615
616 Status2 = NtCreateKey(&NewKeyHandle,
617 KEY_ALL_ACCESS,
618 &ObjectAttributes,
619 Info.KeyNode->TitleIndex,
620 &ClassName,
621 0,
622 NULL);
623 if (NT_SUCCESS(Status2))
624 {
625 newCopyKeys = RtlAllocateHeap(ProcessHeap,
626 0,
627 sizeof(REGP_COPY_KEYS));
628 if (newCopyKeys != NULL)
629 {
630 /* save the handles and enqueue the subkey */
631 newCopyKeys->hKeySrc = KeyHandle;
632 newCopyKeys->hKeyDest = NewKeyHandle;
633 InsertTailList(&copyQueueHead,
634 &newCopyKeys->ListEntry);
635 }
636 else
637 {
638 NtClose(KeyHandle);
639 NtClose(NewKeyHandle);
640
641 Status2 = STATUS_INSUFFICIENT_RESOURCES;
642 }
643 }
644 else
645 {
646 NtClose(KeyHandle);
647 }
648 }
649
650 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
651 {
652 Status = Status2;
653 }
654
655 Index++;
656 }
657 else if (Status2 == STATUS_BUFFER_OVERFLOW)
658 {
659 PVOID Buffer;
660
661 ASSERT(BufferSize < BufferSizeRequired);
662
663 Buffer = RtlReAllocateHeap(ProcessHeap,
664 0,
665 Info.Buffer,
666 BufferSizeRequired);
667 if (Buffer != NULL)
668 {
669 Info.Buffer = Buffer;
670 /* try again */
671 }
672 else
673 {
674 /* don't break, let's try to copy as many keys as possible */
675 Status2 = STATUS_INSUFFICIENT_RESOURCES;
676 Index++;
677
678 if (NT_SUCCESS(Status))
679 {
680 Status = Status2;
681 }
682 }
683 }
684 else
685 {
686 /* break to avoid an infinite loop in case of denied access or
687 other errors! */
688 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
689 {
690 Status = Status2;
691 }
692
693 break;
694 }
695 }
696
697 /* close the handles and remove the entry from the list */
698 if (copyKeys->hKeySrc != hKeySrc)
699 {
700 NtClose(copyKeys->hKeySrc);
701 }
702 if (copyKeys->hKeyDest != hKeyDest)
703 {
704 NtClose(copyKeys->hKeyDest);
705 }
706
707 RemoveEntryList(&copyKeys->ListEntry);
708
709 RtlFreeHeap(ProcessHeap,
710 0,
711 copyKeys);
712 } while (!IsListEmpty(&copyQueueHead));
713 }
714 else
715 Status = STATUS_INSUFFICIENT_RESOURCES;
716
717 RtlFreeHeap(ProcessHeap,
718 0,
719 Info.Buffer);
720
721 return Status;
722 }
723
724
725 /************************************************************************
726 * RegCopyTreeW
727 *
728 * @implemented
729 */
730 LONG WINAPI
731 RegCopyTreeW(IN HKEY hKeySrc,
732 IN LPCWSTR lpSubKey OPTIONAL,
733 IN HKEY hKeyDest)
734 {
735 HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
736 NTSTATUS Status;
737
738 Status = MapDefaultKey(&KeyHandle,
739 hKeySrc);
740 if (!NT_SUCCESS(Status))
741 {
742 return RtlNtStatusToDosError(Status);
743 }
744
745 Status = MapDefaultKey(&DestKeyHandle,
746 hKeyDest);
747 if (!NT_SUCCESS(Status))
748 {
749 goto Cleanup2;
750 }
751
752 if (lpSubKey != NULL)
753 {
754 OBJECT_ATTRIBUTES ObjectAttributes;
755 UNICODE_STRING SubKeyName;
756
757 RtlInitUnicodeString(&SubKeyName,
758 (LPWSTR)lpSubKey);
759
760 InitializeObjectAttributes(&ObjectAttributes,
761 &SubKeyName,
762 OBJ_CASE_INSENSITIVE,
763 KeyHandle,
764 NULL);
765
766 Status = NtOpenKey(&SubKeyHandle,
767 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
768 &ObjectAttributes);
769 if (!NT_SUCCESS(Status))
770 {
771 goto Cleanup;
772 }
773
774 CurKey = SubKeyHandle;
775 }
776 else
777 CurKey = KeyHandle;
778
779 Status = RegpCopyTree(CurKey,
780 hKeyDest);
781
782 if (SubKeyHandle != NULL)
783 {
784 NtClose(SubKeyHandle);
785 }
786
787 Cleanup:
788 ClosePredefKey(DestKeyHandle);
789 Cleanup2:
790 ClosePredefKey(KeyHandle);
791
792 if (!NT_SUCCESS(Status))
793 {
794 return RtlNtStatusToDosError(Status);
795 }
796
797 return ERROR_SUCCESS;
798 }
799
800
801 /************************************************************************
802 * RegCopyTreeA
803 *
804 * @implemented
805 */
806 LONG WINAPI
807 RegCopyTreeA(IN HKEY hKeySrc,
808 IN LPCSTR lpSubKey OPTIONAL,
809 IN HKEY hKeyDest)
810 {
811 UNICODE_STRING SubKeyName = { 0, 0, NULL };
812 LONG Ret;
813
814 if (lpSubKey != NULL &&
815 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
816 (LPSTR)lpSubKey))
817 {
818 return ERROR_NOT_ENOUGH_MEMORY;
819 }
820
821 Ret = RegCopyTreeW(hKeySrc,
822 SubKeyName.Buffer,
823 hKeyDest);
824
825 RtlFreeUnicodeString(&SubKeyName);
826
827 return Ret;
828 }
829
830
831 /************************************************************************
832 * RegConnectRegistryA
833 *
834 * @implemented
835 */
836 LONG WINAPI
837 RegConnectRegistryA(IN LPCSTR lpMachineName,
838 IN HKEY hKey,
839 OUT PHKEY phkResult)
840 {
841 UNICODE_STRING MachineName = { 0, 0, NULL };
842 LONG Ret;
843
844 if (lpMachineName != NULL &&
845 !RtlCreateUnicodeStringFromAsciiz(&MachineName,
846 (LPSTR)lpMachineName))
847 {
848 return ERROR_NOT_ENOUGH_MEMORY;
849 }
850
851 Ret = RegConnectRegistryW(MachineName.Buffer,
852 hKey,
853 phkResult);
854
855 RtlFreeUnicodeString(&MachineName);
856
857 return Ret;
858 }
859
860
861 /************************************************************************
862 * RegConnectRegistryW
863 *
864 * @unimplemented
865 */
866 LONG WINAPI
867 RegConnectRegistryW(LPCWSTR lpMachineName,
868 HKEY hKey,
869 PHKEY phkResult)
870 {
871 LONG ret;
872
873 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
874
875 if (!lpMachineName || !*lpMachineName)
876 {
877 /* Use the local machine name */
878 ret = RegOpenKeyW( hKey, NULL, phkResult );
879 }
880 else
881 {
882 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
883 DWORD len = sizeof(compName) / sizeof(WCHAR);
884
885 /* MSDN says lpMachineName must start with \\ : not so */
886 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
887 lpMachineName += 2;
888
889 if (GetComputerNameW(compName, &len))
890 {
891 if (!_wcsicmp(lpMachineName, compName))
892 ret = RegOpenKeyW(hKey, NULL, phkResult);
893 else
894 {
895 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
896 ret = ERROR_BAD_NETPATH;
897 }
898 }
899 else
900 ret = GetLastError();
901 }
902
903 return ret;
904 }
905
906
907 /************************************************************************
908 * CreateNestedKey
909 *
910 * Create key and all necessary intermediate keys
911 */
912 static NTSTATUS
913 CreateNestedKey(PHKEY KeyHandle,
914 POBJECT_ATTRIBUTES ObjectAttributes,
915 PUNICODE_STRING ClassString,
916 DWORD dwOptions,
917 REGSAM samDesired,
918 DWORD *lpdwDisposition)
919 {
920 OBJECT_ATTRIBUTES LocalObjectAttributes;
921 UNICODE_STRING LocalKeyName;
922 ULONG Disposition;
923 NTSTATUS Status;
924 ULONG FullNameLength;
925 ULONG Length;
926 PWCHAR Ptr;
927 HANDLE LocalKeyHandle;
928
929 Status = NtCreateKey((PHANDLE) KeyHandle,
930 samDesired,
931 ObjectAttributes,
932 0,
933 ClassString,
934 dwOptions,
935 (PULONG)lpdwDisposition);
936 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
937 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
938 return Status;
939
940 /* Copy object attributes */
941 RtlCopyMemory(&LocalObjectAttributes,
942 ObjectAttributes,
943 sizeof(OBJECT_ATTRIBUTES));
944 RtlCreateUnicodeString(&LocalKeyName,
945 ObjectAttributes->ObjectName->Buffer);
946 LocalObjectAttributes.ObjectName = &LocalKeyName;
947 FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
948
949 LocalKeyHandle = NULL;
950
951 /* Remove the last part of the key name and try to create the key again. */
952 while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
953 {
954 Ptr = wcsrchr(LocalKeyName.Buffer, '\\');
955 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
956 {
957 Status = STATUS_UNSUCCESSFUL;
958 break;
959 }
960
961 *Ptr = (WCHAR)0;
962 LocalKeyName.Length = wcslen(LocalKeyName.Buffer) * sizeof(WCHAR);
963
964 Status = NtCreateKey(&LocalKeyHandle,
965 KEY_CREATE_SUB_KEY,
966 &LocalObjectAttributes,
967 0,
968 NULL,
969 0,
970 &Disposition);
971 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
972 }
973
974 if (!NT_SUCCESS(Status))
975 {
976 RtlFreeUnicodeString(&LocalKeyName);
977 return Status;
978 }
979
980 /* Add removed parts of the key name and create them too. */
981 Length = wcslen(LocalKeyName.Buffer);
982 while (TRUE)
983 {
984 if (LocalKeyHandle)
985 NtClose (LocalKeyHandle);
986
987 LocalKeyName.Buffer[Length] = L'\\';
988 Length = wcslen (LocalKeyName.Buffer);
989 LocalKeyName.Length = Length * sizeof(WCHAR);
990
991 if (Length == FullNameLength)
992 {
993 Status = NtCreateKey((PHANDLE) KeyHandle,
994 samDesired,
995 ObjectAttributes,
996 0,
997 ClassString,
998 dwOptions,
999 (PULONG)lpdwDisposition);
1000 break;
1001 }
1002
1003 Status = NtCreateKey(&LocalKeyHandle,
1004 KEY_CREATE_SUB_KEY,
1005 &LocalObjectAttributes,
1006 0,
1007 NULL,
1008 0,
1009 &Disposition);
1010 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
1011 if (!NT_SUCCESS(Status))
1012 break;
1013 }
1014
1015 RtlFreeUnicodeString(&LocalKeyName);
1016
1017 return Status;
1018 }
1019
1020
1021 /************************************************************************
1022 * RegCreateKeyExA
1023 *
1024 * @implemented
1025 */
1026 LONG WINAPI
1027 RegCreateKeyExA(
1028 _In_ HKEY hKey,
1029 _In_ LPCSTR lpSubKey,
1030 _In_ DWORD Reserved,
1031 _In_ LPSTR lpClass,
1032 _In_ DWORD dwOptions,
1033 _In_ REGSAM samDesired,
1034 _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
1035 _Out_ PHKEY phkResult,
1036 _Out_ LPDWORD lpdwDisposition)
1037 {
1038 UNICODE_STRING SubKeyString;
1039 UNICODE_STRING ClassString;
1040 DWORD ErrorCode;
1041
1042 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 RtlInitUnicodeString(&UnicodeString,
3608 NULL);
3609 if (lpClass != NULL)
3610 {
3611 RtlInitEmptyUnicodeString(&UnicodeString,
3612 ClassName,
3613 sizeof(ClassName));
3614 cClass = sizeof(ClassName) / sizeof(WCHAR);
3615 }
3616
3617 ErrorCode = RegQueryInfoKeyW(hKey,
3618 UnicodeString.Buffer,
3619 &cClass,
3620 lpReserved,
3621 lpcSubKeys,
3622 lpcMaxSubKeyLen,
3623 lpcMaxClassLen,
3624 lpcValues,
3625 lpcMaxValueNameLen,
3626 lpcMaxValueLen,
3627 lpcbSecurityDescriptor,
3628 lpftLastWriteTime);
3629 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
3630 {
3631 if (*lpcClass == 0)
3632 {
3633 return ErrorCode;
3634 }
3635
3636 RtlInitEmptyAnsiString(&AnsiString, lpClass, *lpcClass);
3637 UnicodeString.Length = cClass * sizeof(WCHAR);
3638 Status = RtlUnicodeStringToAnsiString(&AnsiString,
3639 &UnicodeString,
3640 FALSE);
3641 ErrorCode = RtlNtStatusToDosError(Status);
3642 cClass = AnsiString.Length;
3643 lpClass[*lpcClass - 1] = 0;
3644 }
3645
3646 if (lpcClass != NULL)
3647 {
3648 *lpcClass = cClass;
3649 }
3650
3651 return ErrorCode;
3652 }
3653
3654
3655 /************************************************************************
3656 * RegQueryInfoKeyW
3657 *
3658 * @implemented
3659 */
3660 LONG WINAPI
3661 RegQueryInfoKeyW(HKEY hKey,
3662 LPWSTR lpClass,
3663 LPDWORD lpcClass,
3664 LPDWORD lpReserved,
3665 LPDWORD lpcSubKeys,
3666 LPDWORD lpcMaxSubKeyLen,
3667 LPDWORD lpcMaxClassLen,
3668 LPDWORD lpcValues,
3669 LPDWORD lpcMaxValueNameLen,
3670 LPDWORD lpcMaxValueLen,
3671 LPDWORD lpcbSecurityDescriptor,
3672 PFILETIME lpftLastWriteTime)
3673 {
3674 KEY_FULL_INFORMATION FullInfoBuffer;
3675 PKEY_FULL_INFORMATION FullInfo;
3676 ULONG FullInfoSize;
3677 ULONG ClassLength = 0;
3678 HANDLE KeyHandle;
3679 NTSTATUS Status;
3680 ULONG Length;
3681 LONG ErrorCode = ERROR_SUCCESS;
3682
3683 if ((lpClass) && (!lpcClass))
3684 {
3685 return ERROR_INVALID_PARAMETER;
3686 }
3687
3688 Status = MapDefaultKey(&KeyHandle,
3689 hKey);
3690 if (!NT_SUCCESS(Status))
3691 {
3692 return RtlNtStatusToDosError(Status);
3693 }
3694
3695 if (lpClass != NULL)
3696 {
3697 if (*lpcClass > 0)
3698 {
3699 ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3700 }
3701 else
3702 {
3703 ClassLength = 0;
3704 }
3705
3706 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3707 FullInfo = RtlAllocateHeap(ProcessHeap,
3708 0,
3709 FullInfoSize);
3710 if (FullInfo == NULL)
3711 {
3712 ErrorCode = ERROR_OUTOFMEMORY;
3713 goto Cleanup;
3714 }
3715 }
3716 else
3717 {
3718 FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3719 FullInfo = &FullInfoBuffer;
3720 }
3721
3722 Status = NtQueryKey(KeyHandle,
3723 KeyFullInformation,
3724 FullInfo,
3725 FullInfoSize,
3726 &Length);
3727 TRACE("NtQueryKey() returned status 0x%X\n", Status);
3728 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
3729 {
3730 ErrorCode = RtlNtStatusToDosError(Status);
3731 goto Cleanup;
3732 }
3733
3734 TRACE("SubKeys %d\n", FullInfo->SubKeys);
3735 if (lpcSubKeys != NULL)
3736 {
3737 *lpcSubKeys = FullInfo->SubKeys;
3738 }
3739
3740 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3741 if (lpcMaxSubKeyLen != NULL)
3742 {
3743 *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR);
3744 }
3745
3746 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3747 if (lpcMaxClassLen != NULL)
3748 {
3749 *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR);
3750 }
3751
3752 TRACE("Values %lu\n", FullInfo->Values);
3753 if (lpcValues != NULL)
3754 {
3755 *lpcValues = FullInfo->Values;
3756 }
3757
3758 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3759 if (lpcMaxValueNameLen != NULL)
3760 {
3761 *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR);
3762 }
3763
3764 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3765 if (lpcMaxValueLen != NULL)
3766 {
3767 *lpcMaxValueLen = FullInfo->MaxValueDataLen;
3768 }
3769
3770 if (lpcbSecurityDescriptor != NULL)
3771 {
3772 Status = NtQuerySecurityObject(KeyHandle,
3773 OWNER_SECURITY_INFORMATION |
3774 GROUP_SECURITY_INFORMATION |
3775 DACL_SECURITY_INFORMATION,
3776 NULL,
3777 0,
3778 lpcbSecurityDescriptor);
3779 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
3780 {
3781 ErrorCode = RtlNtStatusToDosError(Status);
3782 goto Cleanup;
3783 }
3784 }
3785
3786 if (lpftLastWriteTime != NULL)
3787 {
3788 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3789 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3790 }
3791
3792 if (lpClass != NULL)
3793 {
3794 if (*lpcClass == 0)
3795 {
3796 goto Cleanup;
3797 }
3798
3799 if (FullInfo->ClassLength > ClassLength)
3800 {
3801 ErrorCode = ERROR_INSUFFICIENT_BUFFER;
3802 }
3803 else
3804 {
3805 RtlCopyMemory(lpClass,
3806 FullInfo->Class,
3807 FullInfo->ClassLength);
3808 lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL;
3809 }
3810 }
3811
3812 if (lpcClass != NULL)
3813 {
3814 *lpcClass = FullInfo->ClassLength / sizeof(WCHAR);
3815 }
3816
3817 Cleanup:
3818 if (lpClass != NULL)
3819 {
3820 RtlFreeHeap(ProcessHeap,
3821 0,
3822 FullInfo);
3823 }
3824
3825 ClosePredefKey(KeyHandle);
3826
3827 return ErrorCode;
3828 }
3829
3830
3831 /************************************************************************
3832 * RegQueryMultipleValuesA
3833 *
3834 * @implemented
3835 */
3836 LONG WINAPI
3837 RegQueryMultipleValuesA(HKEY hKey,
3838 PVALENTA val_list,
3839 DWORD num_vals,
3840 LPSTR lpValueBuf,
3841 LPDWORD ldwTotsize)
3842 {
3843 ULONG i;
3844 DWORD maxBytes = *ldwTotsize;
3845 LPSTR bufptr = (LPSTR)lpValueBuf;
3846 LONG ErrorCode;
3847
3848 if (maxBytes >= (1024*1024))
3849 return ERROR_TRANSFER_TOO_LONG;
3850
3851 *ldwTotsize = 0;
3852
3853 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3854 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3855
3856 for (i = 0; i < num_vals; i++)
3857 {
3858 val_list[i].ve_valuelen = 0;
3859 ErrorCode = RegQueryValueExA(hKey,
3860 val_list[i].ve_valuename,
3861 NULL,
3862 NULL,
3863 NULL,
3864 &val_list[i].ve_valuelen);
3865 if (ErrorCode != ERROR_SUCCESS)
3866 {
3867 return ErrorCode;
3868 }
3869
3870 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3871 {
3872 ErrorCode = RegQueryValueExA(hKey,
3873 val_list[i].ve_valuename,
3874 NULL,
3875 &val_list[i].ve_type,
3876 (LPBYTE)bufptr,
3877 &val_list[i].ve_valuelen);
3878 if (ErrorCode != ERROR_SUCCESS)
3879 {
3880 return ErrorCode;
3881 }
3882
3883 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3884
3885 bufptr += val_list[i].ve_valuelen;
3886 }
3887
3888 *ldwTotsize += val_list[i].ve_valuelen;
3889 }
3890
3891 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3892 }
3893
3894
3895 /************************************************************************
3896 * RegQueryMultipleValuesW
3897 *
3898 * @implemented
3899 */
3900 LONG WINAPI
3901 RegQueryMultipleValuesW(HKEY hKey,
3902 PVALENTW val_list,
3903 DWORD num_vals,
3904 LPWSTR lpValueBuf,
3905 LPDWORD ldwTotsize)
3906 {
3907 ULONG i;
3908 DWORD maxBytes = *ldwTotsize;
3909 LPSTR bufptr = (LPSTR)lpValueBuf;
3910 LONG ErrorCode;
3911
3912 if (maxBytes >= (1024*1024))
3913 return ERROR_TRANSFER_TOO_LONG;
3914
3915 *ldwTotsize = 0;
3916
3917 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3918 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3919
3920 for (i = 0; i < num_vals; i++)
3921 {
3922 val_list[i].ve_valuelen = 0;
3923 ErrorCode = RegQueryValueExW(hKey,
3924 val_list[i].ve_valuename,
3925 NULL,
3926 NULL,
3927 NULL,
3928 &val_list[i].ve_valuelen);
3929 if (ErrorCode != ERROR_SUCCESS)
3930 {
3931 return ErrorCode;
3932 }
3933
3934 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3935 {
3936 ErrorCode = RegQueryValueExW(hKey,
3937 val_list[i].ve_valuename,
3938 NULL,
3939 &val_list[i].ve_type,
3940 (LPBYTE)bufptr,
3941 &val_list[i].ve_valuelen);
3942 if (ErrorCode != ERROR_SUCCESS)
3943 {
3944 return ErrorCode;
3945 }
3946
3947 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3948
3949 bufptr += val_list[i].ve_valuelen;
3950 }
3951
3952 *ldwTotsize += val_list[i].ve_valuelen;
3953 }
3954
3955 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3956 }
3957
3958
3959 /************************************************************************
3960 * RegQueryReflectionKey
3961 *
3962 * @unimplemented
3963 */
3964 LONG WINAPI
3965 RegQueryReflectionKey(IN HKEY hBase,
3966 OUT BOOL* bIsReflectionDisabled)
3967 {
3968 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3969 hBase, bIsReflectionDisabled);
3970 return ERROR_CALL_NOT_IMPLEMENTED;
3971 }
3972
3973
3974 /******************************************************************************
3975 * RegQueryValueExA [ADVAPI32.@]
3976 *
3977 * Get the type and contents of a specified value under with a key.
3978 *
3979 * PARAMS
3980 * hkey [I] Handle of the key to query
3981 * name [I] Name of value under hkey to query
3982 * reserved [I] Reserved - must be NULL
3983 * type [O] Destination for the value type, or NULL if not required
3984 * data [O] Destination for the values contents, or NULL if not required
3985 * count [I/O] Size of data, updated with the number of bytes returned
3986 *
3987 * RETURNS
3988 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
3989 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
3990 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
3991 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
3992 *
3993 * NOTES
3994 * MSDN states that if data is too small it is partially filled. In reality
3995 * it remains untouched.
3996 */
3997 LONG
3998 WINAPI
3999 RegQueryValueExA(
4000 _In_ HKEY hkeyorg,
4001 _In_ LPCSTR name,
4002 _In_ LPDWORD reserved,
4003 _Out_opt_ LPDWORD type,
4004 _Out_opt_ LPBYTE data,
4005 _Inout_opt_ LPDWORD count)
4006 {
4007 UNICODE_STRING nameW;
4008 DWORD DataLength;
4009 DWORD ErrorCode;
4010 DWORD BufferSize = 0;
4011 WCHAR* Buffer;
4012 CHAR* DataStr = (CHAR*)data;
4013 DWORD LocalType;
4014
4015 /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */
4016 if ((data && !count) || reserved)
4017 return ERROR_INVALID_PARAMETER;
4018
4019 if (name)
4020 {
4021 if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name))
4022 return ERROR_NOT_ENOUGH_MEMORY;
4023 }
4024 else
4025 RtlInitEmptyUnicodeString(&nameW, NULL, 0);
4026
4027 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize);
4028 if (ErrorCode != ERROR_SUCCESS)
4029 {
4030 if ((!data) && count)
4031 *count = 0;
4032 RtlFreeUnicodeString(&nameW);
4033 return ErrorCode;
4034 }
4035
4036 /* See if we can directly handle the call without caring for conversion */
4037 if (!is_string(LocalType) || !count)
4038 {
4039 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count);
4040 RtlFreeUnicodeString(&nameW);
4041 return ErrorCode;
4042 }
4043
4044 /* Allocate a unicode string to get the data */
4045 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
4046 if (!Buffer)
4047 {
4048 RtlFreeUnicodeString(&nameW);
4049 return ERROR_NOT_ENOUGH_MEMORY;
4050 }
4051
4052 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, (LPBYTE)Buffer, &BufferSize);
4053 if (ErrorCode != ERROR_SUCCESS)
4054 {
4055 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4056 RtlFreeUnicodeString(&nameW);
4057 return ErrorCode;
4058 }
4059
4060 /* We don't need this anymore */
4061 RtlFreeUnicodeString(&nameW);
4062
4063 DataLength = *count;
4064 RtlUnicodeToMultiByteSize(count, Buffer, BufferSize);
4065
4066 if ((!data) || (DataLength < *count))
4067 {
4068 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4069 return data ? ERROR_MORE_DATA : ERROR_SUCCESS;
4070 }
4071
4072 /* We can finally do the conversion */
4073 RtlUnicodeToMultiByteN(DataStr, DataLength, NULL, Buffer, BufferSize);
4074
4075 /* NULL-terminate if there is enough room */
4076 if ((DataLength > *count) && (DataStr[*count - 1] != '\0'))
4077 DataStr[*count] = '\0';
4078
4079 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
4080
4081 return ERROR_SUCCESS;
4082 }
4083
4084
4085 /************************************************************************
4086 * RegQueryValueExW
4087 *
4088 * @implemented
4089 */
4090 LONG
4091 WINAPI
4092 RegQueryValueExW(
4093 _In_ HKEY hkeyorg,
4094 _In_ LPCWSTR name,
4095 _In_ LPDWORD reserved,
4096 _In_ LPDWORD type,
4097 _In_ LPBYTE data,
4098 _In_ LPDWORD count)
4099 {
4100 HANDLE hkey;
4101 NTSTATUS status;
4102 UNICODE_STRING name_str;
4103 DWORD total_size;
4104 char buffer[256], *buf_ptr = buffer;
4105 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
4106 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4107
4108 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4109 hkeyorg, debugstr_w(name), reserved, type, data, count,
4110 (count && data) ? *count : 0 );
4111
4112 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4113
4114 status = MapDefaultKey(&hkey, hkeyorg);
4115 if (!NT_SUCCESS(status))
4116 {
4117 return RtlNtStatusToDosError(status);
4118 }
4119
4120 if (IsHKCRKey(hkey))
4121 {
4122 LONG ErrorCode = QueryHKCRValue(hkey, name, reserved, type, data, count);
4123 ClosePredefKey(hkey);
4124 return ErrorCode;
4125 }
4126
4127 RtlInitUnicodeString( &name_str, name );
4128
4129 if (data) total_size = min( sizeof(buffer), *count + info_size );
4130 else
4131 {
4132 total_size = info_size;
4133 if (count) *count = 0;
4134 }
4135
4136 /* this matches Win9x behaviour - NT sets *type to a random value */
4137 if (type) *type = REG_NONE;
4138
4139 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4140 buffer, total_size, &total_size );
4141 if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) goto done;
4142
4143 if (data)
4144 {
4145 /* retry with a dynamically allocated buffer */
4146 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
4147 {
4148 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4149 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4150 {
4151 ClosePredefKey(hkey);
4152 return ERROR_NOT_ENOUGH_MEMORY;
4153 }
4154 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4155 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4156 buf_ptr, total_size, &total_size );
4157 }
4158
4159 if (NT_SUCCESS(status))
4160 {
4161 memcpy( data, buf_ptr + info_size, total_size - info_size );
4162 /* if the type is REG_SZ and data is not 0-terminated
4163 * and there is enough space in the buffer NT appends a \0 */
4164 if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR))
4165 {
4166 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
4167 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
4168 }
4169 }
4170 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
4171 }
4172 else status = STATUS_SUCCESS;
4173
4174 if (type) *type = info->Type;
4175 if (count) *count = total_size - info_size;
4176
4177 done:
4178 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4179 ClosePredefKey(hkey);
4180 return RtlNtStatusToDosError(status);
4181 }
4182
4183
4184 /************************************************************************
4185 * RegQueryValueA
4186 *
4187 * @implemented
4188 */
4189 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
4190 {
4191 DWORD ret;
4192 HKEY subkey = hkey;
4193
4194 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
4195
4196 if (name && name[0])
4197 {
4198 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
4199 }
4200 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4201 if (subkey != hkey) RegCloseKey( subkey );
4202 if (ret == ERROR_FILE_NOT_FOUND)
4203 {
4204 /* return empty string if default value not found */
4205 if (data) *data = 0;
4206 if (count) *count = 1;
4207 ret = ERROR_SUCCESS;
4208 }
4209 return ret;
4210 }
4211
4212
4213 /************************************************************************
4214 * RegQueryValueW
4215 *
4216 * @implemented
4217 */
4218 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
4219 {
4220 DWORD ret;
4221 HKEY subkey = hkey;
4222
4223 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
4224 if (hkey == NULL)
4225 {
4226 return ERROR_INVALID_HANDLE;
4227 }
4228 if (name && name[0])
4229 {
4230 ret = RegOpenKeyW( hkey, name, &subkey);
4231 if (ret != ERROR_SUCCESS)
4232 {
4233 return ret;
4234 }
4235 }
4236
4237 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
4238
4239 if (subkey != hkey)
4240 {
4241 RegCloseKey( subkey );
4242 }
4243
4244 if (ret == ERROR_FILE_NOT_FOUND)
4245 {
4246 /* return empty string if default value not found */
4247 if (data)
4248 *data = 0;
4249 if (count)
4250 *count = sizeof(WCHAR);
4251 ret = ERROR_SUCCESS;
4252 }
4253 return ret;
4254 }
4255
4256
4257 /************************************************************************
4258 * RegReplaceKeyA
4259 *
4260 * @implemented
4261 */
4262 LONG WINAPI
4263 RegReplaceKeyA(HKEY hKey,
4264 LPCSTR lpSubKey,
4265 LPCSTR lpNewFile,
4266 LPCSTR lpOldFile)
4267 {
4268 UNICODE_STRING SubKey;
4269 UNICODE_STRING NewFile;
4270 UNICODE_STRING OldFile;
4271 LONG ErrorCode;
4272
4273 RtlInitEmptyUnicodeString(&SubKey, NULL, 0);
4274 RtlInitEmptyUnicodeString(&OldFile, NULL, 0);
4275 RtlInitEmptyUnicodeString(&NewFile, NULL, 0);
4276
4277 if (lpSubKey)
4278 {
4279 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
4280 {
4281 ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
4282 goto Exit;
4283 }
4284 }
4285
4286 if (lpOldFile)
4287 {
4288 if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile))
4289 {
4290 ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
4291 goto Exit;
4292 }
4293 }
4294
4295 if (lpNewFile)
4296 {
4297 if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile))
4298 {
4299 ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
4300 goto Exit;
4301 }
4302 }
4303
4304 ErrorCode = RegReplaceKeyW(hKey,
4305 SubKey.Buffer,
4306 NewFile.Buffer,
4307 OldFile.Buffer);
4308
4309 Exit:
4310 RtlFreeUnicodeString(&OldFile);
4311 RtlFreeUnicodeString(&NewFile);
4312 RtlFreeUnicodeString(&SubKey);
4313
4314 return ErrorCode;
4315 }
4316
4317
4318 /************************************************************************
4319 * RegReplaceKeyW
4320 *
4321 * @unimplemented
4322 */
4323 LONG WINAPI
4324 RegReplaceKeyW(HKEY hKey,
4325 LPCWSTR lpSubKey,
4326 LPCWSTR lpNewFile,
4327 LPCWSTR lpOldFile)
4328 {
4329 OBJECT_ATTRIBUTES KeyObjectAttributes;
4330 OBJECT_ATTRIBUTES NewObjectAttributes;
4331 OBJECT_ATTRIBUTES OldObjectAttributes;
4332 UNICODE_STRING SubKeyName;
4333 UNICODE_STRING NewFileName;
4334 UNICODE_STRING OldFileName;
4335 BOOLEAN CloseRealKey;
4336 HANDLE RealKeyHandle;
4337 HANDLE KeyHandle;
4338 NTSTATUS Status;
4339 LONG ErrorCode = ERROR_SUCCESS;
4340
4341 if (hKey == HKEY_PERFORMANCE_DATA)
4342 {
4343 return ERROR_INVALID_HANDLE;
4344 }
4345
4346 Status = MapDefaultKey(&KeyHandle,
4347 hKey);
4348 if (!NT_SUCCESS(Status))
4349 {
4350 return RtlNtStatusToDosError(Status);
4351 }
4352
4353 /* Open the real key */
4354 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
4355 {
4356 RtlInitUnicodeString(&SubKeyName,
4357 (PWSTR)lpSubKey);
4358 InitializeObjectAttributes(&KeyObjectAttributes,
4359 &SubKeyName,
4360 OBJ_CASE_INSENSITIVE,
4361 KeyHandle,
4362 NULL);
4363 Status = NtOpenKey(&RealKeyHandle,
4364 MAXIMUM_ALLOWED,
4365 &KeyObjectAttributes);
4366 if (!NT_SUCCESS(Status))
4367 {
4368 ErrorCode = RtlNtStatusToDosError(Status);
4369 goto Cleanup;
4370 }
4371
4372 CloseRealKey = TRUE;
4373 }
4374 else
4375 {
4376 RealKeyHandle = KeyHandle;
4377 CloseRealKey = FALSE;
4378 }
4379
4380 /* Convert new file name */
4381 if (!RtlDosPathNameToNtPathName_U(lpNewFile,
4382 &NewFileName,
4383 NULL,
4384 NULL))
4385 {
4386 if (CloseRealKey)
4387 {
4388 NtClose(RealKeyHandle);
4389 }
4390
4391 ErrorCode = ERROR_INVALID_PARAMETER;
4392 goto Cleanup;
4393 }
4394
4395 InitializeObjectAttributes(&NewObjectAttributes,
4396 &NewFileName,
4397 OBJ_CASE_INSENSITIVE,
4398 NULL,
4399 NULL);
4400
4401 /* Convert old file name */
4402 if (!RtlDosPathNameToNtPathName_U(lpOldFile,
4403 &OldFileName,
4404 NULL,
4405 NULL))
4406 {
4407 RtlFreeHeap(RtlGetProcessHeap (),
4408 0,
4409 NewFileName.Buffer);
4410 if (CloseRealKey)
4411 {
4412 NtClose(RealKeyHandle);
4413 }
4414
4415 ErrorCode = ERROR_INVALID_PARAMETER;
4416 goto Cleanup;
4417 }
4418
4419 InitializeObjectAttributes(&OldObjectAttributes,
4420 &OldFileName,
4421 OBJ_CASE_INSENSITIVE,
4422 NULL,
4423 NULL);
4424
4425 Status = NtReplaceKey(&NewObjectAttributes,
4426 RealKeyHandle,
4427 &OldObjectAttributes);
4428
4429 RtlFreeHeap(RtlGetProcessHeap(),
4430 0,
4431 OldFileName.Buffer);
4432 RtlFreeHeap(RtlGetProcessHeap(),
4433 0,
4434 NewFileName.Buffer);
4435
4436 if (CloseRealKey)
4437 {
4438 NtClose(RealKeyHandle);
4439 }
4440
4441 if (!NT_SUCCESS(Status))
4442 {
4443 return RtlNtStatusToDosError(Status);
4444 }
4445
4446 Cleanup:
4447 ClosePredefKey(KeyHandle);
4448
4449 return ErrorCode;
4450 }
4451
4452
4453 /************************************************************************
4454 * RegRestoreKeyA
4455 *
4456 * @implemented
4457 */
4458 LONG WINAPI
4459 RegRestoreKeyA(HKEY hKey,
4460 LPCSTR lpFile,
4461 DWORD dwFlags)
4462 {
4463 UNICODE_STRING FileName;
4464 LONG ErrorCode;
4465
4466 if (lpFile)
4467 {
4468 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
4469 return ERROR_NOT_ENOUGH_MEMORY;
4470 }
4471 else
4472 RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4473
4474 ErrorCode = RegRestoreKeyW(hKey,
4475 FileName.Buffer,
4476 dwFlags);
4477
4478 RtlFreeUnicodeString(&FileName);
4479
4480 return ErrorCode;
4481 }
4482
4483
4484 /************************************************************************
4485 * RegRestoreKeyW
4486 *
4487 * @implemented
4488 */
4489 LONG WINAPI
4490 RegRestoreKeyW(HKEY hKey,
4491 LPCWSTR lpFile,
4492 DWORD dwFlags)
4493 {
4494 OBJECT_ATTRIBUTES ObjectAttributes;
4495 IO_STATUS_BLOCK IoStatusBlock;
4496 UNICODE_STRING FileName;
4497 HANDLE FileHandle;
4498 HANDLE KeyHandle;
4499 NTSTATUS Status;
4500
4501 if (hKey == HKEY_PERFORMANCE_DATA)
4502 {
4503 return ERROR_INVALID_HANDLE;
4504 }
4505
4506 Status = MapDefaultKey(&KeyHandle,
4507 hKey);
4508 if (!NT_SUCCESS(Status))
4509 {
4510 return RtlNtStatusToDosError(Status);
4511 }
4512
4513 if (!RtlDosPathNameToNtPathName_U(lpFile,
4514 &FileName,
4515 NULL,
4516 NULL))
4517 {
4518 Status = STATUS_INVALID_PARAMETER;
4519 goto Cleanup;
4520 }
4521
4522 InitializeObjectAttributes(&ObjectAttributes,
4523 &FileName,
4524 OBJ_CASE_INSENSITIVE,
4525 NULL,
4526 NULL);
4527
4528 Status = NtOpenFile(&FileHandle,
4529 FILE_GENERIC_READ,
4530 &ObjectAttributes,
4531 &IoStatusBlock,
4532 FILE_SHARE_READ,
4533 FILE_SYNCHRONOUS_IO_NONALERT);
4534 RtlFreeHeap(RtlGetProcessHeap(),
4535 0,
4536 FileName.Buffer);
4537 if (!NT_SUCCESS(Status))
4538 {
4539 goto Cleanup;
4540 }
4541
4542 Status = NtRestoreKey(KeyHandle,
4543 FileHandle,
4544 (ULONG)dwFlags);
4545 NtClose (FileHandle);
4546
4547 Cleanup:
4548 ClosePredefKey(KeyHandle);
4549
4550 if (!NT_SUCCESS(Status))
4551 {
4552 return RtlNtStatusToDosError(Status);
4553 }
4554
4555 return ERROR_SUCCESS;
4556 }
4557
4558
4559 /************************************************************************
4560 * RegSaveKeyA
4561 *
4562 * @implemented
4563 */
4564 LONG WINAPI
4565 RegSaveKeyA(HKEY hKey,
4566 LPCSTR lpFile,
4567 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4568 {
4569 UNICODE_STRING FileName;
4570 LONG ErrorCode;
4571
4572 if (lpFile)
4573 {
4574 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
4575 return ERROR_NOT_ENOUGH_MEMORY;
4576 }
4577 else
4578 RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4579
4580 ErrorCode = RegSaveKeyW(hKey,
4581 FileName.Buffer,
4582 lpSecurityAttributes);
4583 RtlFreeUnicodeString(&FileName);
4584
4585 return ErrorCode;
4586 }
4587
4588
4589 /************************************************************************
4590 * RegSaveKeyW
4591 *
4592 * @implemented
4593 */
4594 LONG WINAPI
4595 RegSaveKeyW(HKEY hKey,
4596 LPCWSTR lpFile,
4597 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4598 {
4599 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
4600 OBJECT_ATTRIBUTES ObjectAttributes;
4601 UNICODE_STRING FileName;
4602 IO_STATUS_BLOCK IoStatusBlock;
4603 HANDLE FileHandle;
4604 HANDLE KeyHandle;
4605 NTSTATUS Status;
4606
4607 Status = MapDefaultKey(&KeyHandle,
4608 hKey);
4609 if (!NT_SUCCESS(Status))
4610 {
4611 return RtlNtStatusToDosError(Status);
4612 }
4613
4614 if (!RtlDosPathNameToNtPathName_U(lpFile,
4615 &FileName,
4616 NULL,
4617 NULL))
4618 {
4619 Status = STATUS_INVALID_PARAMETER;
4620 goto Cleanup;
4621 }
4622
4623 if (lpSecurityAttributes != NULL)
4624 {
4625 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4626 }
4627
4628 InitializeObjectAttributes(&ObjectAttributes,
4629 &FileName,
4630 OBJ_CASE_INSENSITIVE,
4631 NULL,
4632 SecurityDescriptor);
4633 Status = NtCreateFile(&FileHandle,
4634 GENERIC_WRITE | SYNCHRONIZE,
4635 &ObjectAttributes,
4636 &IoStatusBlock,
4637 NULL,
4638 FILE_ATTRIBUTE_NORMAL,
4639 FILE_SHARE_READ,
4640 FILE_CREATE,
4641 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
4642 NULL,
4643 0);
4644 RtlFreeHeap(RtlGetProcessHeap(),
4645 0,
4646 FileName.Buffer);
4647 if (!NT_SUCCESS(Status))
4648 {
4649 goto Cleanup;
4650 }
4651
4652 Status = NtSaveKey(KeyHandle,
4653 FileHandle);
4654 NtClose (FileHandle);
4655
4656 Cleanup:
4657 ClosePredefKey(KeyHandle);
4658
4659 if (!NT_SUCCESS(Status))
4660 {
4661 return RtlNtStatusToDosError(Status);
4662 }
4663
4664 return ERROR_SUCCESS;
4665 }
4666
4667
4668 /************************************************************************
4669 * RegSaveKeyExA
4670 *
4671 * @implemented
4672 */
4673 LONG
4674 WINAPI
4675 RegSaveKeyExA(HKEY hKey,
4676 LPCSTR lpFile,
4677 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4678 DWORD Flags)
4679 {
4680 UNICODE_STRING FileName;
4681 LONG ErrorCode;
4682
4683 if (lpFile)
4684 {
4685 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
4686 return ERROR_NOT_ENOUGH_MEMORY;
4687 }
4688 else
4689 RtlInitEmptyUnicodeString(&FileName, NULL, 0);
4690
4691 ErrorCode = RegSaveKeyExW(hKey,
4692 FileName.Buffer,
4693 lpSecurityAttributes,
4694 Flags);
4695 RtlFreeUnicodeString(&FileName);
4696
4697 return ErrorCode;
4698 }
4699
4700
4701 /************************************************************************
4702 * RegSaveKeyExW
4703 *
4704 * @unimplemented
4705 */
4706 LONG
4707 WINAPI
4708 RegSaveKeyExW(HKEY hKey,
4709 LPCWSTR lpFile,
4710 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
4711 DWORD Flags)
4712 {
4713 switch (Flags)
4714 {
4715 case REG_STANDARD_FORMAT:
4716 case REG_LATEST_FORMAT:
4717 case REG_NO_COMPRESSION:
4718 break;
4719 default:
4720 return ERROR_INVALID_PARAMETER;
4721 }
4722
4723 FIXME("RegSaveKeyExW(): Flags ignored!\n");
4724
4725 return RegSaveKeyW(hKey,
4726 lpFile,
4727 lpSecurityAttributes);
4728 }
4729
4730
4731 /************************************************************************
4732 * RegSetKeySecurity
4733 *
4734 * @implemented
4735 */
4736 LONG WINAPI
4737 RegSetKeySecurity(HKEY hKey,
4738 SECURITY_INFORMATION SecurityInformation,
4739 PSECURITY_DESCRIPTOR pSecurityDescriptor)
4740 {
4741 HANDLE KeyHandle;
4742 NTSTATUS Status;
4743
4744 if (hKey == HKEY_PERFORMANCE_DATA)
4745 {
4746 return ERROR_INVALID_HANDLE;
4747 }
4748
4749 Status = MapDefaultKey(&KeyHandle,
4750 hKey);
4751 if (!NT_SUCCESS(Status))
4752 {
4753 return RtlNtStatusToDosError(Status);
4754 }
4755
4756 Status = NtSetSecurityObject(KeyHandle,
4757 SecurityInformation,
4758 pSecurityDescriptor);
4759
4760 ClosePredefKey(KeyHandle);
4761
4762 if (!NT_SUCCESS(Status))
4763 {
4764 return RtlNtStatusToDosError(Status);
4765 }
4766
4767 return ERROR_SUCCESS;
4768 }
4769
4770
4771 /************************************************************************
4772 * RegSetValueExA
4773 *
4774 * @implemented
4775 */
4776 LONG WINAPI
4777 RegSetValueExA(HKEY hKey,
4778 LPCSTR lpValueName,
4779 DWORD Reserved,
4780 DWORD dwType,
4781 CONST BYTE* lpData,
4782 DWORD cbData)
4783 {
4784 UNICODE_STRING ValueName;
4785 LPWSTR pValueName;
4786 ANSI_STRING AnsiString;
4787 UNICODE_STRING Data;
4788 LONG ErrorCode;
4789 LPBYTE pData;
4790 DWORD DataSize;
4791 NTSTATUS Status;
4792
4793 /* Convert SubKey name to Unicode */
4794 if (lpValueName != NULL && lpValueName[0] != '\0')
4795 {
4796 BOOL bConverted;
4797 bConverted = RtlCreateUnicodeStringFromAsciiz(&ValueName,
4798 (PSTR)lpValueName);
4799 if(!bConverted)
4800 return ERROR_NOT_ENOUGH_MEMORY;
4801 }
4802 else
4803 {
4804 ValueName.Buffer = NULL;
4805 }
4806
4807 pValueName = (LPWSTR)ValueName.Buffer;
4808
4809
4810 if (is_string(dwType) && (cbData != 0))
4811 {
4812 /* Convert ANSI string Data to Unicode */
4813 /* If last character NOT zero then increment length */
4814 LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0);
4815 AnsiString.Buffer = (PSTR)lpData;
4816 AnsiString.Length = cbData + bNoNulledStr;
4817 AnsiString.MaximumLength = cbData + bNoNulledStr;
4818 Status = RtlAnsiStringToUnicodeString(&Data,
4819 &AnsiString,
4820 TRUE);
4821
4822 if (!NT_SUCCESS(Status))
4823 {
4824 if (pValueName != NULL)
4825 RtlFreeUnicodeString(&ValueName);
4826
4827 return RtlNtStatusToDosError(Status);
4828 }
4829 pData = (LPBYTE)Data.Buffer;
4830 DataSize = cbData * sizeof(WCHAR);
4831 }
4832 else
4833 {
4834 Data.Buffer = NULL;
4835 pData = (LPBYTE)lpData;
4836 DataSize = cbData;
4837 }
4838
4839 ErrorCode = RegSetValueExW(hKey,
4840 pValueName,
4841 Reserved,
4842 dwType,
4843 pData,
4844 DataSize);
4845
4846 if (pValueName != NULL)
4847 RtlFreeUnicodeString(&ValueName);
4848
4849 if (Data.Buffer != NULL)
4850 RtlFreeUnicodeString(&Data);
4851
4852 return ErrorCode;
4853 }
4854
4855
4856 /************************************************************************
4857 * RegSetValueExW
4858 *
4859 * @implemented
4860 */
4861 LONG
4862 WINAPI
4863 RegSetValueExW(
4864 _In_ HKEY hKey,
4865 _In_ LPCWSTR lpValueName,
4866 _In_ DWORD Reserved,
4867 _In_ DWORD dwType,
4868 _In_ CONST BYTE* lpData,
4869 _In_ DWORD cbData)
4870 {
4871 UNICODE_STRING ValueName;
4872 HANDLE KeyHandle;
4873 NTSTATUS Status;
4874
4875 Status = MapDefaultKey(&KeyHandle,
4876 hKey);
4877 if (!NT_SUCCESS(Status))
4878 {
4879 return RtlNtStatusToDosError(Status);
4880 }
4881
4882 if (IsHKCRKey(KeyHandle))
4883 {
4884 LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData);
4885 ClosePredefKey(KeyHandle);
4886 return ErrorCode;
4887 }
4888
4889 if (is_string(dwType) && (cbData != 0))
4890 {
4891 PWSTR pwsData = (PWSTR)lpData;
4892
4893 _SEH2_TRY
4894 {
4895 if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
4896 (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
4897 {
4898 /* Increment length if last character is not zero and next is zero */
4899 cbData += sizeof(WCHAR);
4900 }
4901 }
4902 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4903 {
4904 ClosePredefKey(KeyHandle);
4905 return ERROR_NOACCESS;
4906 }
4907 _SEH2_END;
4908 }
4909
4910 RtlInitUnicodeString(&ValueName, lpValueName);
4911
4912 Status = NtSetValueKey(KeyHandle,
4913 &ValueName,
4914 0,
4915 dwType,
4916 (PVOID)lpData,
4917 (ULONG)cbData);
4918
4919 ClosePredefKey(KeyHandle);
4920
4921 if (!NT_SUCCESS(Status))
4922 {
4923 return RtlNtStatusToDosError(Status);
4924 }
4925
4926 return ERROR_SUCCESS;
4927 }
4928
4929
4930 /************************************************************************
4931 * RegSetValueA
4932 *
4933 * @implemented
4934 */
4935 LONG WINAPI
4936 RegSetValueA(HKEY hKeyOriginal,
4937 LPCSTR lpSubKey,
4938 DWORD dwType,
4939 LPCSTR lpData,
4940 DWORD cbData)
4941 {
4942 HKEY subkey;
4943 HANDLE hKey;
4944 DWORD ret;
4945 NTSTATUS Status;
4946
4947 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData );
4948
4949 if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER;
4950
4951 Status = MapDefaultKey(&hKey, hKeyOriginal);
4952 if (!NT_SUCCESS(Status))
4953 {
4954 return RtlNtStatusToDosError (Status);
4955 }
4956 subkey = hKey;
4957
4958 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
4959 {
4960 ret = RegCreateKeyA(hKey, lpSubKey, &subkey);
4961 if (ret != ERROR_SUCCESS)
4962 goto Cleanup;
4963 }
4964
4965 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 );
4966 if (subkey != hKey)
4967 RegCloseKey(subkey);
4968
4969 Cleanup:
4970 ClosePredefKey(hKey);
4971
4972 return ret;
4973 }
4974
4975
4976 /************************************************************************
4977 * RegSetValueW
4978 *
4979 * @implemented
4980 */
4981 LONG WINAPI
4982 RegSetValueW(HKEY hKeyOriginal,
4983 LPCWSTR lpSubKey,
4984 DWORD dwType,
4985 LPCWSTR lpData,
4986 DWORD cbData)
4987 {
4988 HKEY subkey;
4989 HANDLE hKey;
4990 DWORD ret;
4991 NTSTATUS Status;
4992
4993 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData );
4994
4995 if (dwType != REG_SZ || !lpData)
4996 return ERROR_INVALID_PARAMETER;
4997
4998 Status = MapDefaultKey(&hKey,
4999 hKeyOriginal);
5000 if (!NT_SUCCESS(Status))
5001 {
5002 return RtlNtStatusToDosError(Status);
5003 }
5004 subkey = hKey;
5005
5006 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
5007 {
5008 ret = RegCreateKeyW(hKey, lpSubKey, &subkey);
5009 if (ret != ERROR_SUCCESS)
5010 goto Cleanup;
5011 }
5012
5013 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData,
5014 (wcslen( lpData ) + 1) * sizeof(WCHAR) );
5015 if (subkey != hKey)
5016 RegCloseKey(subkey);
5017
5018 Cleanup:
5019 ClosePredefKey(hKey);
5020
5021 return ret;
5022 }
5023
5024
5025 /************************************************************************
5026 * RegUnLoadKeyA
5027 *
5028 * @implemented
5029 */
5030 LONG WINAPI
5031 RegUnLoadKeyA(HKEY hKey,
5032 LPCSTR lpSubKey)
5033 {
5034 UNICODE_STRING KeyName;
5035 DWORD ErrorCode;
5036
5037 if (lpSubKey)
5038 {
5039 if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
5040 return ERROR_NOT_ENOUGH_MEMORY;
5041 }
5042 else
5043 RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
5044
5045 ErrorCode = RegUnLoadKeyW(hKey,
5046 KeyName.Buffer);
5047
5048 RtlFreeUnicodeString (&KeyName);
5049
5050 return ErrorCode;
5051 }
5052
5053
5054 /************************************************************************
5055 * RegUnLoadKeyW
5056 *
5057 * @implemented
5058 */
5059 LONG WINAPI
5060 RegUnLoadKeyW(HKEY hKey,
5061 LPCWSTR lpSubKey)
5062 {
5063 OBJECT_ATTRIBUTES ObjectAttributes;
5064 UNICODE_STRING KeyName;
5065 HANDLE KeyHandle;
5066 NTSTATUS Status;
5067
5068 if (hKey == HKEY_PERFORMANCE_DATA)
5069 {
5070 return ERROR_INVALID_HANDLE;
5071 }
5072
5073 Status = MapDefaultKey(&KeyHandle, hKey);
5074 if (!NT_SUCCESS(Status))
5075 {
5076 return RtlNtStatusToDosError(Status);
5077 }
5078
5079 RtlInitUnicodeString(&KeyName,
5080 (LPWSTR)lpSubKey);
5081
5082 InitializeObjectAttributes(&ObjectAttributes,
5083 &KeyName,
5084 OBJ_CASE_INSENSITIVE,
5085 KeyHandle,
5086 NULL);
5087
5088 Status = NtUnloadKey(&ObjectAttributes);
5089
5090 ClosePredefKey(KeyHandle);
5091
5092 if (!NT_SUCCESS(Status))
5093 {
5094 return RtlNtStatusToDosError(Status);
5095 }
5096
5097 return ERROR_SUCCESS;
5098 }
5099
5100
5101 /******************************************************************************
5102 * load_string [Internal]
5103 *
5104 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5105 * avoid importing user32, which is higher level than advapi32. Helper for
5106 * RegLoadMUIString.
5107 */
5108 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
5109 {
5110 HGLOBAL hMemory;
5111 HRSRC hResource;
5112 WCHAR *pString;
5113 int idxString;
5114
5115 /* Negative values have to be inverted. */
5116 if (HIWORD(resId) == 0xffff)
5117 resId = (UINT)(-((INT)resId));
5118
5119 /* Load the resource into memory and get a pointer to it. */
5120 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
5121 if (!hResource) return 0;
5122 hMemory = LoadResource(hModule, hResource);
5123 if (!hMemory) return 0;
5124 pString = LockResource(hMemory);
5125
5126 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5127 idxString = resId & 0xf;
5128 while (idxString--) pString += *pString + 1;
5129
5130 /* If no buffer is given, return length of the string. */
5131 if (!pwszBuffer) return *pString;
5132
5133 /* Else copy over the string, respecting the buffer size. */
5134 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
5135 if (cMaxChars >= 0)
5136 {
5137 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
5138 pwszBuffer[cMaxChars] = L'\0';
5139 }
5140
5141 return cMaxChars;
5142 }
5143
5144
5145 /************************************************************************
5146 * RegLoadMUIStringW
5147 *
5148 * @implemented
5149 */
5150 LONG WINAPI
5151 RegLoadMUIStringW(IN HKEY hKey,
5152 IN LPCWSTR pszValue OPTIONAL,
5153 OUT LPWSTR pszOutBuf,
5154 IN DWORD cbOutBuf,
5155 OUT LPDWORD pcbData OPTIONAL,
5156 IN DWORD Flags,
5157 IN LPCWSTR pszDirectory OPTIONAL)
5158 {
5159 DWORD dwValueType, cbData;
5160 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
5161 LONG result;
5162
5163 /* Parameter sanity checks. */
5164 if (!hKey || !pszOutBuf)
5165 return ERROR_INVALID_PARAMETER;
5166
5167 if (pszDirectory && *pszDirectory)
5168 {
5169 FIXME("BaseDir parameter not yet supported!\n");
5170 return ERROR_INVALID_PARAMETER;
5171 }
5172
5173 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5174 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
5175 if (result != ERROR_SUCCESS) goto cleanup;
5176 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
5177 {
5178 result = ERROR_FILE_NOT_FOUND;
5179 goto cleanup;
5180 }
5181 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5182 if (!pwszTempBuffer)
5183 {
5184 result = ERROR_NOT_ENOUGH_MEMORY;
5185 goto cleanup;
5186 }
5187 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
5188 if (result != ERROR_SUCCESS) goto cleanup;
5189
5190 /* Expand environment variables, if appropriate, or copy the original string over. */
5191 if (dwValueType == REG_EXPAND_SZ)
5192 {
5193 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
5194 if (!cbData) goto cleanup;
5195 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5196 if (!pwszExpandedBuffer)
5197 {
5198 result = ERROR_NOT_ENOUGH_MEMORY;
5199 goto cleanup;
5200 }
5201 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
5202 }
5203 else
5204 {
5205 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5206 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
5207 }
5208
5209 /* If the value references a resource based string, parse the value and load the string.
5210 * Else just copy over the original value. */
5211 result = ERROR_SUCCESS;
5212 if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
5213 {
5214 lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
5215 }
5216 else
5217 {
5218 WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
5219 UINT uiStringId;
5220 HMODULE hModule;
5221
5222 /* Format of the expanded value is 'path_to_dll,-resId' */
5223 if (!pComma || pComma[1] != L'-')
5224 {
5225 result = ERROR_BADKEY;
5226 goto cleanup;
5227 }
5228
5229 uiStringId = _wtoi(pComma+2);
5230 *pComma = L'\0';
5231
5232 hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
5233 if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
5234 result = ERROR_BADKEY;
5235 FreeLibrary(hModule);
5236 }
5237
5238 cleanup:
5239 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
5240 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
5241 return result;
5242 }
5243
5244
5245 /************************************************************************
5246 * RegLoadMUIStringA
5247 *
5248 * @implemented
5249 */
5250 LONG WINAPI
5251 RegLoadMUIStringA(IN HKEY hKey,
5252 IN LPCSTR pszValue OPTIONAL,
5253 OUT LPSTR pszOutBuf,
5254 IN DWORD cbOutBuf,
5255 OUT LPDWORD pcbData OPTIONAL,
5256 IN DWORD Flags,
5257 IN LPCSTR pszDirectory OPTIONAL)
5258 {
5259 UNICODE_STRING valueW, baseDirW;
5260 WCHAR *pwszBuffer;
5261 DWORD cbData = cbOutBuf * sizeof(WCHAR);
5262 LONG result;
5263
5264 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
5265 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
5266 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
5267 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
5268 {
5269 result = ERROR_NOT_ENOUGH_MEMORY;
5270 goto cleanup;
5271 }
5272
5273 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
5274 baseDirW.Buffer);
5275
5276 if (result == ERROR_SUCCESS)
5277 {
5278 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
5279 if (pcbData)
5280 *pcbData = cbData;
5281 }
5282
5283 cleanup:
5284 HeapFree(GetProcessHeap(), 0, pwszBuffer);
5285 RtlFreeUnicodeString(&baseDirW);
5286 RtlFreeUnicodeString(&valueW);
5287
5288 return result;
5289 }
5290
5291 /* EOF */