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