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