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