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