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