Fix formatting. No code changes!
[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 STDCALL
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 STDCALL
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 STDCALL
401 RegCloseKey(HKEY hKey)
402 {
403 NTSTATUS Status;
404
405 /* don't close null handle or a pseudo handle */
406 if ((!hKey) || (((ULONG)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 STDCALL
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 STDCALL
785 RegCopyTreeA(IN HKEY hKeySrc,
786 IN LPCSTR lpSubKey OPTIONAL,
787 IN HKEY hKeyDest)
788 {
789 UNICODE_STRING SubKeyName = {0};
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 STDCALL
815 RegConnectRegistryA(IN LPCSTR lpMachineName,
816 IN HKEY hKey,
817 OUT PHKEY phkResult)
818 {
819 UNICODE_STRING MachineName = {0};
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 STDCALL
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 STDCALL
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 %x\n", (ULONG)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 STDCALL
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 %x\n", (ULONG)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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
1413 RegDeleteKeyValueA(IN HKEY hKey,
1414 IN LPCSTR lpSubKey OPTIONAL,
1415 IN LPCSTR lpValueName OPTIONAL)
1416 {
1417 UNICODE_STRING SubKey = {0}, ValueName = {0};
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 STDCALL
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 STDCALL
1828 RegDeleteTreeA(IN HKEY hKey,
1829 IN LPCSTR lpSubKey OPTIONAL)
1830 {
1831 UNICODE_STRING SubKeyName = {0};
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 Namea1 Length %d\n", NameLength);
2584 TRACE("Key Namea Length %d\n", *lpcbName);
2585 TRACE("Key Namea %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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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
3342 Status = MapDefaultKey(&KeyHandle,
3343 hKey);
3344 if (!NT_SUCCESS(Status))
3345 {
3346 return RtlNtStatusToDosError(Status);
3347 }
3348
3349 RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
3350 (LPSTR)lpSubKey);
3351 InitializeObjectAttributes(&ObjectAttributes,
3352 &SubKeyString,
3353 OBJ_CASE_INSENSITIVE,
3354 KeyHandle,
3355 NULL);
3356
3357 Status = NtOpenKey((PHANDLE)phkResult,
3358 samDesired,
3359 &ObjectAttributes);
3360 RtlFreeUnicodeString(&SubKeyString);
3361 if (!NT_SUCCESS(Status))
3362 {
3363 ErrorCode = RtlNtStatusToDosError(Status);
3364 }
3365
3366 ClosePredefKey(KeyHandle);
3367
3368 return ErrorCode;
3369 }
3370
3371
3372 /************************************************************************
3373 * RegOpenKeyExW
3374 *
3375 * @implemented
3376 */
3377 LONG STDCALL
3378 RegOpenKeyExW(HKEY hKey,
3379 LPCWSTR lpSubKey,
3380 DWORD ulOptions,
3381 REGSAM samDesired,
3382 PHKEY phkResult)
3383 {
3384 OBJECT_ATTRIBUTES ObjectAttributes;
3385 UNICODE_STRING SubKeyString;
3386 HANDLE KeyHandle;
3387 NTSTATUS Status;
3388 LONG ErrorCode = ERROR_SUCCESS;
3389
3390 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3391 hKey, lpSubKey, ulOptions, samDesired, phkResult);
3392
3393 Status = MapDefaultKey(&KeyHandle, hKey);
3394 if (!NT_SUCCESS(Status))
3395 {
3396 return RtlNtStatusToDosError(Status);
3397 }
3398
3399 if (lpSubKey != NULL)
3400 RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
3401 else
3402 RtlInitUnicodeString(&SubKeyString, (LPWSTR)L"");
3403
3404 InitializeObjectAttributes(&ObjectAttributes,
3405 &SubKeyString,
3406 OBJ_CASE_INSENSITIVE,
3407 KeyHandle,
3408 NULL);
3409
3410 Status = NtOpenKey((PHANDLE)phkResult,
3411 samDesired,
3412 &ObjectAttributes);
3413 if (!NT_SUCCESS(Status))
3414 {
3415 ErrorCode = RtlNtStatusToDosError(Status);
3416 }
3417
3418 ClosePredefKey(KeyHandle);
3419
3420 return ErrorCode;
3421 }
3422
3423
3424 /************************************************************************
3425 * RegOpenUserClassesRoot
3426 *
3427 * @implemented
3428 */
3429 LONG STDCALL
3430 RegOpenUserClassesRoot(IN HANDLE hToken,
3431 IN DWORD dwOptions,
3432 IN REGSAM samDesired,
3433 OUT PHKEY phkResult)
3434 {
3435 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
3436 const WCHAR UserClassesKeySuffix[] = L"_Classes";
3437 PTOKEN_USER TokenUserData;
3438 ULONG RequiredLength;
3439 UNICODE_STRING UserSidString, UserClassesKeyRoot;
3440 OBJECT_ATTRIBUTES ObjectAttributes;
3441 NTSTATUS Status;
3442
3443 /* check parameters */
3444 if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
3445 {
3446 return ERROR_INVALID_PARAMETER;
3447 }
3448
3449 /*
3450 * Get the user sid from the token
3451 */
3452
3453 ReadTokenSid:
3454 /* determine how much memory we need */
3455 Status = NtQueryInformationToken(hToken,
3456 TokenUser,
3457 NULL,
3458 0,
3459 &RequiredLength);
3460 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
3461 {
3462 /* NOTE - as opposed to all other registry functions windows does indeed
3463 change the last error code in case the caller supplied a invalid
3464 handle for example! */
3465 return RtlNtStatusToDosError(Status);
3466 }
3467
3468 TokenUserData = RtlAllocateHeap(ProcessHeap,
3469 0,
3470 RequiredLength);
3471 if (TokenUserData == NULL)
3472 {
3473 return ERROR_NOT_ENOUGH_MEMORY;
3474 }
3475
3476 /* attempt to read the information */
3477 Status = NtQueryInformationToken(hToken,
3478 TokenUser,
3479 TokenUserData,
3480 RequiredLength,
3481 &RequiredLength);
3482 if (!NT_SUCCESS(Status))
3483 {
3484 RtlFreeHeap(ProcessHeap,
3485 0,
3486 TokenUserData);
3487 if (Status == STATUS_BUFFER_TOO_SMALL)
3488 {
3489 /* the information appears to have changed?! try again */
3490 goto ReadTokenSid;
3491 }
3492
3493 /* NOTE - as opposed to all other registry functions windows does indeed
3494 change the last error code in case the caller supplied a invalid
3495 handle for example! */
3496 return RtlNtStatusToDosError(Status);
3497 }
3498
3499 /*
3500 * Build the absolute path for the user's registry in the form
3501 * "\Registry\User\<SID>_Classes"
3502 */
3503 Status = RtlConvertSidToUnicodeString(&UserSidString,
3504 TokenUserData->User.Sid,
3505 TRUE);
3506
3507 /* we don't need the user data anymore, free it */
3508 RtlFreeHeap(ProcessHeap,
3509 0,
3510 TokenUserData);
3511
3512 if (!NT_SUCCESS(Status))
3513 {
3514 return RtlNtStatusToDosError(Status);
3515 }
3516
3517 /* allocate enough memory for the entire key string */
3518 UserClassesKeyRoot.Length = 0;
3519 UserClassesKeyRoot.MaximumLength = UserSidString.Length +
3520 sizeof(UserClassesKeyPrefix) +
3521 sizeof(UserClassesKeySuffix);
3522 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
3523 0,
3524 UserClassesKeyRoot.MaximumLength);
3525 if (UserClassesKeyRoot.Buffer == NULL)
3526 {
3527 RtlFreeUnicodeString(&UserSidString);
3528 return RtlNtStatusToDosError(Status);
3529 }
3530
3531 /* build the string */
3532 RtlAppendUnicodeToString(&UserClassesKeyRoot,
3533 UserClassesKeyPrefix);
3534 RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
3535 &UserSidString);
3536 RtlAppendUnicodeToString(&UserClassesKeyRoot,
3537 UserClassesKeySuffix);
3538
3539 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
3540
3541 /*
3542 * Open the key
3543 */
3544 InitializeObjectAttributes(&ObjectAttributes,
3545 &UserClassesKeyRoot,
3546 OBJ_CASE_INSENSITIVE,
3547 NULL,
3548 NULL);
3549
3550 Status = NtOpenKey((PHANDLE)phkResult,
3551 samDesired,
3552 &ObjectAttributes);
3553
3554 RtlFreeUnicodeString(&UserSidString);
3555 RtlFreeUnicodeString(&UserClassesKeyRoot);
3556
3557 if (!NT_SUCCESS(Status))
3558 {
3559 return RtlNtStatusToDosError(Status);
3560 }
3561
3562 return ERROR_SUCCESS;
3563 }
3564
3565
3566 /************************************************************************
3567 * RegQueryInfoKeyA
3568 *
3569 * @implemented
3570 */
3571 LONG STDCALL
3572 RegQueryInfoKeyA(HKEY hKey,
3573 LPSTR lpClass,
3574 LPDWORD lpcbClass,
3575 LPDWORD lpReserved,
3576 LPDWORD lpcSubKeys,
3577 LPDWORD lpcbMaxSubKeyLen,
3578 LPDWORD lpcbMaxClassLen,
3579 LPDWORD lpcValues,
3580 LPDWORD lpcbMaxValueNameLen,
3581 LPDWORD lpcbMaxValueLen,
3582 LPDWORD lpcbSecurityDescriptor,
3583 PFILETIME lpftLastWriteTime)
3584 {
3585 WCHAR ClassName[MAX_PATH];
3586 UNICODE_STRING UnicodeString;
3587 ANSI_STRING AnsiString;
3588 LONG ErrorCode;
3589
3590 RtlInitUnicodeString(&UnicodeString,
3591 NULL);
3592 if (lpClass != NULL)
3593 {
3594 UnicodeString.Buffer = &ClassName[0];
3595 UnicodeString.MaximumLength = sizeof(ClassName);
3596 AnsiString.MaximumLength = *lpcbClass;
3597 }
3598
3599 ErrorCode = RegQueryInfoKeyW(hKey,
3600 UnicodeString.Buffer,
3601 lpcbClass,
3602 lpReserved,
3603 lpcSubKeys,
3604 lpcbMaxSubKeyLen,
3605 lpcbMaxClassLen,
3606 lpcValues,
3607 lpcbMaxValueNameLen,
3608 lpcbMaxValueLen,
3609 lpcbSecurityDescriptor,
3610 lpftLastWriteTime);
3611 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
3612 {
3613 AnsiString.Buffer = lpClass;
3614 AnsiString.Length = 0;
3615 UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
3616 RtlUnicodeStringToAnsiString(&AnsiString,
3617 &UnicodeString,
3618 FALSE);
3619 *lpcbClass = AnsiString.Length;
3620 lpClass[AnsiString.Length] = 0;
3621 }
3622
3623 return ErrorCode;
3624 }
3625
3626
3627 /************************************************************************
3628 * RegQueryInfoKeyW
3629 *
3630 * @implemented
3631 */
3632 LONG STDCALL
3633 RegQueryInfoKeyW(HKEY hKey,
3634 LPWSTR lpClass,
3635 LPDWORD lpcbClass,
3636 LPDWORD lpReserved,
3637 LPDWORD lpcSubKeys,
3638 LPDWORD lpcbMaxSubKeyLen,
3639 LPDWORD lpcbMaxClassLen,
3640 LPDWORD lpcValues,
3641 LPDWORD lpcbMaxValueNameLen,
3642 LPDWORD lpcbMaxValueLen,
3643 LPDWORD lpcbSecurityDescriptor,
3644 PFILETIME lpftLastWriteTime)
3645 {
3646 KEY_FULL_INFORMATION FullInfoBuffer;
3647 PKEY_FULL_INFORMATION FullInfo;
3648 ULONG FullInfoSize;
3649 ULONG ClassLength = 0;
3650 HANDLE KeyHandle;
3651 NTSTATUS Status;
3652 ULONG Length;
3653 LONG ErrorCode = ERROR_SUCCESS;
3654
3655 if ((lpClass) && (!lpcbClass))
3656 {
3657 return ERROR_INVALID_PARAMETER;
3658 }
3659
3660 Status = MapDefaultKey(&KeyHandle,
3661 hKey);
3662 if (!NT_SUCCESS(Status))
3663 {
3664 return RtlNtStatusToDosError(Status);
3665 }
3666
3667 if (lpClass != NULL)
3668 {
3669 if (*lpcbClass > 0)
3670 {
3671 ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
3672 }
3673 else
3674 {
3675 ClassLength = 0;
3676 }
3677
3678 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
3679 FullInfo = RtlAllocateHeap(ProcessHeap,
3680 0,
3681 FullInfoSize);
3682 if (FullInfo == NULL)
3683 {
3684 ErrorCode = ERROR_OUTOFMEMORY;
3685 goto Cleanup;
3686 }
3687
3688 FullInfo->ClassLength = ClassLength;
3689 }
3690 else
3691 {
3692 FullInfoSize = sizeof(KEY_FULL_INFORMATION);
3693 FullInfo = &FullInfoBuffer;
3694 FullInfo->ClassLength = 0;
3695 }
3696 FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
3697
3698 Status = NtQueryKey(KeyHandle,
3699 KeyFullInformation,
3700 FullInfo,
3701 FullInfoSize,
3702 &Length);
3703 TRACE("NtQueryKey() returned status 0x%X\n", Status);
3704 if (!NT_SUCCESS(Status))
3705 {
3706 if (lpClass != NULL)
3707 {
3708 RtlFreeHeap(ProcessHeap,
3709 0,
3710 FullInfo);
3711 }
3712
3713 ErrorCode = RtlNtStatusToDosError(Status);
3714 goto Cleanup;
3715 }
3716
3717 TRACE("SubKeys %d\n", FullInfo->SubKeys);
3718 if (lpcSubKeys != NULL)
3719 {
3720 *lpcSubKeys = FullInfo->SubKeys;
3721 }
3722
3723 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
3724 if (lpcbMaxSubKeyLen != NULL)
3725 {
3726 *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
3727 }
3728
3729 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
3730 if (lpcbMaxClassLen != NULL)
3731 {
3732 *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
3733 }
3734
3735 TRACE("Values %lu\n", FullInfo->Values);
3736 if (lpcValues != NULL)
3737 {
3738 *lpcValues = FullInfo->Values;
3739 }
3740
3741 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
3742 if (lpcbMaxValueNameLen != NULL)
3743 {
3744 *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
3745 }
3746
3747 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
3748 if (lpcbMaxValueLen != NULL)
3749 {
3750 *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
3751 }
3752
3753 #if 0
3754 if (lpcbSecurityDescriptor != NULL)
3755 {
3756 Status = NtQuerySecurityObject(KeyHandle,
3757 OWNER_SECURITY_INFORMATION |
3758 GROUP_SECURITY_INFORMATION |
3759 DACL_SECURITY_INFORMATION,
3760 NULL,
3761 0,
3762 lpcbSecurityDescriptor);
3763 if (!NT_SUCCESS(Status))
3764 {
3765 if (lpClass != NULL)
3766 {
3767 RtlFreeHeap(ProcessHeap,
3768 0,
3769 FullInfo);
3770 }
3771
3772 ErrorCode = RtlNtStatusToDosError(Status);
3773 goto Cleanup;
3774 }
3775 }
3776 #endif
3777
3778 if (lpftLastWriteTime != NULL)
3779 {
3780 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
3781 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
3782 }
3783
3784 if (lpClass != NULL)
3785 {
3786 if (FullInfo->ClassLength > ClassLength)
3787 {
3788 ErrorCode = ERROR_BUFFER_OVERFLOW;
3789 }
3790 else
3791 {
3792 RtlCopyMemory(lpClass,
3793 FullInfo->Class,
3794 FullInfo->ClassLength);
3795 *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
3796 lpClass[*lpcbClass] = 0;
3797 }
3798
3799 RtlFreeHeap(ProcessHeap,
3800 0,
3801 FullInfo);
3802 }
3803
3804 Cleanup:
3805 ClosePredefKey(KeyHandle);
3806
3807 return ErrorCode;
3808 }
3809
3810
3811 /************************************************************************
3812 * RegQueryMultipleValuesA
3813 *
3814 * @implemented
3815 */
3816 LONG STDCALL
3817 RegQueryMultipleValuesA(HKEY hKey,
3818 PVALENTA val_list,
3819 DWORD num_vals,
3820 LPSTR lpValueBuf,
3821 LPDWORD ldwTotsize)
3822 {
3823 ULONG i;
3824 DWORD maxBytes = *ldwTotsize;
3825 LPSTR bufptr = (LPSTR)lpValueBuf;
3826 LONG ErrorCode;
3827
3828 if (maxBytes >= (1024*1024))
3829 return ERROR_TRANSFER_TOO_LONG;
3830
3831 *ldwTotsize = 0;
3832
3833 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3834 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3835
3836 for (i = 0; i < num_vals; i++)
3837 {
3838 val_list[i].ve_valuelen = 0;
3839 ErrorCode = RegQueryValueExA(hKey,
3840 val_list[i].ve_valuename,
3841 NULL,
3842 NULL,
3843 NULL,
3844 &val_list[i].ve_valuelen);
3845 if (ErrorCode != ERROR_SUCCESS)
3846 {
3847 return ErrorCode;
3848 }
3849
3850 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3851 {
3852 ErrorCode = RegQueryValueExA(hKey,
3853 val_list[i].ve_valuename,
3854 NULL,
3855 &val_list[i].ve_type,
3856 (LPBYTE)bufptr,
3857 &val_list[i].ve_valuelen);
3858 if (ErrorCode != ERROR_SUCCESS)
3859 {
3860 return ErrorCode;
3861 }
3862
3863 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3864
3865 bufptr += val_list[i].ve_valuelen;
3866 }
3867
3868 *ldwTotsize += val_list[i].ve_valuelen;
3869 }
3870
3871 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3872 }
3873
3874
3875 /************************************************************************
3876 * RegQueryMultipleValuesW
3877 *
3878 * @implemented
3879 */
3880 LONG STDCALL
3881 RegQueryMultipleValuesW(HKEY hKey,
3882 PVALENTW val_list,
3883 DWORD num_vals,
3884 LPWSTR lpValueBuf,
3885 LPDWORD ldwTotsize)
3886 {
3887 ULONG i;
3888 DWORD maxBytes = *ldwTotsize;
3889 LPSTR bufptr = (LPSTR)lpValueBuf;
3890 LONG ErrorCode;
3891
3892 if (maxBytes >= (1024*1024))
3893 return ERROR_TRANSFER_TOO_LONG;
3894
3895 *ldwTotsize = 0;
3896
3897 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3898 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
3899
3900 for (i = 0; i < num_vals; i++)
3901 {
3902 val_list[i].ve_valuelen = 0;
3903 ErrorCode = RegQueryValueExW(hKey,
3904 val_list[i].ve_valuename,
3905 NULL,
3906 NULL,
3907 NULL,
3908 &val_list[i].ve_valuelen);
3909 if (ErrorCode != ERROR_SUCCESS)
3910 {
3911 return ErrorCode;
3912 }
3913
3914 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
3915 {
3916 ErrorCode = RegQueryValueExW(hKey,
3917 val_list[i].ve_valuename,
3918 NULL,
3919 &val_list[i].ve_type,
3920 (LPBYTE)bufptr,
3921 &val_list[i].ve_valuelen);
3922 if (ErrorCode != ERROR_SUCCESS)
3923 {
3924 return ErrorCode;
3925 }
3926
3927 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3928
3929 bufptr += val_list[i].ve_valuelen;
3930 }
3931
3932 *ldwTotsize += val_list[i].ve_valuelen;
3933 }
3934
3935 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3936 }
3937
3938
3939 /************************************************************************
3940 * RegQueryReflectionKey
3941 *
3942 * @unimplemented
3943 */
3944 LONG WINAPI
3945 RegQueryReflectionKey(IN HKEY hBase,
3946 OUT BOOL* bIsReflectionDisabled)
3947 {
3948 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3949 hBase, bIsReflectionDisabled);
3950 return ERROR_CALL_NOT_IMPLEMENTED;
3951 }
3952
3953
3954 /************************************************************************
3955 * RegQueryValueExA
3956 *
3957 * @implemented
3958 */
3959 LONG STDCALL
3960 RegQueryValueExA(HKEY hKey,
3961 LPCSTR lpValueName,
3962 LPDWORD lpReserved,
3963 LPDWORD lpType,
3964 LPBYTE lpData,
3965 LPDWORD lpcbData)
3966 {
3967 UNICODE_STRING ValueName;
3968 UNICODE_STRING ValueData;
3969 ANSI_STRING AnsiString;
3970 LONG ErrorCode;
3971 DWORD Length;
3972 DWORD Type;
3973
3974 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3975 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
3976
3977 if (lpData != NULL && lpcbData == NULL)
3978 {
3979 return ERROR_INVALID_PARAMETER;
3980 }
3981
3982 if (lpData)
3983 {
3984 ValueData.Length = 0;
3985 ValueData.MaximumLength = (*lpcbData + 1) * sizeof(WCHAR);
3986 ValueData.Buffer = RtlAllocateHeap(ProcessHeap,
3987 0,
3988 ValueData.MaximumLength);
3989 if (!ValueData.Buffer)
3990 {
3991 return ERROR_OUTOFMEMORY;
3992 }
3993 }
3994 else
3995 {
3996 ValueData.Buffer = NULL;
3997 ValueData.Length = 0;
3998 ValueData.MaximumLength = 0;
3999
4000 if (lpcbData)
4001 *lpcbData = 0;
4002 }
4003
4004 RtlCreateUnicodeStringFromAsciiz(&ValueName,
4005 (LPSTR)lpValueName);
4006
4007 Length = (lpcbData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
4008 ErrorCode = RegQueryValueExW(hKey,
4009 ValueName.Buffer,
4010 lpReserved,
4011 &Type,
4012 (lpData == NULL) ? NULL : (LPBYTE)ValueData.Buffer,
4013 &Length);
4014 TRACE("ErrorCode %lu\n", ErrorCode);
4015 RtlFreeUnicodeString(&ValueName);
4016
4017 if (ErrorCode == ERROR_SUCCESS ||
4018 ErrorCode == ERROR_MORE_DATA)
4019 {
4020 if (lpType != NULL)
4021 {
4022 *lpType = Type;
4023 }
4024
4025 if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ))
4026 {
4027 if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
4028 {
4029 RtlInitAnsiString(&AnsiString, NULL);
4030 AnsiString.Buffer = (LPSTR)lpData;
4031 AnsiString.MaximumLength = *lpcbData;
4032 ValueData.Length = Length;
4033 ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
4034 RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
4035 }
4036
4037 Length = Length / sizeof(WCHAR);
4038 }
4039 else if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
4040 {
4041 if (*lpcbData < Length)
4042 {
4043 ErrorCode = ERROR_MORE_DATA;
4044 }
4045 else
4046 {
4047 RtlMoveMemory(lpData, ValueData.Buffer, Length);
4048 }
4049 }
4050
4051 if (lpcbData != NULL)
4052 {
4053 *lpcbData = Length;
4054 }
4055 }
4056
4057 if (ValueData.Buffer != NULL)
4058 {
4059 RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
4060 }
4061
4062 return ErrorCode;
4063 }
4064
4065
4066 /************************************************************************
4067 * RegQueryValueExW
4068 *
4069 * @implemented
4070 */
4071 LONG
4072 WINAPI
4073 RegQueryValueExW(HKEY hkeyorg,
4074 LPCWSTR name,
4075 LPDWORD reserved,
4076 LPDWORD type,
4077 LPBYTE data,
4078 LPDWORD count)
4079 {
4080 HANDLE hkey;
4081 NTSTATUS status;
4082 UNICODE_STRING name_str;
4083 DWORD total_size;
4084 char buffer[256], *buf_ptr = buffer;
4085 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
4086 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
4087
4088 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4089 hkey, debugstr_w(name), reserved, type, data, count,
4090 (count && data) ? *count : 0 );
4091
4092 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
4093 //if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
4094
4095 status = MapDefaultKey(&hkey, hkeyorg);
4096 if (!NT_SUCCESS(status))
4097 {
4098 return RtlNtStatusToDosError(status);
4099 }
4100
4101 RtlInitUnicodeString( &name_str, name );
4102
4103 if (data) total_size = min( sizeof(buffer), *count + info_size );
4104 else
4105 {
4106 total_size = info_size;
4107 if (count) *count = 0;
4108 }
4109
4110 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4111 buffer, total_size, &total_size );
4112 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
4113
4114 if (data)
4115 {
4116 /* retry with a dynamically allocated buffer */
4117 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
4118 {
4119 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4120 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
4121 return ERROR_NOT_ENOUGH_MEMORY;
4122 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
4123 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
4124 buf_ptr, total_size, &total_size );
4125 }
4126
4127 if (!status)
4128 {
4129 memcpy( data, buf_ptr + info_size, total_size - info_size );
4130 /* if the type is REG_SZ and data is not 0-terminated
4131 * and there is enough space in the buffer NT appends a \0 */
4132 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
4133 {
4134 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
4135 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
4136 }
4137 }
4138 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
4139 }
4140 else status = STATUS_SUCCESS;
4141
4142 if (type) *type = info->Type;
4143 if (count) *count = total_size - info_size;
4144
4145 done:
4146 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
4147 ClosePredefKey(hkey);
4148 return RtlNtStatusToDosError(status);
4149 }
4150
4151
4152 /************************************************************************
4153 * RegQueryValueA
4154 *
4155 * @implemented
4156 */
4157 LONG STDCALL
4158 RegQueryValueA(HKEY hKey,
4159 LPCSTR lpSubKey,
4160 LPSTR lpValue,
4161 PLONG lpcbValue)
4162 {
4163 WCHAR SubKeyNameBuffer[MAX_PATH+1];
4164 UNICODE_STRING SubKeyName;
4165 UNICODE_STRING Value;
4166 ANSI_STRING AnsiString;
4167 LONG ValueSize;
4168 LONG ErrorCode;
4169
4170 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
4171 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
4172
4173 if (lpValue != NULL &&
4174 lpcbValue == NULL)
4175 {
4176 return ERROR_INVALID_PARAMETER;
4177 }
4178
4179 RtlInitUnicodeString(&SubKeyName,
4180 NULL);
4181 RtlInitUnicodeString(&Value,
4182 NULL);
4183 if (lpSubKey != NULL &&
4184 strlen(lpSubKey) != 0)
4185 {
4186 RtlInitAnsiString(&AnsiString,
4187 (LPSTR)lpSubKey);
4188 SubKeyName.Buffer = &SubKeyNameBuffer[0];
4189 SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
4190 RtlAnsiStringToUnicodeString(&SubKeyName,
4191 &AnsiString,
4192 FALSE);
4193 }
4194
4195 if (lpValue != NULL)
4196 {
4197 ValueSize = *lpcbValue * sizeof(WCHAR);
4198 Value.MaximumLength = ValueSize;
4199 Value.Buffer = RtlAllocateHeap(ProcessHeap,
4200 0,
4201 ValueSize);
4202 if (Value.Buffer == NULL)
4203 {
4204 return ERROR_OUTOFMEMORY;
4205 }
4206 }
4207 else
4208 {
4209 ValueSize = 0;
4210 }
4211
4212 ErrorCode = RegQueryValueW(hKey,
4213 (LPCWSTR)SubKeyName.Buffer,
4214 Value.Buffer,
4215 &ValueSize);
4216 if (ErrorCode == ERROR_SUCCESS)
4217 {
4218 if (lpValue != NULL)
4219 {
4220 Value.Length = ValueSize;
4221 RtlInitAnsiString(&AnsiString,
4222 NULL);
4223 AnsiString.Buffer = lpValue;
4224 AnsiString.MaximumLength = *lpcbValue;
4225 RtlUnicodeStringToAnsiString(&AnsiString,
4226 &Value,
4227 FALSE);
4228 *lpcbValue = ValueSize;
4229 }
4230 else if (lpcbValue != NULL)
4231 {
4232 *lpcbValue = ValueSize;
4233 }
4234 }
4235
4236 if (Value.Buffer != NULL)
4237 {
4238 RtlFreeHeap(ProcessHeap,
4239 0,
4240 Value.Buffer);
4241 }
4242
4243 return ErrorCode;
4244 }
4245
4246
4247 /************************************************************************
4248 * RegQueryValueW
4249 *
4250 * @implemented
4251 */
4252 LONG STDCALL
4253 RegQueryValueW(HKEY hKey,
4254 LPCWSTR lpSubKey,
4255 LPWSTR lpValue,
4256 PLONG lpcbValue)
4257 {
4258 OBJECT_ATTRIBUTES ObjectAttributes;
4259 UNICODE_STRING SubKeyString;
4260 HANDLE KeyHandle;
4261 HANDLE RealKey;
4262 LONG ErrorCode;
4263 BOOL CloseRealKey;
4264 NTSTATUS Status;
4265
4266 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
4267 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
4268
4269 Status = MapDefaultKey(&KeyHandle,
4270 hKey);
4271 if (!NT_SUCCESS(Status))
4272 {
4273 return RtlNtStatusToDosError(Status);
4274 }
4275
4276 if (lpSubKey != NULL &&
4277 wcslen(lpSubKey) != 0)
4278 {
4279 RtlInitUnicodeString(&SubKeyString,
4280 (LPWSTR)lpSubKey);
4281 InitializeObjectAttributes(&ObjectAttributes,
4282 &SubKeyString,
4283 OBJ_CASE_INSENSITIVE,
4284 KeyHandle,
4285 NULL);
4286 Status = NtOpenKey(&RealKey,
4287 KEY_QUERY_VALUE,
4288 &ObjectAttributes);
4289 if (!NT_SUCCESS(Status))
4290 {
4291 ErrorCode = RtlNtStatusToDosError(Status);
4292 goto Cleanup;
4293 }
4294
4295 CloseRealKey = TRUE;
4296 }
4297 else
4298 {
4299 RealKey = hKey;
4300 CloseRealKey = FALSE;
4301 }
4302
4303 ErrorCode = RegQueryValueExW(RealKey,
4304 NULL,
4305 NULL,
4306 NULL,
4307 (LPBYTE)lpValue,
4308 (LPDWORD)lpcbValue);
4309 if (CloseRealKey)
4310 {
4311 NtClose(RealKey);
4312 }
4313
4314 Cleanup:
4315 ClosePredefKey(KeyHandle);
4316
4317 return ErrorCode;
4318 }
4319
4320
4321 /************************************************************************
4322 * RegReplaceKeyA
4323 *
4324 * @implemented
4325 */
4326 LONG STDCALL
4327 RegReplaceKeyA(HKEY hKey,
4328 LPCSTR lpSubKey,
4329 LPCSTR lpNewFile,
4330 LPCSTR lpOldFile)
4331 {
4332 UNICODE_STRING SubKey;
4333 UNICODE_STRING NewFile;
4334 UNICODE_STRING OldFile;
4335 LONG ErrorCode;
4336
4337 RtlCreateUnicodeStringFromAsciiz(&SubKey,
4338 (PCSZ)lpSubKey);
4339 RtlCreateUnicodeStringFromAsciiz(&OldFile,
4340 (PCSZ)lpOldFile);
4341 RtlCreateUnicodeStringFromAsciiz(&NewFile,
4342 (PCSZ)lpNewFile);
4343
4344 ErrorCode = RegReplaceKeyW(hKey,
4345 SubKey.Buffer,
4346 NewFile.Buffer,
4347 OldFile.Buffer);
4348
4349 RtlFreeUnicodeString(&OldFile);
4350 RtlFreeUnicodeString(&NewFile);
4351 RtlFreeUnicodeString(&SubKey);
4352
4353 return ErrorCode;
4354 }
4355
4356
4357 /************************************************************************
4358 * RegReplaceKeyW
4359 *
4360 * @unimplemented
4361 */
4362 LONG STDCALL
4363 RegReplaceKeyW(HKEY hKey,
4364 LPCWSTR lpSubKey,
4365 LPCWSTR lpNewFile,
4366 LPCWSTR lpOldFile)
4367 {
4368 OBJECT_ATTRIBUTES KeyObjectAttributes;
4369 OBJECT_ATTRIBUTES NewObjectAttributes;
4370 OBJECT_ATTRIBUTES OldObjectAttributes;
4371 UNICODE_STRING SubKeyName;
4372 UNICODE_STRING NewFileName;
4373 UNICODE_STRING OldFileName;
4374 BOOLEAN CloseRealKey;
4375 HANDLE RealKeyHandle;
4376 HANDLE KeyHandle;
4377 NTSTATUS Status;
4378 LONG ErrorCode = ERROR_SUCCESS;
4379
4380 if (hKey == HKEY_PERFORMANCE_DATA)
4381 {
4382 return ERROR_INVALID_HANDLE;
4383 }
4384
4385 Status = MapDefaultKey(&KeyHandle,
4386 hKey);
4387 if (!NT_SUCCESS(Status))
4388 {
4389 return RtlNtStatusToDosError(Status);
4390 }
4391
4392 /* Open the real key */
4393 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
4394 {
4395 RtlInitUnicodeString(&SubKeyName,
4396 (PWSTR)lpSubKey);
4397 InitializeObjectAttributes(&KeyObjectAttributes,
4398 &SubKeyName,
4399 OBJ_CASE_INSENSITIVE,
4400 KeyHandle,
4401 NULL);
4402 Status = NtOpenKey(&RealKeyHandle,
4403 MAXIMUM_ALLOWED,
4404 &KeyObjectAttributes);
4405 if (!NT_SUCCESS(Status))
4406 {
4407 ErrorCode = RtlNtStatusToDosError(Status);
4408 goto Cleanup;
4409 }
4410
4411 CloseRealKey = TRUE;
4412 }
4413 else
4414 {
4415 RealKeyHandle = KeyHandle;
4416 CloseRealKey = FALSE;
4417 }
4418
4419 /* Convert new file name */
4420 if (!RtlDosPathNameToNtPathName_U(lpNewFile,
4421 &NewFileName,
4422 NULL,
4423 NULL))
4424 {
4425 if (CloseRealKey)
4426 {
4427 NtClose(RealKeyHandle);
4428 }
4429
4430 ErrorCode = ERROR_INVALID_PARAMETER;
4431 goto Cleanup;
4432 }
4433
4434 InitializeObjectAttributes(&NewObjectAttributes,
4435 &NewFileName,
4436 OBJ_CASE_INSENSITIVE,
4437 NULL,
4438 NULL);
4439
4440 /* Convert old file name */
4441 if (!RtlDosPathNameToNtPathName_U(lpOldFile,
4442 &OldFileName,
4443 NULL,
4444 NULL))
4445 {
4446 RtlFreeHeap(RtlGetProcessHeap (),
4447 0,
4448 NewFileName.Buffer);
4449 if (CloseRealKey)
4450 {
4451 NtClose(RealKeyHandle);
4452 }
4453
4454 ErrorCode = ERROR_INVALID_PARAMETER;
4455 goto Cleanup;
4456 }
4457
4458 InitializeObjectAttributes(&OldObjectAttributes,
4459 &OldFileName,
4460 OBJ_CASE_INSENSITIVE,
4461 NULL,
4462 NULL);
4463
4464 Status = NtReplaceKey(&NewObjectAttributes,
4465 RealKeyHandle,
4466 &OldObjectAttributes);
4467
4468 RtlFreeHeap(RtlGetProcessHeap(),
4469 0,
4470 OldFileName.Buffer);
4471 RtlFreeHeap(RtlGetProcessHeap(),
4472 0,
4473 NewFileName.Buffer);
4474
4475 if (CloseRealKey)
4476 {
4477 NtClose(RealKeyHandle);
4478 }
4479
4480 if (!NT_SUCCESS(Status))
4481 {
4482 return RtlNtStatusToDosError(Status);
4483 }
4484
4485 Cleanup:
4486 ClosePredefKey(KeyHandle);
4487
4488 return ErrorCode;
4489 }
4490
4491
4492 /************************************************************************
4493 * RegRestoreKeyA
4494 *
4495 * @implemented
4496 */
4497 LONG STDCALL
4498 RegRestoreKeyA(HKEY hKey,
4499 LPCSTR lpFile,
4500 DWORD dwFlags)
4501 {
4502 UNICODE_STRING FileName;
4503 LONG ErrorCode;
4504
4505 RtlCreateUnicodeStringFromAsciiz(&FileName,
4506 (PCSZ)lpFile);
4507
4508 ErrorCode = RegRestoreKeyW(hKey,
4509 FileName.Buffer,
4510 dwFlags);
4511
4512 RtlFreeUnicodeString(&FileName);
4513
4514 return ErrorCode;
4515 }
4516
4517
4518 /************************************************************************
4519 * RegRestoreKeyW
4520 *
4521 * @implemented
4522 */
4523 LONG STDCALL
4524 RegRestoreKeyW(HKEY hKey,
4525 LPCWSTR lpFile,
4526 DWORD dwFlags)
4527 {
4528 OBJECT_ATTRIBUTES ObjectAttributes;
4529 IO_STATUS_BLOCK IoStatusBlock;
4530 UNICODE_STRING FileName;
4531 HANDLE FileHandle;
4532 HANDLE KeyHandle;
4533 NTSTATUS Status;
4534
4535 if (hKey == HKEY_PERFORMANCE_DATA)
4536 {
4537 return ERROR_INVALID_HANDLE;
4538 }
4539
4540 Status = MapDefaultKey(&KeyHandle,
4541 hKey);
4542 if (!NT_SUCCESS(Status))
4543 {
4544 return RtlNtStatusToDosError(Status);
4545 }
4546
4547 if (!RtlDosPathNameToNtPathName_U(lpFile,
4548 &FileName,
4549 NULL,
4550 NULL))
4551 {
4552 Status = STATUS_INVALID_PARAMETER;
4553 goto Cleanup;
4554 }
4555
4556 InitializeObjectAttributes(&ObjectAttributes,
4557 &FileName,
4558 OBJ_CASE_INSENSITIVE,
4559 NULL,
4560 NULL);
4561
4562 Status = NtOpenFile(&FileHandle,
4563 FILE_GENERIC_READ,
4564 &ObjectAttributes,
4565 &IoStatusBlock,
4566 FILE_SHARE_READ,
4567 FILE_SYNCHRONOUS_IO_NONALERT);
4568 RtlFreeHeap(RtlGetProcessHeap(),
4569 0,
4570 FileName.Buffer);
4571 if (!NT_SUCCESS(Status))
4572 {
4573 goto Cleanup;
4574 }
4575
4576 Status = NtRestoreKey(KeyHandle,
4577 FileHandle,
4578 (ULONG)dwFlags);
4579 NtClose (FileHandle);
4580
4581 Cleanup:
4582 ClosePredefKey(KeyHandle);
4583
4584 if (!NT_SUCCESS(Status))
4585 {
4586 return RtlNtStatusToDosError(Status);
4587 }
4588
4589 return ERROR_SUCCESS;
4590 }
4591
4592
4593 /************************************************************************
4594 * RegSaveKeyA
4595 *
4596 * @implemented
4597 */
4598 LONG STDCALL
4599 RegSaveKeyA(HKEY hKey,
4600 LPCSTR lpFile,
4601 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4602 {
4603 UNICODE_STRING FileName;
4604 LONG ErrorCode;
4605
4606 RtlCreateUnicodeStringFromAsciiz(&FileName,
4607 (LPSTR)lpFile);
4608 ErrorCode = RegSaveKeyW(hKey,
4609 FileName.Buffer,
4610 lpSecurityAttributes);
4611 RtlFreeUnicodeString(&FileName);
4612
4613 return ErrorCode;
4614 }
4615
4616
4617 /************************************************************************
4618 * RegSaveKeyW
4619 *
4620 * @implemented
4621 */
4622 LONG STDCALL
4623 RegSaveKeyW(HKEY hKey,
4624 LPCWSTR lpFile,
4625 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
4626 {
4627 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
4628 OBJECT_ATTRIBUTES ObjectAttributes;
4629 UNICODE_STRING FileName;
4630 IO_STATUS_BLOCK IoStatusBlock;
4631 HANDLE FileHandle;
4632 HANDLE KeyHandle;
4633 NTSTATUS Status;
4634
4635 Status = MapDefaultKey(&KeyHandle,
4636 hKey);
4637 if (!NT_SUCCESS(Status))
4638 {
4639 return RtlNtStatusToDosError(Status);
4640 }
4641
4642 if (!RtlDosPathNameToNtPathName_U(lpFile,
4643 &FileName,
4644 NULL,
4645 NULL))
4646 {
4647 Status = STATUS_INVALID_PARAMETER;
4648 goto Cleanup;
4649 }
4650
4651 if (lpSecurityAttributes != NULL)
4652 {
4653 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
4654 }
4655
4656 InitializeObjectAttributes(&ObjectAttributes,
4657 &FileName,
4658 OBJ_CASE_INSENSITIVE,
4659 NULL,
4660 SecurityDescriptor);
4661 Status = NtCreateFile(&FileHandle,
4662 GENERIC_WRITE | SYNCHRONIZE,
4663 &ObjectAttributes,
4664 &IoStatusBlock,
4665 NULL,
4666 FILE_ATTRIBUTE_NORMAL,
4667 FILE_SHARE_READ,
4668 FILE_CREATE,
4669 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
4670 NULL,
4671 0);
4672 RtlFreeHeap(RtlGetProcessHeap(),
4673 0,
4674 FileName.Buffer);
4675 if (!NT_SUCCESS(Status))
4676 {
4677 goto Cleanup;
4678 }
4679
4680 Status = NtSaveKey(KeyHandle,
4681 FileHandle);
4682 NtClose (FileHandle);
4683
4684 Cleanup:
4685 ClosePredefKey(KeyHandle);
4686
4687 if (!NT_SUCCESS(Status))
4688 {
4689 return RtlNtStatusToDosError(Status);
4690 }
4691
4692 return ERROR_SUCCESS;
4693 }
4694
4695
4696 /************************************************************************
4697 * RegSetKeySecurity
4698 *
4699 * @implemented
4700 */
4701 LONG STDCALL
4702 RegSetKeySecurity(HKEY hKey,
4703 SECURITY_INFORMATION SecurityInformation,
4704 PSECURITY_DESCRIPTOR pSecurityDescriptor)
4705 {
4706 HANDLE KeyHandle;
4707 NTSTATUS Status;
4708
4709 if (hKey == HKEY_PERFORMANCE_DATA)
4710 {
4711 return ERROR_INVALID_HANDLE;
4712 }
4713
4714 Status = MapDefaultKey(&KeyHandle,
4715 hKey);
4716 if (!NT_SUCCESS(Status))
4717 {
4718 return RtlNtStatusToDosError(Status);
4719 }
4720
4721 Status = NtSetSecurityObject(KeyHandle,
4722 SecurityInformation,
4723 pSecurityDescriptor);
4724
4725 ClosePredefKey(KeyHandle);
4726
4727 if (!NT_SUCCESS(Status))
4728 {
4729 return RtlNtStatusToDosError(Status);
4730 }
4731
4732 return ERROR_SUCCESS;
4733 }
4734
4735
4736 /************************************************************************
4737 * RegSetValueExA
4738 *
4739 * @implemented
4740 */
4741 LONG STDCALL
4742 RegSetValueExA(HKEY hKey,
4743 LPCSTR lpValueName,
4744 DWORD Reserved,
4745 DWORD dwType,
4746 CONST BYTE* lpData,
4747 DWORD cbData)
4748 {
4749 UNICODE_STRING ValueName;
4750 LPWSTR pValueName;
4751 ANSI_STRING AnsiString;
4752 UNICODE_STRING Data;
4753 LONG ErrorCode;
4754 LPBYTE pData;
4755 DWORD DataSize;
4756
4757 if (lpValueName != NULL &&
4758 strlen(lpValueName) != 0)
4759 {
4760 RtlCreateUnicodeStringFromAsciiz(&ValueName,
4761 (PSTR)lpValueName);
4762 }
4763 else
4764 {
4765 ValueName.Buffer = NULL;
4766 }
4767
4768 pValueName = (LPWSTR)ValueName.Buffer;
4769
4770 if (((dwType == REG_SZ) ||
4771 (dwType == REG_MULTI_SZ) ||
4772 (dwType == REG_EXPAND_SZ)) &&
4773 (cbData != 0))
4774 {
4775 /* NT adds one if the caller forgot the NULL-termination character */
4776 if (lpData[cbData - 1] != '\0')
4777 {
4778 cbData++;
4779 }
4780
4781 RtlInitAnsiString(&AnsiString,
4782 NULL);
4783 AnsiString.Buffer = (PSTR)lpData;
4784 AnsiString.Length = cbData - 1;
4785 AnsiString.MaximumLength = cbData;
4786 RtlAnsiStringToUnicodeString(&Data,
4787 &AnsiString,
4788 TRUE);
4789 pData = (LPBYTE)Data.Buffer;
4790 DataSize = cbData * sizeof(WCHAR);
4791 }
4792 else
4793 {
4794 RtlInitUnicodeString(&Data,
4795 NULL);
4796 pData = (LPBYTE)lpData;
4797 DataSize = cbData;
4798 }
4799
4800 ErrorCode = RegSetValueExW(hKey,
4801 pValueName,
4802 Reserved,
4803 dwType,
4804 pData,
4805 DataSize);
4806 if (pValueName != NULL)
4807 {
4808 RtlFreeHeap(ProcessHeap,
4809 0,
4810 ValueName.Buffer);
4811 }
4812
4813 if (Data.Buffer != NULL)
4814 {
4815 RtlFreeHeap(ProcessHeap,
4816 0,
4817 Data.Buffer);
4818 }
4819
4820 return ErrorCode;
4821 }
4822
4823
4824 /************************************************************************
4825 * RegSetValueExW
4826 *
4827 * @implemented
4828 */
4829 LONG STDCALL
4830 RegSetValueExW(HKEY hKey,
4831 LPCWSTR lpValueName,
4832 DWORD Reserved,
4833 DWORD dwType,
4834 CONST BYTE* lpData,
4835 DWORD cbData)
4836 {
4837 UNICODE_STRING ValueName;
4838 PUNICODE_STRING pValueName;
4839 HANDLE KeyHandle;
4840 NTSTATUS Status;
4841
4842 Status = MapDefaultKey(&KeyHandle,
4843 hKey);
4844 if (!NT_SUCCESS(Status))
4845 {
4846 return RtlNtStatusToDosError(Status);
4847 }
4848
4849 if (lpValueName != NULL)
4850 {
4851 RtlInitUnicodeString(&ValueName,
4852 lpValueName);
4853 }
4854 else
4855 {
4856 RtlInitUnicodeString(&ValueName, L"");
4857 }
4858 pValueName = &ValueName;
4859
4860 if (((dwType == REG_SZ) ||
4861 (dwType == REG_MULTI_SZ) ||
4862 (dwType == REG_EXPAND_SZ)) &&
4863 (cbData != 0) && (*(((PWCHAR)lpData) + (cbData / sizeof(WCHAR)) - 1) != L'\0'))
4864 {
4865 /* NT adds one if the caller forgot the NULL-termination character */
4866 cbData += sizeof(WCHAR);
4867 }
4868
4869 Status = NtSetValueKey(KeyHandle,
4870 pValueName,
4871 0,
4872 dwType,
4873 (PVOID)lpData,
4874 (ULONG)cbData);
4875
4876 ClosePredefKey(KeyHandle);
4877
4878 if (!NT_SUCCESS(Status))
4879 {
4880 return RtlNtStatusToDosError(Status);
4881 }
4882
4883 return ERROR_SUCCESS;
4884 }
4885
4886
4887 /************************************************************************
4888 * RegSetValueA
4889 *
4890 * @implemented
4891 */
4892 LONG STDCALL
4893 RegSetValueA(HKEY hKeyOriginal,
4894 LPCSTR lpSubKey,
4895 DWORD dwType,
4896 LPCSTR lpData,
4897 DWORD cbData)
4898 {
4899 HKEY subkey;
4900 HANDLE hKey;
4901 DWORD ret;
4902 NTSTATUS Status;
4903
4904 TRACE("(%p,%s,%d,%s,%d)\n", hKey, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData );
4905
4906 if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER;
4907
4908 Status = MapDefaultKey(&hKey, hKeyOriginal);
4909 if (!NT_SUCCESS(Status))
4910 {
4911 return RtlNtStatusToDosError (Status);
4912 }
4913 subkey = hKey;
4914
4915 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
4916 {
4917 ret = RegCreateKeyA(hKey, lpSubKey, &subkey);
4918 if (ret != ERROR_SUCCESS)
4919 goto Cleanup;
4920 }
4921
4922 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 );
4923 if (subkey != hKey)
4924 RegCloseKey(subkey);
4925
4926 Cleanup:
4927 ClosePredefKey(hKey);
4928
4929 return ret;
4930 }
4931
4932
4933 /************************************************************************
4934 * RegSetValueW
4935 *
4936 * @implemented
4937 */
4938 LONG STDCALL
4939 RegSetValueW(HKEY hKeyOriginal,
4940 LPCWSTR lpSubKey,
4941 DWORD dwType,
4942 LPCWSTR lpData,
4943 DWORD cbData)
4944 {
4945 HKEY subkey;
4946 HANDLE hKey;
4947 DWORD ret;
4948 NTSTATUS Status;
4949
4950 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData );
4951
4952 if (dwType != REG_SZ || !lpData)
4953 return ERROR_INVALID_PARAMETER;
4954
4955 Status = MapDefaultKey(&hKey,
4956 hKeyOriginal);
4957 if (!NT_SUCCESS(Status))
4958 {
4959 return RtlNtStatusToDosError(Status);
4960 }
4961 subkey = hKey;
4962
4963 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */
4964 {
4965 ret = RegCreateKeyW(hKey, lpSubKey, &subkey);
4966 if (ret != ERROR_SUCCESS)
4967 goto Cleanup;
4968 }
4969
4970 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData,
4971 (wcslen( lpData ) + 1) * sizeof(WCHAR) );
4972 if (subkey != hKey)
4973 RegCloseKey(subkey);
4974
4975 Cleanup:
4976 ClosePredefKey(hKey);
4977
4978 return ret;
4979 }
4980
4981
4982 /************************************************************************
4983 * RegUnLoadKeyA
4984 *
4985 * @implemented
4986 */
4987 LONG STDCALL
4988 RegUnLoadKeyA(HKEY hKey,
4989 LPCSTR lpSubKey)
4990 {
4991 UNICODE_STRING KeyName;
4992 DWORD ErrorCode;
4993
4994 RtlCreateUnicodeStringFromAsciiz(&KeyName,
4995 (LPSTR)lpSubKey);
4996
4997 ErrorCode = RegUnLoadKeyW(hKey,
4998 KeyName.Buffer);
4999
5000 RtlFreeUnicodeString (&KeyName);
5001
5002 return ErrorCode;
5003 }
5004
5005
5006 /************************************************************************
5007 * RegUnLoadKeyW
5008 *
5009 * @implemented
5010 */
5011 LONG STDCALL
5012 RegUnLoadKeyW(HKEY hKey,
5013 LPCWSTR lpSubKey)
5014 {
5015 OBJECT_ATTRIBUTES ObjectAttributes;
5016 UNICODE_STRING KeyName;
5017 HANDLE KeyHandle;
5018 NTSTATUS Status;
5019
5020 if (hKey == HKEY_PERFORMANCE_DATA)
5021 {
5022 return ERROR_INVALID_HANDLE;
5023 }
5024
5025 Status = MapDefaultKey(&KeyHandle, hKey);
5026 if (!NT_SUCCESS(Status))
5027 {
5028 return RtlNtStatusToDosError(Status);
5029 }
5030
5031 RtlInitUnicodeString(&KeyName,
5032 (LPWSTR)lpSubKey);
5033
5034 InitializeObjectAttributes(&ObjectAttributes,
5035 &KeyName,
5036 OBJ_CASE_INSENSITIVE,
5037 KeyHandle,
5038 NULL);
5039
5040 Status = NtUnloadKey(&ObjectAttributes);
5041
5042 ClosePredefKey(KeyHandle);
5043
5044 if (!NT_SUCCESS(Status))
5045 {
5046 return RtlNtStatusToDosError(Status);
5047 }
5048
5049 return ERROR_SUCCESS;
5050 }
5051
5052
5053 /******************************************************************************
5054 * load_string [Internal]
5055 *
5056 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5057 * avoid importing user32, which is higher level than advapi32. Helper for
5058 * RegLoadMUIString.
5059 */
5060 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
5061 {
5062 HGLOBAL hMemory;
5063 HRSRC hResource;
5064 WCHAR *pString;
5065 int idxString;
5066
5067 /* Negative values have to be inverted. */
5068 if (HIWORD(resId) == 0xffff)
5069 resId = (UINT)(-((INT)resId));
5070
5071 /* Load the resource into memory and get a pointer to it. */
5072 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
5073 if (!hResource) return 0;
5074 hMemory = LoadResource(hModule, hResource);
5075 if (!hMemory) return 0;
5076 pString = LockResource(hMemory);
5077
5078 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5079 idxString = resId & 0xf;
5080 while (idxString--) pString += *pString + 1;
5081
5082 /* If no buffer is given, return length of the string. */
5083 if (!pwszBuffer) return *pString;
5084
5085 /* Else copy over the string, respecting the buffer size. */
5086 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
5087 if (cMaxChars >= 0)
5088 {
5089 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
5090 pwszBuffer[cMaxChars] = L'\0';
5091 }
5092
5093 return cMaxChars;
5094 }
5095
5096
5097 /************************************************************************
5098 * RegLoadMUIStringW
5099 *
5100 * @implemented
5101 */
5102 LONG STDCALL
5103 RegLoadMUIStringW(IN HKEY hKey,
5104 IN LPCWSTR pszValue OPTIONAL,
5105 OUT LPWSTR pszOutBuf,
5106 IN DWORD cbOutBuf,
5107 OUT LPDWORD pcbData OPTIONAL,
5108 IN DWORD Flags,
5109 IN LPCWSTR pszDirectory OPTIONAL)
5110 {
5111 DWORD dwValueType, cbData;
5112 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
5113 LONG result;
5114
5115 /* Parameter sanity checks. */
5116 if (!hKey || !pszOutBuf)
5117 return ERROR_INVALID_PARAMETER;
5118
5119 if (pszDirectory && *pszDirectory)
5120 {
5121 FIXME("BaseDir parameter not yet supported!\n");
5122 return ERROR_INVALID_PARAMETER;
5123 }
5124
5125 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5126 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
5127 if (result != ERROR_SUCCESS) goto cleanup;
5128 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
5129 {
5130 result = ERROR_FILE_NOT_FOUND;
5131 goto cleanup;
5132 }
5133 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5134 if (!pwszTempBuffer)
5135 {
5136 result = ERROR_NOT_ENOUGH_MEMORY;
5137 goto cleanup;
5138 }
5139 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
5140 if (result != ERROR_SUCCESS) goto cleanup;
5141
5142 /* Expand environment variables, if appropriate, or copy the original string over. */
5143 if (dwValueType == REG_EXPAND_SZ)
5144 {
5145 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
5146 if (!cbData) goto cleanup;
5147 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5148 if (!pwszExpandedBuffer)
5149 {
5150 result = ERROR_NOT_ENOUGH_MEMORY;
5151 goto cleanup;
5152 }
5153 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
5154 }
5155 else
5156 {
5157 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
5158 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
5159 }
5160
5161 /* If the value references a resource based string, parse the value and load the string.
5162 * Else just copy over the original value. */
5163 result = ERROR_SUCCESS;
5164 if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
5165 {
5166 lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
5167 }
5168 else
5169 {
5170 WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
5171 UINT uiStringId;
5172 HMODULE hModule;
5173
5174 /* Format of the expanded value is 'path_to_dll,-resId' */
5175 if (!pComma || pComma[1] != L'-')
5176 {
5177 result = ERROR_BADKEY;
5178 goto cleanup;
5179 }
5180
5181 uiStringId = _wtoi(pComma+2);
5182 *pComma = L'\0';
5183
5184 hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
5185 if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
5186 result = ERROR_BADKEY;
5187 FreeLibrary(hModule);
5188 }
5189
5190 cleanup:
5191 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
5192 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
5193 return result;
5194 }
5195
5196
5197 /************************************************************************
5198 * RegLoadMUIStringA
5199 *
5200 * @implemented
5201 */
5202 LONG STDCALL
5203 RegLoadMUIStringA(IN HKEY hKey,
5204 IN LPCSTR pszValue OPTIONAL,
5205 OUT LPSTR pszOutBuf,
5206 IN DWORD cbOutBuf,
5207 OUT LPDWORD pcbData OPTIONAL,
5208 IN DWORD Flags,
5209 IN LPCSTR pszDirectory OPTIONAL)
5210 {
5211 UNICODE_STRING valueW, baseDirW;
5212 WCHAR *pwszBuffer;
5213 DWORD cbData = cbOutBuf * sizeof(WCHAR);
5214 LONG result;
5215
5216 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
5217 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
5218 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
5219 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
5220 {
5221 result = ERROR_NOT_ENOUGH_MEMORY;
5222 goto cleanup;
5223 }
5224
5225 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
5226 baseDirW.Buffer);
5227
5228 if (result == ERROR_SUCCESS)
5229 {
5230 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
5231 if (pcbData)
5232 *pcbData = cbData;
5233 }
5234
5235 cleanup:
5236 HeapFree(GetProcessHeap(), 0, pwszBuffer);
5237 RtlFreeUnicodeString(&baseDirW);
5238 RtlFreeUnicodeString(&valueW);
5239
5240 return result;
5241 }
5242
5243 /* EOF */