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