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