Remove warnings
[reactos.git] / reactos / lib / advapi32 / reg / reg.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/advapi32/reg/reg.c
6 * PURPOSE: Registry functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
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 #define NDEBUG
18 #include <wine/debug.h>
19
20 /* DEFINES ******************************************************************/
21
22 #define MAX_DEFAULT_HANDLES 6
23 #define REG_MAX_NAME_SIZE 256
24 #define REG_MAX_DATA_SIZE 2048
25
26 /* FIXME: should go into msvcrt.h header? */
27 #define offsetof(s,m) (size_t)&(((s*)NULL)->m)
28
29 /* GLOBALS ******************************************************************/
30
31 static RTL_CRITICAL_SECTION HandleTableCS;
32 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
33 static HANDLE ProcessHeap;
34 static BOOLEAN DefaultHandlesDisabled = FALSE;
35
36 /* PROTOTYPES ***************************************************************/
37
38 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
39 static VOID CloseDefaultKeys(VOID);
40 #define CloseDefaultKey(Handle) \
41 if ((ULONG_PTR)Handle & 0x1) { \
42 NtClose(Handle); \
43 }
44
45 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
46 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
47 static NTSTATUS OpenUsersKey (PHANDLE KeyHandle);
48 static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
49
50
51 /* FUNCTIONS ****************************************************************/
52 /* check if value type needs string conversion (Ansi<->Unicode) */
53 inline static int is_string( DWORD type )
54 {
55 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
56 }
57
58 /************************************************************************
59 * RegInitDefaultHandles
60 */
61 BOOL
62 RegInitialize (VOID)
63 {
64 TRACE("RegInitialize()\n");
65
66 ProcessHeap = RtlGetProcessHeap();
67 RtlZeroMemory (DefaultHandleTable,
68 MAX_DEFAULT_HANDLES * sizeof(HANDLE));
69 RtlInitializeCriticalSection (&HandleTableCS);
70
71 return TRUE;
72 }
73
74
75 /************************************************************************
76 * RegInit
77 */
78 BOOL
79 RegCleanup (VOID)
80 {
81 TRACE("RegCleanup()\n");
82
83 CloseDefaultKeys ();
84 RtlDeleteCriticalSection (&HandleTableCS);
85
86 return TRUE;
87 }
88
89
90 static NTSTATUS
91 MapDefaultKey (OUT PHANDLE RealKey,
92 IN HKEY Key)
93 {
94 PHANDLE Handle;
95 ULONG Index;
96 BOOLEAN DoOpen;
97 NTSTATUS Status = STATUS_SUCCESS;
98
99 TRACE("MapDefaultKey (Key %x)\n", Key);
100
101 if (((ULONG)Key & 0xF0000000) != 0x80000000)
102 {
103 *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
104 return STATUS_SUCCESS;
105 }
106
107 /* Handle special cases here */
108 Index = (ULONG)Key & 0x0FFFFFFF;
109 if (Index >= MAX_DEFAULT_HANDLES)
110 {
111 return STATUS_INVALID_PARAMETER;
112 }
113
114 RtlEnterCriticalSection (&HandleTableCS);
115
116 if (!DefaultHandlesDisabled)
117 {
118 Handle = &DefaultHandleTable[Index];
119 DoOpen = (*Handle == NULL);
120 }
121 else
122 {
123 Handle = RealKey;
124 DoOpen = TRUE;
125 }
126
127 if (DoOpen)
128 {
129 /* create/open the default handle */
130 switch (Index)
131 {
132 case 0: /* HKEY_CLASSES_ROOT */
133 Status = OpenClassesRootKey (Handle);
134 break;
135
136 case 1: /* HKEY_CURRENT_USER */
137 Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
138 Handle);
139 break;
140
141 case 2: /* HKEY_LOCAL_MACHINE */
142 Status = OpenLocalMachineKey (Handle);
143 break;
144
145 case 3: /* HKEY_USERS */
146 Status = OpenUsersKey (Handle);
147 break;
148 #if 0
149 case 4: /* HKEY_PERFORMANCE_DATA */
150 Status = OpenPerformanceDataKey (Handle);
151 break;
152 #endif
153 case 5: /* HKEY_CURRENT_CONFIG */
154 Status = OpenCurrentConfigKey (Handle);
155 break;
156
157 case 6: /* HKEY_DYN_DATA */
158 Status = STATUS_NOT_IMPLEMENTED;
159 break;
160
161 default:
162 WARN("MapDefaultHandle() no handle creator\n");
163 Status = STATUS_INVALID_PARAMETER;
164 break;
165 }
166 }
167
168 if (NT_SUCCESS(Status))
169 {
170 if (!DefaultHandlesDisabled)
171 *RealKey = *Handle;
172 else
173 *(PULONG_PTR)Handle |= 0x1;
174 }
175
176 RtlLeaveCriticalSection (&HandleTableCS);
177
178 return Status;
179 }
180
181
182 static VOID
183 CloseDefaultKeys (VOID)
184 {
185 ULONG i;
186
187 RtlEnterCriticalSection (&HandleTableCS);
188 for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
189 {
190 if (DefaultHandleTable[i] != NULL)
191 {
192 NtClose (DefaultHandleTable[i]);
193 DefaultHandleTable[i] = NULL;
194 }
195 }
196 RtlLeaveCriticalSection (&HandleTableCS);
197 }
198
199
200 static NTSTATUS
201 OpenClassesRootKey (PHANDLE KeyHandle)
202 {
203 OBJECT_ATTRIBUTES Attributes;
204 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
205
206 TRACE("OpenClassesRootKey()\n");
207
208 InitializeObjectAttributes (&Attributes,
209 &KeyName,
210 OBJ_CASE_INSENSITIVE,
211 NULL,
212 NULL);
213 return NtOpenKey (KeyHandle,
214 MAXIMUM_ALLOWED,
215 &Attributes);
216 }
217
218
219 static NTSTATUS
220 OpenLocalMachineKey (PHANDLE KeyHandle)
221 {
222 OBJECT_ATTRIBUTES Attributes;
223 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
224 NTSTATUS Status;
225
226 TRACE("OpenLocalMachineKey()\n");
227
228 InitializeObjectAttributes (&Attributes,
229 &KeyName,
230 OBJ_CASE_INSENSITIVE,
231 NULL,
232 NULL);
233 Status = NtOpenKey (KeyHandle,
234 MAXIMUM_ALLOWED,
235 &Attributes);
236
237 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
238 return Status;
239 }
240
241
242 static NTSTATUS
243 OpenUsersKey (PHANDLE KeyHandle)
244 {
245 OBJECT_ATTRIBUTES Attributes;
246 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User");
247
248 TRACE("OpenUsersKey()\n");
249
250 InitializeObjectAttributes (&Attributes,
251 &KeyName,
252 OBJ_CASE_INSENSITIVE,
253 NULL,
254 NULL);
255 return NtOpenKey (KeyHandle,
256 MAXIMUM_ALLOWED,
257 &Attributes);
258 }
259
260
261 static NTSTATUS
262 OpenCurrentConfigKey (PHANDLE KeyHandle)
263 {
264 OBJECT_ATTRIBUTES Attributes;
265 UNICODE_STRING KeyName =
266 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
267
268 TRACE("OpenCurrentConfigKey()\n");
269
270 InitializeObjectAttributes (&Attributes,
271 &KeyName,
272 OBJ_CASE_INSENSITIVE,
273 NULL,
274 NULL);
275 return NtOpenKey (KeyHandle,
276 MAXIMUM_ALLOWED,
277 &Attributes);
278 }
279
280
281 /************************************************************************
282 * RegDisablePredefinedCacheEx
283 *
284 * @implemented
285 */
286 LONG STDCALL
287 RegDisablePredefinedCacheEx(VOID)
288 {
289 RtlEnterCriticalSection (&HandleTableCS);
290 DefaultHandlesDisabled = TRUE;
291 RtlLeaveCriticalSection (&HandleTableCS);
292 return ERROR_SUCCESS;
293 }
294
295
296 /************************************************************************
297 * RegCloseKey
298 *
299 * @implemented
300 */
301 LONG STDCALL
302 RegCloseKey (HKEY hKey)
303 {
304 NTSTATUS Status;
305
306 /* don't close null handle or a pseudo handle */
307 if ((!hKey) || (((ULONG)hKey & 0xF0000000) == 0x80000000))
308 {
309 return ERROR_INVALID_HANDLE;
310 }
311
312 Status = NtClose (hKey);
313 if (!NT_SUCCESS(Status))
314 {
315 return RtlNtStatusToDosError (Status);
316 }
317
318 return ERROR_SUCCESS;
319 }
320
321
322 /************************************************************************
323 * RegConnectRegistryA
324 *
325 * @unimplemented
326 */
327 LONG STDCALL
328 RegConnectRegistryA (LPCSTR lpMachineName,
329 HKEY hKey,
330 PHKEY phkResult)
331 {
332 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
333 return ERROR_CALL_NOT_IMPLEMENTED;
334 }
335
336
337 /************************************************************************
338 * RegCopyTreeW
339 *
340 * @unimplemented
341 */
342 LONG STDCALL
343 RegCopyTreeW(IN HKEY hKeySrc,
344 IN LPCWSTR lpSubKey OPTIONAL,
345 IN HKEY hKeyDest)
346 {
347 HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
348 NTSTATUS Status;
349
350 Status = MapDefaultKey(&KeyHandle,
351 hKeySrc);
352 if (!NT_SUCCESS(Status))
353 {
354 return RtlNtStatusToDosError(Status);
355 }
356
357 Status = MapDefaultKey(&DestKeyHandle,
358 hKeyDest);
359 if (!NT_SUCCESS(Status))
360 {
361 goto Cleanup2;
362 }
363
364 if (lpSubKey != NULL)
365 {
366 OBJECT_ATTRIBUTES ObjectAttributes;
367 UNICODE_STRING SubKeyName;
368
369 RtlInitUnicodeString(&SubKeyName,
370 (LPWSTR)lpSubKey);
371
372 InitializeObjectAttributes(&ObjectAttributes,
373 &SubKeyName,
374 OBJ_CASE_INSENSITIVE,
375 KeyHandle,
376 NULL);
377
378 Status = NtOpenKey(&SubKeyHandle,
379 KEY_READ,
380 &ObjectAttributes);
381 if (!NT_SUCCESS(Status))
382 {
383 goto Cleanup;
384 }
385
386 CurKey = SubKeyHandle;
387 }
388 else
389 CurKey = KeyHandle;
390
391 /* FIXME - copy all keys and values recursively */
392 Status = STATUS_NOT_IMPLEMENTED;
393
394 if (SubKeyHandle != NULL)
395 {
396 NtClose(SubKeyHandle);
397 }
398
399 Cleanup:
400 CloseDefaultKey(DestKeyHandle);
401 Cleanup2:
402 CloseDefaultKey(KeyHandle);
403
404 if (!NT_SUCCESS(Status))
405 {
406 return RtlNtStatusToDosError(Status);
407 }
408
409 return ERROR_SUCCESS;
410 }
411
412
413 /************************************************************************
414 * RegCopyTreeA
415 *
416 * @implemented
417 */
418 LONG STDCALL
419 RegCopyTreeA(IN HKEY hKeySrc,
420 IN LPCSTR lpSubKey OPTIONAL,
421 IN HKEY hKeyDest)
422 {
423 UNICODE_STRING SubKeyName;
424 LONG Ret;
425
426 if (lpSubKey != NULL)
427 {
428 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
429 (LPSTR)lpSubKey))
430 {
431 return ERROR_NOT_ENOUGH_MEMORY;
432 }
433 }
434 else
435 RtlInitUnicodeString(&SubKeyName,
436 NULL);
437
438 Ret = RegCopyTreeW(hKeySrc,
439 SubKeyName.Buffer,
440 hKeyDest);
441
442 RtlFreeUnicodeString(&SubKeyName);
443
444 return Ret;
445 }
446
447
448 /************************************************************************
449 * RegConnectRegistryW
450 *
451 * @unimplemented
452 */
453 LONG STDCALL
454 RegConnectRegistryW (LPCWSTR lpMachineName,
455 HKEY hKey,
456 PHKEY phkResult)
457 {
458 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
459 return ERROR_CALL_NOT_IMPLEMENTED;
460 }
461
462
463 /************************************************************************
464 * CreateNestedKey
465 *
466 * Create key and all necessary intermediate keys
467 */
468 static NTSTATUS
469 CreateNestedKey(PHKEY KeyHandle,
470 POBJECT_ATTRIBUTES ObjectAttributes,
471 PUNICODE_STRING ClassString,
472 DWORD dwOptions,
473 REGSAM samDesired,
474 DWORD *lpdwDisposition)
475 {
476 OBJECT_ATTRIBUTES LocalObjectAttributes;
477 UNICODE_STRING LocalKeyName;
478 ULONG Disposition;
479 NTSTATUS Status;
480 ULONG FullNameLength;
481 ULONG Length;
482 PWCHAR Ptr;
483 HANDLE LocalKeyHandle;
484
485 Status = NtCreateKey((PHANDLE) KeyHandle,
486 samDesired,
487 ObjectAttributes,
488 0,
489 ClassString,
490 dwOptions,
491 (PULONG)lpdwDisposition);
492 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
493 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
494 return Status;
495
496 /* Copy object attributes */
497 RtlCopyMemory (&LocalObjectAttributes,
498 ObjectAttributes,
499 sizeof(OBJECT_ATTRIBUTES));
500 RtlCreateUnicodeString (&LocalKeyName,
501 ObjectAttributes->ObjectName->Buffer);
502 LocalObjectAttributes.ObjectName = &LocalKeyName;
503 FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
504
505 /* Remove the last part of the key name and try to create the key again. */
506 while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
507 {
508 Ptr = wcsrchr (LocalKeyName.Buffer, '\\');
509 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
510 {
511 Status = STATUS_UNSUCCESSFUL;
512 break;
513 }
514 *Ptr = (WCHAR)0;
515 LocalKeyName.Length = wcslen (LocalKeyName.Buffer) * sizeof(WCHAR);
516
517 Status = NtCreateKey (&LocalKeyHandle,
518 KEY_ALL_ACCESS,
519 &LocalObjectAttributes,
520 0,
521 NULL,
522 0,
523 &Disposition);
524 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
525 }
526
527 if (!NT_SUCCESS(Status))
528 {
529 RtlFreeUnicodeString (&LocalKeyName);
530 return Status;
531 }
532
533 /* Add removed parts of the key name and create them too. */
534 Length = wcslen (LocalKeyName.Buffer);
535 while (TRUE)
536 {
537 NtClose (LocalKeyHandle);
538
539 LocalKeyName.Buffer[Length] = L'\\';
540 Length = wcslen (LocalKeyName.Buffer);
541 LocalKeyName.Length = Length * sizeof(WCHAR);
542
543 if (Length == FullNameLength)
544 {
545 Status = NtCreateKey((PHANDLE) KeyHandle,
546 samDesired,
547 ObjectAttributes,
548 0,
549 ClassString,
550 dwOptions,
551 (PULONG)lpdwDisposition);
552 break;
553 }
554 Status = NtCreateKey (&LocalKeyHandle,
555 KEY_CREATE_SUB_KEY,
556 &LocalObjectAttributes,
557 0,
558 NULL,
559 0,
560 &Disposition);
561 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
562 if (!NT_SUCCESS(Status))
563 break;
564 }
565
566 RtlFreeUnicodeString (&LocalKeyName);
567
568 return Status;
569 }
570
571
572 /************************************************************************
573 * RegCreateKeyExA
574 *
575 * @implemented
576 */
577 LONG STDCALL
578 RegCreateKeyExA (HKEY hKey,
579 LPCSTR lpSubKey,
580 DWORD Reserved,
581 LPSTR lpClass,
582 DWORD dwOptions,
583 REGSAM samDesired,
584 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
585 PHKEY phkResult,
586 LPDWORD lpdwDisposition)
587 {
588 UNICODE_STRING SubKeyString;
589 UNICODE_STRING ClassString;
590 OBJECT_ATTRIBUTES Attributes;
591 HANDLE ParentKey;
592 NTSTATUS Status;
593
594 TRACE("RegCreateKeyExA() called\n");
595
596 /* get the real parent key */
597 Status = MapDefaultKey (&ParentKey,
598 hKey);
599 if (!NT_SUCCESS(Status))
600 {
601 return RtlNtStatusToDosError (Status);
602 }
603 TRACE("ParentKey %x\n", (ULONG)ParentKey);
604
605 if (lpClass != NULL)
606 {
607 RtlCreateUnicodeStringFromAsciiz (&ClassString,
608 lpClass);
609 }
610
611 RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
612 (LPSTR)lpSubKey);
613 InitializeObjectAttributes (&Attributes,
614 &SubKeyString,
615 OBJ_CASE_INSENSITIVE,
616 (HANDLE)ParentKey,
617 (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
618 Status = CreateNestedKey(phkResult,
619 &Attributes,
620 (lpClass == NULL)? NULL : &ClassString,
621 dwOptions,
622 samDesired,
623 lpdwDisposition);
624 RtlFreeUnicodeString (&SubKeyString);
625 if (lpClass != NULL)
626 {
627 RtlFreeUnicodeString (&ClassString);
628 }
629
630 CloseDefaultKey(ParentKey);
631
632 TRACE("Status %x\n", Status);
633 if (!NT_SUCCESS(Status))
634 {
635 return RtlNtStatusToDosError (Status);
636 }
637
638 return ERROR_SUCCESS;
639 }
640
641
642 /************************************************************************
643 * RegCreateKeyExW
644 *
645 * @implemented
646 */
647 LONG STDCALL
648 RegCreateKeyExW (HKEY hKey,
649 LPCWSTR lpSubKey,
650 DWORD Reserved,
651 LPWSTR lpClass,
652 DWORD dwOptions,
653 REGSAM samDesired,
654 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
655 PHKEY phkResult,
656 LPDWORD lpdwDisposition)
657 {
658 UNICODE_STRING SubKeyString;
659 UNICODE_STRING ClassString;
660 OBJECT_ATTRIBUTES Attributes;
661 HANDLE ParentKey;
662 NTSTATUS Status;
663
664 TRACE("RegCreateKeyExW() called\n");
665
666 /* get the real parent key */
667 Status = MapDefaultKey (&ParentKey,
668 hKey);
669 if (!NT_SUCCESS(Status))
670 {
671 return RtlNtStatusToDosError(Status);
672 }
673 TRACE("ParentKey %x\n", (ULONG)ParentKey);
674
675 RtlInitUnicodeString (&ClassString,
676 lpClass);
677 RtlInitUnicodeString (&SubKeyString,
678 lpSubKey);
679 InitializeObjectAttributes (&Attributes,
680 &SubKeyString,
681 OBJ_CASE_INSENSITIVE,
682 (HANDLE)ParentKey,
683 (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
684 Status = CreateNestedKey(phkResult,
685 &Attributes,
686 (lpClass == NULL)? NULL : &ClassString,
687 dwOptions,
688 samDesired,
689 lpdwDisposition);
690
691 CloseDefaultKey(ParentKey);
692
693 TRACE("Status %x\n", Status);
694 if (!NT_SUCCESS(Status))
695 {
696 return RtlNtStatusToDosError (Status);
697 }
698
699 return ERROR_SUCCESS;
700 }
701
702
703 /************************************************************************
704 * RegCreateKeyA
705 *
706 * @implemented
707 */
708 LONG STDCALL
709 RegCreateKeyA (HKEY hKey,
710 LPCSTR lpSubKey,
711 PHKEY phkResult)
712 {
713 return RegCreateKeyExA (hKey,
714 lpSubKey,
715 0,
716 NULL,
717 0,
718 MAXIMUM_ALLOWED,
719 NULL,
720 phkResult,
721 NULL);
722 }
723
724
725 /************************************************************************
726 * RegCreateKeyW
727 *
728 * @implemented
729 */
730 LONG STDCALL
731 RegCreateKeyW (HKEY hKey,
732 LPCWSTR lpSubKey,
733 PHKEY phkResult)
734 {
735 return RegCreateKeyExW (hKey,
736 lpSubKey,
737 0,
738 NULL,
739 0,
740 MAXIMUM_ALLOWED,
741 NULL,
742 phkResult,
743 NULL);
744 }
745
746
747 /************************************************************************
748 * RegDeleteKeyA
749 *
750 * @implemented
751 */
752 LONG STDCALL
753 RegDeleteKeyA (HKEY hKey,
754 LPCSTR lpSubKey)
755 {
756 OBJECT_ATTRIBUTES ObjectAttributes;
757 UNICODE_STRING SubKeyName;
758 HANDLE ParentKey;
759 HANDLE TargetKey;
760 NTSTATUS Status;
761
762 Status = MapDefaultKey (&ParentKey,
763 hKey);
764 if (!NT_SUCCESS(Status))
765 {
766 return RtlNtStatusToDosError (Status);
767 }
768
769 RtlCreateUnicodeStringFromAsciiz (&SubKeyName,
770 (LPSTR)lpSubKey);
771 InitializeObjectAttributes(&ObjectAttributes,
772 &SubKeyName,
773 OBJ_CASE_INSENSITIVE,
774 ParentKey,
775 NULL);
776
777 Status = NtOpenKey (&TargetKey,
778 DELETE,
779 &ObjectAttributes);
780 RtlFreeUnicodeString (&SubKeyName);
781 if (!NT_SUCCESS(Status))
782 {
783 goto Cleanup;
784 }
785
786 Status = NtDeleteKey (TargetKey);
787 NtClose (TargetKey);
788
789 Cleanup:
790 CloseDefaultKey(ParentKey);
791
792 if (!NT_SUCCESS(Status))
793 {
794 return RtlNtStatusToDosError(Status);
795 }
796
797 return ERROR_SUCCESS;
798 }
799
800
801 /************************************************************************
802 * RegDeleteKeyW
803 *
804 * @implemented
805 */
806 LONG STDCALL
807 RegDeleteKeyW (HKEY hKey,
808 LPCWSTR lpSubKey)
809 {
810 OBJECT_ATTRIBUTES ObjectAttributes;
811 UNICODE_STRING SubKeyName;
812 HANDLE ParentKey;
813 HANDLE TargetKey;
814 NTSTATUS Status;
815
816 Status = MapDefaultKey (&ParentKey,
817 hKey);
818 if (!NT_SUCCESS(Status))
819 {
820 return RtlNtStatusToDosError (Status);
821 }
822
823 RtlInitUnicodeString (&SubKeyName,
824 (LPWSTR)lpSubKey);
825 InitializeObjectAttributes (&ObjectAttributes,
826 &SubKeyName,
827 OBJ_CASE_INSENSITIVE,
828 ParentKey,
829 NULL);
830 Status = NtOpenKey (&TargetKey,
831 DELETE,
832 &ObjectAttributes);
833 if (!NT_SUCCESS(Status))
834 {
835 goto Cleanup;
836 }
837
838 Status = NtDeleteKey (TargetKey);
839 NtClose (TargetKey);
840
841 Cleanup:
842 CloseDefaultKey(ParentKey);
843
844 if (!NT_SUCCESS(Status))
845 {
846 return RtlNtStatusToDosError (Status);
847 }
848
849 return ERROR_SUCCESS;
850 }
851
852
853 /************************************************************************
854 * RegDeleteKeyValueW
855 *
856 * @implemented
857 */
858 LONG STDCALL
859 RegDeleteKeyValueW(IN HKEY hKey,
860 IN LPCWSTR lpSubKey OPTIONAL,
861 IN LPCWSTR lpValueName OPTIONAL)
862 {
863 UNICODE_STRING ValueName;
864 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
865 NTSTATUS Status;
866
867 Status = MapDefaultKey(&KeyHandle,
868 hKey);
869 if (!NT_SUCCESS(Status))
870 {
871 return RtlNtStatusToDosError(Status);
872 }
873
874 if (lpSubKey != NULL)
875 {
876 OBJECT_ATTRIBUTES ObjectAttributes;
877 UNICODE_STRING SubKeyName;
878
879 RtlInitUnicodeString(&SubKeyName,
880 (LPWSTR)lpSubKey);
881
882 InitializeObjectAttributes(&ObjectAttributes,
883 &SubKeyName,
884 OBJ_CASE_INSENSITIVE,
885 KeyHandle,
886 NULL);
887
888 Status = NtOpenKey(&SubKeyHandle,
889 KEY_SET_VALUE,
890 &ObjectAttributes);
891 if (!NT_SUCCESS(Status))
892 {
893 goto Cleanup;
894 }
895
896 CurKey = SubKeyHandle;
897 }
898 else
899 CurKey = KeyHandle;
900
901 RtlInitUnicodeString(&ValueName,
902 (LPWSTR)lpValueName);
903
904 Status = NtDeleteValueKey(CurKey,
905 &ValueName);
906
907 if (SubKeyHandle != NULL)
908 {
909 NtClose(SubKeyHandle);
910 }
911
912 Cleanup:
913 CloseDefaultKey(KeyHandle);
914
915 if (!NT_SUCCESS(Status))
916 {
917 return RtlNtStatusToDosError(Status);
918 }
919
920 return ERROR_SUCCESS;
921 }
922
923
924 /************************************************************************
925 * RegDeleteKeyValueA
926 *
927 * @implemented
928 */
929 LONG STDCALL
930 RegDeleteKeyValueA(IN HKEY hKey,
931 IN LPCSTR lpSubKey OPTIONAL,
932 IN LPCSTR lpValueName OPTIONAL)
933 {
934 UNICODE_STRING SubKey, ValueName;
935 LONG Ret;
936
937 if (lpSubKey != NULL)
938 {
939 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey,
940 (LPSTR)lpSubKey))
941 {
942 return ERROR_NOT_ENOUGH_MEMORY;
943 }
944 }
945 else
946 RtlInitUnicodeString(&SubKey,
947 NULL);
948
949 if (lpValueName != NULL)
950 {
951 if (!RtlCreateUnicodeStringFromAsciiz(&ValueName,
952 (LPSTR)lpValueName))
953 {
954 RtlFreeUnicodeString(&SubKey);
955 return ERROR_NOT_ENOUGH_MEMORY;
956 }
957 }
958 else
959 RtlInitUnicodeString(&ValueName,
960 NULL);
961
962 Ret = RegDeleteKeyValueW(hKey,
963 SubKey.Buffer,
964 SubKey.Buffer);
965
966 RtlFreeUnicodeString(&SubKey);
967 RtlFreeUnicodeString(&ValueName);
968
969 return Ret;
970 }
971
972
973 static NTSTATUS
974 RegpDeleteTree(IN HKEY hKey)
975 {
976 typedef struct
977 {
978 LIST_ENTRY ListEntry;
979 HANDLE KeyHandle;
980 } REGP_DEL_KEYS, *PREG_DEL_KEYS;
981
982 LIST_ENTRY delQueueHead;
983 PREG_DEL_KEYS delKeys = NULL, newDelKeys;
984 HANDLE ProcessHeap;
985 ULONG BufferSize;
986 PKEY_BASIC_INFORMATION BasicInfo;
987 PREG_DEL_KEYS KeyDelRoot;
988 NTSTATUS Status = STATUS_SUCCESS;
989 NTSTATUS Status2 = STATUS_SUCCESS;
990
991 InitializeListHead(&delQueueHead);
992
993 ProcessHeap = RtlGetProcessHeap();
994
995 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
996 structure for the root key, we only do that for subkeys as we need to
997 allocate REGP_DEL_KEYS structures anyway! */
998 KeyDelRoot = RtlAllocateHeap(ProcessHeap,
999 0,
1000 sizeof(REGP_DEL_KEYS));
1001 if (KeyDelRoot != NULL)
1002 {
1003 KeyDelRoot->KeyHandle = hKey;
1004 InsertTailList(&delQueueHead,
1005 &KeyDelRoot->ListEntry);
1006
1007 do
1008 {
1009 delKeys = CONTAINING_RECORD(delQueueHead.Flink,
1010 REGP_DEL_KEYS,
1011 ListEntry);
1012
1013 BufferSize = 0;
1014 BasicInfo = NULL;
1015 newDelKeys = NULL;
1016
1017 ReadFirstSubKey:
1018 /* check if this key contains subkeys and delete them first by queuing
1019 them at the head of the list */
1020 Status2 = NtEnumerateKey(delKeys->KeyHandle,
1021 0,
1022 KeyBasicInformation,
1023 BasicInfo,
1024 BufferSize,
1025 &BufferSize);
1026
1027 if (NT_SUCCESS(Status2))
1028 {
1029 OBJECT_ATTRIBUTES ObjectAttributes;
1030 UNICODE_STRING SubKeyName;
1031
1032 ASSERT(newDelKeys != NULL);
1033 ASSERT(BasicInfo != NULL);
1034
1035 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1036 SubKeyName.Length = BasicInfo->NameLength;
1037 SubKeyName.MaximumLength = BasicInfo->NameLength;
1038 SubKeyName.Buffer = BasicInfo->Name;
1039
1040 InitializeObjectAttributes(&ObjectAttributes,
1041 &SubKeyName,
1042 OBJ_CASE_INSENSITIVE,
1043 delKeys->KeyHandle,
1044 NULL);
1045
1046 /* open the subkey */
1047 Status2 = NtOpenKey(&newDelKeys->KeyHandle,
1048 DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
1049 &ObjectAttributes);
1050 if (!NT_SUCCESS(Status2))
1051 {
1052 goto SubKeyFailure;
1053 }
1054
1055 /* enqueue this key to the head of the deletion queue */
1056 InsertHeadList(&delQueueHead,
1057 &newDelKeys->ListEntry);
1058
1059 /* try again from the head of the list */
1060 continue;
1061 }
1062 else
1063 {
1064 if (Status2 == STATUS_BUFFER_TOO_SMALL)
1065 {
1066 newDelKeys = RtlAllocateHeap(ProcessHeap,
1067 0,
1068 BufferSize + sizeof(REGP_DEL_KEYS));
1069 if (newDelKeys != NULL)
1070 {
1071 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1072
1073 /* try again */
1074 goto ReadFirstSubKey;
1075 }
1076 else
1077 {
1078 /* don't break, let's try to delete as many keys as possible */
1079 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1080 goto SubKeyFailureNoFree;
1081 }
1082 }
1083 else if (Status2 == STATUS_BUFFER_OVERFLOW)
1084 {
1085 PREG_DEL_KEYS newDelKeys2;
1086
1087 ASSERT(newDelKeys != NULL);
1088
1089 /* we need more memory to query the key name */
1090 newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
1091 0,
1092 newDelKeys,
1093 BufferSize + sizeof(REGP_DEL_KEYS));
1094 if (newDelKeys2 != NULL)
1095 {
1096 newDelKeys = newDelKeys2;
1097 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1098
1099 /* try again */
1100 goto ReadFirstSubKey;
1101 }
1102 else
1103 {
1104 /* don't break, let's try to delete as many keys as possible */
1105 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1106 }
1107 }
1108 SubKeyFailure:
1109 RtlFreeHeap(ProcessHeap,
1110 0,
1111 newDelKeys);
1112 SubKeyFailureNoFree:
1113 /* don't break, let's try to delete as many keys as possible */
1114 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
1115 {
1116 Status = Status2;
1117 }
1118 }
1119
1120 Status2 = NtDeleteKey(delKeys->KeyHandle);
1121
1122 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1123
1124 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
1125 {
1126 /* don't break, let's try to delete as many keys as possible */
1127 Status = Status2;
1128 }
1129
1130 /* remove the entry from the list */
1131 RemoveEntryList(&delKeys->ListEntry);
1132
1133 RtlFreeHeap(ProcessHeap,
1134 0,
1135 delKeys);
1136 } while (!IsListEmpty(&delQueueHead));
1137 }
1138 else
1139 Status = STATUS_INSUFFICIENT_RESOURCES;
1140
1141 return Status;
1142 }
1143
1144
1145 /************************************************************************
1146 * RegDeleteTreeW
1147 *
1148 * @implemented
1149 */
1150 LONG STDCALL
1151 RegDeleteTreeW(IN HKEY hKey,
1152 IN LPCWSTR lpSubKey OPTIONAL)
1153 {
1154 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1155 NTSTATUS Status;
1156
1157 Status = MapDefaultKey(&KeyHandle,
1158 hKey);
1159 if (!NT_SUCCESS(Status))
1160 {
1161 return RtlNtStatusToDosError(Status);
1162 }
1163
1164 if (lpSubKey != NULL)
1165 {
1166 OBJECT_ATTRIBUTES ObjectAttributes;
1167 UNICODE_STRING SubKeyName;
1168
1169 RtlInitUnicodeString(&SubKeyName,
1170 (LPWSTR)lpSubKey);
1171
1172 InitializeObjectAttributes(&ObjectAttributes,
1173 &SubKeyName,
1174 OBJ_CASE_INSENSITIVE,
1175 KeyHandle,
1176 NULL);
1177
1178 Status = NtOpenKey(&SubKeyHandle,
1179 DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
1180 &ObjectAttributes);
1181 if (!NT_SUCCESS(Status))
1182 {
1183 goto Cleanup;
1184 }
1185
1186 CurKey = SubKeyHandle;
1187 }
1188 else
1189 CurKey = KeyHandle;
1190
1191 Status = RegpDeleteTree(CurKey);
1192
1193 if (SubKeyHandle != NULL)
1194 {
1195 NtClose(SubKeyHandle);
1196 }
1197
1198 Cleanup:
1199 CloseDefaultKey(KeyHandle);
1200
1201 if (!NT_SUCCESS(Status))
1202 {
1203 return RtlNtStatusToDosError(Status);
1204 }
1205
1206 return ERROR_SUCCESS;
1207 }
1208
1209
1210 /************************************************************************
1211 * RegDeleteTreeA
1212 *
1213 * @implemented
1214 */
1215 LONG STDCALL
1216 RegDeleteTreeA(IN HKEY hKey,
1217 IN LPCSTR lpSubKey OPTIONAL)
1218 {
1219 UNICODE_STRING SubKeyName;
1220 LONG Ret;
1221
1222 if (lpSubKey != NULL)
1223 {
1224 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1225 (LPSTR)lpSubKey))
1226 {
1227 return ERROR_NOT_ENOUGH_MEMORY;
1228 }
1229 }
1230 else
1231 RtlInitUnicodeString(&SubKeyName,
1232 NULL);
1233
1234 Ret = RegDeleteTreeW(hKey,
1235 SubKeyName.Buffer);
1236
1237 RtlFreeUnicodeString(&SubKeyName);
1238
1239 return Ret;
1240 }
1241
1242
1243 /************************************************************************
1244 * RegSetKeyValueW
1245 *
1246 * @implemented
1247 */
1248 LONG STDCALL
1249 RegSetKeyValueW(IN HKEY hKey,
1250 IN LPCWSTR lpSubKey OPTIONAL,
1251 IN LPCWSTR lpValueName OPTIONAL,
1252 IN DWORD dwType,
1253 IN LPCVOID lpData OPTIONAL,
1254 IN DWORD cbData)
1255 {
1256 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1257 NTSTATUS Status;
1258 LONG Ret;
1259
1260 Status = MapDefaultKey(&KeyHandle,
1261 hKey);
1262 if (!NT_SUCCESS(Status))
1263 {
1264 return RtlNtStatusToDosError(Status);
1265 }
1266
1267 if (lpSubKey != NULL)
1268 {
1269 OBJECT_ATTRIBUTES ObjectAttributes;
1270 UNICODE_STRING SubKeyName;
1271
1272 RtlInitUnicodeString(&SubKeyName,
1273 (LPWSTR)lpSubKey);
1274
1275 InitializeObjectAttributes(&ObjectAttributes,
1276 &SubKeyName,
1277 OBJ_CASE_INSENSITIVE,
1278 KeyHandle,
1279 NULL);
1280
1281 Status = NtOpenKey(&SubKeyHandle,
1282 KEY_SET_VALUE,
1283 &ObjectAttributes);
1284 if (!NT_SUCCESS(Status))
1285 {
1286 Ret = RtlNtStatusToDosError(Status);
1287 goto Cleanup;
1288 }
1289
1290 CurKey = SubKeyHandle;
1291 }
1292 else
1293 CurKey = KeyHandle;
1294
1295 Ret = RegSetValueExW(CurKey,
1296 lpValueName,
1297 0,
1298 dwType,
1299 lpData,
1300 cbData);
1301
1302 if (SubKeyHandle != NULL)
1303 {
1304 NtClose(SubKeyHandle);
1305 }
1306
1307 Cleanup:
1308 CloseDefaultKey(KeyHandle);
1309
1310 return Ret;
1311 }
1312
1313
1314 /************************************************************************
1315 * RegSetKeyValueA
1316 *
1317 * @implemented
1318 */
1319 LONG STDCALL
1320 RegSetKeyValueA(IN HKEY hKey,
1321 IN LPCSTR lpSubKey OPTIONAL,
1322 IN LPCSTR lpValueName OPTIONAL,
1323 IN DWORD dwType,
1324 IN LPCVOID lpData OPTIONAL,
1325 IN DWORD cbData)
1326 {
1327 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1328 NTSTATUS Status;
1329 LONG Ret;
1330
1331 Status = MapDefaultKey(&KeyHandle,
1332 hKey);
1333 if (!NT_SUCCESS(Status))
1334 {
1335 return RtlNtStatusToDosError(Status);
1336 }
1337
1338 if (lpSubKey != NULL)
1339 {
1340 OBJECT_ATTRIBUTES ObjectAttributes;
1341 UNICODE_STRING SubKeyName;
1342
1343 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1344 (LPSTR)lpSubKey))
1345 {
1346 Ret = ERROR_NOT_ENOUGH_MEMORY;
1347 goto Cleanup;
1348 }
1349
1350 InitializeObjectAttributes(&ObjectAttributes,
1351 &SubKeyName,
1352 OBJ_CASE_INSENSITIVE,
1353 KeyHandle,
1354 NULL);
1355
1356 Status = NtOpenKey(&SubKeyHandle,
1357 KEY_SET_VALUE,
1358 &ObjectAttributes);
1359
1360 RtlFreeUnicodeString(&SubKeyName);
1361
1362 if (!NT_SUCCESS(Status))
1363 {
1364 Ret = RtlNtStatusToDosError(Status);
1365 goto Cleanup;
1366 }
1367
1368 CurKey = SubKeyHandle;
1369 }
1370 else
1371 CurKey = KeyHandle;
1372
1373 Ret = RegSetValueExA(CurKey,
1374 lpValueName,
1375 0,
1376 dwType,
1377 lpData,
1378 cbData);
1379
1380 if (SubKeyHandle != NULL)
1381 {
1382 NtClose(SubKeyHandle);
1383 }
1384
1385 Cleanup:
1386 CloseDefaultKey(KeyHandle);
1387
1388 return Ret;
1389 }
1390
1391
1392 /************************************************************************
1393 * RegDeleteValueA
1394 *
1395 * @implemented
1396 */
1397 LONG STDCALL
1398 RegDeleteValueA (HKEY hKey,
1399 LPCSTR lpValueName)
1400 {
1401 UNICODE_STRING ValueName;
1402 HANDLE KeyHandle;
1403 NTSTATUS Status;
1404
1405 Status = MapDefaultKey (&KeyHandle,
1406 hKey);
1407 if (!NT_SUCCESS(Status))
1408 {
1409 return RtlNtStatusToDosError (Status);
1410 }
1411
1412 RtlCreateUnicodeStringFromAsciiz (&ValueName,
1413 (LPSTR)lpValueName);
1414 Status = NtDeleteValueKey (KeyHandle,
1415 &ValueName);
1416 RtlFreeUnicodeString (&ValueName);
1417
1418 CloseDefaultKey(KeyHandle);
1419
1420 if (!NT_SUCCESS(Status))
1421 {
1422 return RtlNtStatusToDosError (Status);
1423 }
1424
1425 return ERROR_SUCCESS;
1426 }
1427
1428
1429 /************************************************************************
1430 * RegDeleteValueW
1431 *
1432 * @implemented
1433 */
1434 LONG STDCALL
1435 RegDeleteValueW (HKEY hKey,
1436 LPCWSTR lpValueName)
1437 {
1438 UNICODE_STRING ValueName;
1439 NTSTATUS Status;
1440 HANDLE KeyHandle;
1441
1442 Status = MapDefaultKey (&KeyHandle,
1443 hKey);
1444 if (!NT_SUCCESS(Status))
1445 {
1446 return RtlNtStatusToDosError (Status);
1447 }
1448
1449 RtlInitUnicodeString (&ValueName,
1450 (LPWSTR)lpValueName);
1451
1452 Status = NtDeleteValueKey (KeyHandle,
1453 &ValueName);
1454
1455 CloseDefaultKey(KeyHandle);
1456
1457 if (!NT_SUCCESS(Status))
1458 {
1459 return RtlNtStatusToDosError (Status);
1460 }
1461
1462 return ERROR_SUCCESS;
1463 }
1464
1465
1466 /************************************************************************
1467 * RegEnumKeyA
1468 *
1469 * @implemented
1470 */
1471 LONG STDCALL
1472 RegEnumKeyA (HKEY hKey,
1473 DWORD dwIndex,
1474 LPSTR lpName,
1475 DWORD cbName)
1476 {
1477 DWORD dwLength;
1478
1479 dwLength = cbName;
1480 return RegEnumKeyExA (hKey,
1481 dwIndex,
1482 lpName,
1483 &dwLength,
1484 NULL,
1485 NULL,
1486 NULL,
1487 NULL);
1488 }
1489
1490
1491 /************************************************************************
1492 * RegEnumKeyW
1493 *
1494 * @implemented
1495 */
1496 LONG STDCALL
1497 RegEnumKeyW (HKEY hKey,
1498 DWORD dwIndex,
1499 LPWSTR lpName,
1500 DWORD cbName)
1501 {
1502 DWORD dwLength;
1503
1504 dwLength = cbName;
1505 return RegEnumKeyExW (hKey,
1506 dwIndex,
1507 lpName,
1508 &dwLength,
1509 NULL,
1510 NULL,
1511 NULL,
1512 NULL);
1513 }
1514
1515
1516 /************************************************************************
1517 * RegEnumKeyExA
1518 *
1519 * @implemented
1520 */
1521 LONG STDCALL
1522 RegEnumKeyExA (HKEY hKey,
1523 DWORD dwIndex,
1524 LPSTR lpName,
1525 LPDWORD lpcbName,
1526 LPDWORD lpReserved,
1527 LPSTR lpClass,
1528 LPDWORD lpcbClass,
1529 PFILETIME lpftLastWriteTime)
1530 {
1531 union
1532 {
1533 KEY_NODE_INFORMATION Node;
1534 KEY_BASIC_INFORMATION Basic;
1535 } *KeyInfo;
1536
1537 UNICODE_STRING StringU;
1538 ANSI_STRING StringA;
1539 LONG ErrorCode = ERROR_SUCCESS;
1540 DWORD NameLength;
1541 DWORD ClassLength = 0;
1542 DWORD BufferSize;
1543 DWORD ResultSize;
1544 HANDLE KeyHandle;
1545 NTSTATUS Status;
1546
1547 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
1548 hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
1549
1550 if ((lpClass) && (!lpcbClass))
1551 {
1552 return ERROR_INVALID_PARAMETER;
1553 }
1554
1555 Status = MapDefaultKey(&KeyHandle, hKey);
1556 if (!NT_SUCCESS(Status))
1557 {
1558 return RtlNtStatusToDosError (Status);
1559 }
1560
1561 if (*lpcbName > 0)
1562 {
1563 NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
1564 }
1565 else
1566 {
1567 NameLength = 0;
1568 }
1569
1570 if (lpClass)
1571 {
1572 if (*lpcbClass > 0)
1573 {
1574 ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
1575 }
1576 else
1577 {
1578 ClassLength = 0;
1579 }
1580
1581 /* The class name should start at a dword boundary */
1582 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
1583 }
1584 else
1585 {
1586 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
1587 }
1588
1589 KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
1590 if (KeyInfo == NULL)
1591 {
1592 ErrorCode = ERROR_OUTOFMEMORY;
1593 goto Cleanup;
1594 }
1595
1596 Status = NtEnumerateKey (KeyHandle,
1597 (ULONG)dwIndex,
1598 lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
1599 KeyInfo,
1600 BufferSize,
1601 &ResultSize);
1602 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
1603 if (!NT_SUCCESS(Status))
1604 {
1605 ErrorCode = RtlNtStatusToDosError (Status);
1606 }
1607 else
1608 {
1609 if (lpClass == NULL)
1610 {
1611 if (KeyInfo->Basic.NameLength > NameLength)
1612 {
1613 ErrorCode = ERROR_BUFFER_OVERFLOW;
1614 }
1615 else
1616 {
1617 StringU.Buffer = KeyInfo->Basic.Name;
1618 StringU.Length = KeyInfo->Basic.NameLength;
1619 StringU.MaximumLength = KeyInfo->Basic.NameLength;
1620 }
1621 }
1622 else
1623 {
1624 if (KeyInfo->Node.NameLength > NameLength ||
1625 KeyInfo->Node.ClassLength > ClassLength)
1626 {
1627 ErrorCode = ERROR_BUFFER_OVERFLOW;
1628 }
1629 else
1630 {
1631 StringA.Buffer = lpClass;
1632 StringA.Length = 0;
1633 StringA.MaximumLength = *lpcbClass;
1634 StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
1635 StringU.Length = KeyInfo->Node.ClassLength;
1636 StringU.MaximumLength = KeyInfo->Node.ClassLength;
1637 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
1638 lpClass[StringA.Length] = 0;
1639 *lpcbClass = StringA.Length;
1640 StringU.Buffer = KeyInfo->Node.Name;
1641 StringU.Length = KeyInfo->Node.NameLength;
1642 StringU.MaximumLength = KeyInfo->Node.NameLength;
1643 }
1644 }
1645
1646 if (ErrorCode == ERROR_SUCCESS)
1647 {
1648 StringA.Buffer = lpName;
1649 StringA.Length = 0;
1650 StringA.MaximumLength = *lpcbName;
1651 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
1652 lpName[StringA.Length] = 0;
1653 *lpcbName = StringA.Length;
1654 if (lpftLastWriteTime != NULL)
1655 {
1656 if (lpClass == NULL)
1657 {
1658 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
1659 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
1660 }
1661 else
1662 {
1663 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
1664 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
1665 }
1666 }
1667 }
1668 }
1669
1670 TRACE("Key Namea0 Length %d\n", StringU.Length);
1671 TRACE("Key Namea1 Length %d\n", NameLength);
1672 TRACE("Key Namea Length %d\n", *lpcbName);
1673 TRACE("Key Namea %s\n", lpName);
1674
1675 RtlFreeHeap (ProcessHeap,
1676 0,
1677 KeyInfo);
1678
1679 Cleanup:
1680 CloseDefaultKey(KeyHandle);
1681
1682 return ErrorCode;
1683 }
1684
1685
1686 /************************************************************************
1687 * RegEnumKeyExW
1688 *
1689 * @implemented
1690 */
1691 LONG STDCALL
1692 RegEnumKeyExW (HKEY hKey,
1693 DWORD dwIndex,
1694 LPWSTR lpName,
1695 LPDWORD lpcbName,
1696 LPDWORD lpReserved,
1697 LPWSTR lpClass,
1698 LPDWORD lpcbClass,
1699 PFILETIME lpftLastWriteTime)
1700 {
1701 union
1702 {
1703 KEY_NODE_INFORMATION Node;
1704 KEY_BASIC_INFORMATION Basic;
1705 } *KeyInfo;
1706
1707 ULONG BufferSize;
1708 ULONG ResultSize;
1709 ULONG NameLength;
1710 ULONG ClassLength = 0;
1711 HANDLE KeyHandle;
1712 LONG ErrorCode = ERROR_SUCCESS;
1713 NTSTATUS Status;
1714
1715 Status = MapDefaultKey(&KeyHandle,
1716 hKey);
1717 if (!NT_SUCCESS(Status))
1718 {
1719 return RtlNtStatusToDosError (Status);
1720 }
1721
1722 if (*lpcbName > 0)
1723 {
1724 NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
1725 }
1726 else
1727 {
1728 NameLength = 0;
1729 }
1730
1731 if (lpClass)
1732 {
1733 if (*lpcbClass > 0)
1734 {
1735 ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
1736 }
1737 else
1738 {
1739 ClassLength = 0;
1740 }
1741
1742 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
1743 }
1744 else
1745 {
1746 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
1747 }
1748
1749 KeyInfo = RtlAllocateHeap (ProcessHeap,
1750 0,
1751 BufferSize);
1752 if (KeyInfo == NULL)
1753 {
1754 ErrorCode = ERROR_OUTOFMEMORY;
1755 goto Cleanup;
1756 }
1757
1758 Status = NtEnumerateKey (KeyHandle,
1759 (ULONG)dwIndex,
1760 lpClass ? KeyNodeInformation : KeyBasicInformation,
1761 KeyInfo,
1762 BufferSize,
1763 &ResultSize);
1764 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
1765 if (!NT_SUCCESS(Status))
1766 {
1767 ErrorCode = RtlNtStatusToDosError (Status);
1768 }
1769 else
1770 {
1771 if (lpClass == NULL)
1772 {
1773 if (KeyInfo->Basic.NameLength > NameLength)
1774 {
1775 ErrorCode = ERROR_BUFFER_OVERFLOW;
1776 }
1777 else
1778 {
1779 RtlCopyMemory (lpName,
1780 KeyInfo->Basic.Name,
1781 KeyInfo->Basic.NameLength);
1782 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
1783 lpName[*lpcbName] = 0;
1784 }
1785 }
1786 else
1787 {
1788 if (KeyInfo->Node.NameLength > NameLength ||
1789 KeyInfo->Node.ClassLength > ClassLength)
1790 {
1791 ErrorCode = ERROR_BUFFER_OVERFLOW;
1792 }
1793 else
1794 {
1795 RtlCopyMemory (lpName,
1796 KeyInfo->Node.Name,
1797 KeyInfo->Node.NameLength);
1798 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
1799 lpName[*lpcbName] = 0;
1800 RtlCopyMemory (lpClass,
1801 (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
1802 KeyInfo->Node.ClassLength);
1803 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
1804 lpClass[*lpcbClass] = 0;
1805 }
1806 }
1807
1808 if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
1809 {
1810 if (lpClass == NULL)
1811 {
1812 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
1813 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
1814 }
1815 else
1816 {
1817 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
1818 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
1819 }
1820 }
1821 }
1822
1823 RtlFreeHeap (ProcessHeap,
1824 0,
1825 KeyInfo);
1826
1827 Cleanup:
1828 CloseDefaultKey(KeyHandle);
1829
1830 return ErrorCode;
1831 }
1832
1833 /************************************************************************
1834 * RegEnumValueA
1835 *
1836 * @implemented
1837 */
1838 LONG STDCALL
1839 RegEnumValueA( HKEY hKey, DWORD index, LPSTR value, LPDWORD val_count,
1840 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1841 {
1842 HANDLE KeyHandle;
1843 NTSTATUS status;
1844 DWORD total_size;
1845 char buffer[256], *buf_ptr = buffer;
1846 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1847 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1848
1849 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1850 // hkey, index, value, val_count, reserved, type, data, count );
1851
1852 /* NT only checks count, not val_count */
1853 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1854 status = MapDefaultKey (&KeyHandle, hKey);
1855 if (!NT_SUCCESS(status))
1856 {
1857 return RtlNtStatusToDosError (status);
1858 }
1859
1860 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1861 if (data) total_size += *count;
1862 total_size = min( sizeof(buffer), total_size );
1863
1864 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
1865 buffer, total_size, &total_size );
1866 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1867
1868 /* we need to fetch the contents for a string type even if not requested,
1869 * because we need to compute the length of the ASCII string. */
1870 if (value || data || is_string(info->Type))
1871 {
1872 /* retry with a dynamically allocated buffer */
1873 while (status == STATUS_BUFFER_OVERFLOW)
1874 {
1875 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1876 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1877 {
1878 status = STATUS_INSUFFICIENT_RESOURCES;
1879 goto done;
1880 }
1881 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1882 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
1883 buf_ptr, total_size, &total_size );
1884 }
1885
1886 if (status) goto done;
1887
1888 if (is_string(info->Type))
1889 {
1890 DWORD len;
1891 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1892 total_size - info->DataOffset );
1893 if (data && len)
1894 {
1895 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1896 else
1897 {
1898 RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1899 total_size - info->DataOffset );
1900 /* if the type is REG_SZ and data is not 0-terminated
1901 * and there is enough space in the buffer NT appends a \0 */
1902 if (len < *count && data[len-1]) data[len] = 0;
1903 }
1904 }
1905 info->DataLength = len;
1906 }
1907 else if (data)
1908 {
1909 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1910 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1911 }
1912
1913 if (value && !status)
1914 {
1915 DWORD len;
1916
1917 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1918 if (len >= *val_count)
1919 {
1920 status = STATUS_BUFFER_OVERFLOW;
1921 if (*val_count)
1922 {
1923 len = *val_count - 1;
1924 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1925 value[len] = 0;
1926 }
1927 }
1928 else
1929 {
1930 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1931 value[len] = 0;
1932 *val_count = len;
1933 }
1934 }
1935 }
1936 else status = STATUS_SUCCESS;
1937
1938 if (type) *type = info->Type;
1939 if (count) *count = info->DataLength;
1940
1941 done:
1942 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1943 CloseDefaultKey(KeyHandle);
1944 return RtlNtStatusToDosError(status);
1945 }
1946
1947 /******************************************************************************
1948 * RegEnumValueW [ADVAPI32.@]
1949 * @implemented
1950 *
1951 * PARAMS
1952 * hkey [I] Handle to key to query
1953 * index [I] Index of value to query
1954 * value [O] Value string
1955 * val_count [I/O] Size of value buffer (in wchars)
1956 * reserved [I] Reserved
1957 * type [O] Type code
1958 * data [O] Value data
1959 * count [I/O] Size of data buffer (in bytes)
1960 *
1961 * RETURNS
1962 * Success: ERROR_SUCCESS
1963 * Failure: nonzero error code from Winerror.h
1964 */
1965 LONG STDCALL
1966 RegEnumValueW( HKEY hKey, DWORD index, LPWSTR value, PDWORD val_count,
1967 PDWORD reserved, PDWORD type, LPBYTE data, PDWORD count )
1968 {
1969 HANDLE KeyHandle;
1970 NTSTATUS status;
1971 DWORD total_size;
1972 char buffer[256], *buf_ptr = buffer;
1973 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1974 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1975
1976 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1977 // hkey, index, value, val_count, reserved, type, data, count );
1978
1979 /* NT only checks count, not val_count */
1980 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1981
1982 status = MapDefaultKey (&KeyHandle, hKey);
1983 if (!NT_SUCCESS(status))
1984 {
1985 return RtlNtStatusToDosError (status);
1986 }
1987
1988 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1989 if (data) total_size += *count;
1990 total_size = min( sizeof(buffer), total_size );
1991
1992 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
1993 buffer, total_size, &total_size );
1994 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1995
1996 if (value || data)
1997 {
1998 /* retry with a dynamically allocated buffer */
1999 while (status == STATUS_BUFFER_OVERFLOW)
2000 {
2001 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2002 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2003 {
2004 status = ERROR_NOT_ENOUGH_MEMORY;
2005 goto done;
2006 }
2007 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2008 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2009 buf_ptr, total_size, &total_size );
2010 }
2011
2012 if (status) goto done;
2013
2014 if (value)
2015 {
2016 if (info->NameLength/sizeof(WCHAR) >= *val_count)
2017 {
2018 status = STATUS_BUFFER_OVERFLOW;
2019 goto overflow;
2020 }
2021 memcpy( value, info->Name, info->NameLength );
2022 *val_count = info->NameLength / sizeof(WCHAR);
2023 value[*val_count] = 0;
2024 }
2025
2026 if (data)
2027 {
2028 if (total_size - info->DataOffset > *count)
2029 {
2030 status = STATUS_BUFFER_OVERFLOW;
2031 goto overflow;
2032 }
2033 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2034 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
2035 {
2036 /* if the type is REG_SZ and data is not 0-terminated
2037 * and there is enough space in the buffer NT appends a \0 */
2038 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
2039 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
2040 }
2041 }
2042 }
2043 else status = STATUS_SUCCESS;
2044
2045 overflow:
2046 if (type) *type = info->Type;
2047 if (count) *count = info->DataLength;
2048
2049 done:
2050 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2051 CloseDefaultKey(KeyHandle);
2052 return RtlNtStatusToDosError(status);
2053 }
2054
2055 /************************************************************************
2056 * RegFlushKey
2057 *
2058 * @implemented
2059 */
2060 LONG STDCALL
2061 RegFlushKey(HKEY hKey)
2062 {
2063 HANDLE KeyHandle;
2064 NTSTATUS Status;
2065
2066 if (hKey == HKEY_PERFORMANCE_DATA)
2067 {
2068 return ERROR_SUCCESS;
2069 }
2070
2071 Status = MapDefaultKey (&KeyHandle,
2072 hKey);
2073 if (!NT_SUCCESS(Status))
2074 {
2075 return RtlNtStatusToDosError (Status);
2076 }
2077
2078 Status = NtFlushKey (KeyHandle);
2079
2080 CloseDefaultKey(KeyHandle);
2081
2082 if (!NT_SUCCESS(Status))
2083 {
2084 return RtlNtStatusToDosError (Status);
2085 }
2086
2087 return ERROR_SUCCESS;
2088 }
2089
2090
2091 /************************************************************************
2092 * RegGetKeySecurity
2093 *
2094 * @implemented
2095 */
2096 LONG STDCALL
2097 RegGetKeySecurity(HKEY hKey,
2098 SECURITY_INFORMATION SecurityInformation,
2099 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2100 LPDWORD lpcbSecurityDescriptor)
2101 {
2102 HANDLE KeyHandle;
2103 NTSTATUS Status;
2104
2105 if (hKey == HKEY_PERFORMANCE_DATA)
2106 {
2107 return ERROR_INVALID_HANDLE;
2108 }
2109
2110 Status = MapDefaultKey(&KeyHandle,
2111 hKey);
2112 if (!NT_SUCCESS(Status))
2113 {
2114 TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
2115 return RtlNtStatusToDosError (Status);
2116 }
2117
2118 Status = NtQuerySecurityObject(KeyHandle,
2119 SecurityInformation,
2120 pSecurityDescriptor,
2121 *lpcbSecurityDescriptor,
2122 lpcbSecurityDescriptor);
2123
2124 CloseDefaultKey(KeyHandle);
2125
2126 if (!NT_SUCCESS(Status))
2127 {
2128 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
2129 return RtlNtStatusToDosError (Status);
2130 }
2131
2132 return ERROR_SUCCESS;
2133 }
2134
2135
2136 /************************************************************************
2137 * RegLoadKeyA
2138 *
2139 * @implemented
2140 */
2141 LONG STDCALL
2142 RegLoadKeyA (HKEY hKey,
2143 LPCSTR lpSubKey,
2144 LPCSTR lpFile)
2145 {
2146 UNICODE_STRING FileName;
2147 UNICODE_STRING KeyName;
2148 LONG ErrorCode;
2149
2150 RtlCreateUnicodeStringFromAsciiz (&KeyName,
2151 (LPSTR)lpSubKey);
2152 RtlCreateUnicodeStringFromAsciiz (&FileName,
2153 (LPSTR)lpFile);
2154
2155 ErrorCode = RegLoadKeyW (hKey,
2156 KeyName.Buffer,
2157 FileName.Buffer);
2158
2159 RtlFreeUnicodeString (&FileName);
2160 RtlFreeUnicodeString (&KeyName);
2161
2162 return ErrorCode;
2163 }
2164
2165
2166 /************************************************************************
2167 * RegLoadKeyW
2168 *
2169 * @implemented
2170 */
2171 LONG STDCALL
2172 RegLoadKeyW (HKEY hKey,
2173 LPCWSTR lpSubKey,
2174 LPCWSTR lpFile)
2175 {
2176 OBJECT_ATTRIBUTES FileObjectAttributes;
2177 OBJECT_ATTRIBUTES KeyObjectAttributes;
2178 UNICODE_STRING FileName;
2179 UNICODE_STRING KeyName;
2180 HANDLE KeyHandle;
2181 NTSTATUS Status;
2182 LONG ErrorCode = ERROR_SUCCESS;
2183
2184 if (hKey == HKEY_PERFORMANCE_DATA)
2185 {
2186 return ERROR_INVALID_HANDLE;
2187 }
2188
2189 Status = MapDefaultKey (&KeyHandle,
2190 hKey);
2191 if (!NT_SUCCESS(Status))
2192 {
2193 return RtlNtStatusToDosError (Status);
2194 }
2195
2196 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
2197 &FileName,
2198 NULL,
2199 NULL))
2200 {
2201 ErrorCode = ERROR_BAD_PATHNAME;
2202 goto Cleanup;
2203 }
2204
2205 InitializeObjectAttributes (&FileObjectAttributes,
2206 &FileName,
2207 OBJ_CASE_INSENSITIVE,
2208 NULL,
2209 NULL);
2210
2211 RtlInitUnicodeString (&KeyName,
2212 (LPWSTR)lpSubKey);
2213
2214 InitializeObjectAttributes (&KeyObjectAttributes,
2215 &KeyName,
2216 OBJ_CASE_INSENSITIVE,
2217 KeyHandle,
2218 NULL);
2219
2220 Status = NtLoadKey (&KeyObjectAttributes,
2221 &FileObjectAttributes);
2222
2223 RtlFreeUnicodeString (&FileName);
2224
2225 if (!NT_SUCCESS(Status))
2226 {
2227 ErrorCode = RtlNtStatusToDosError (Status);
2228 goto Cleanup;
2229 }
2230
2231 Cleanup:
2232 CloseDefaultKey(KeyHandle);
2233
2234 return ErrorCode;
2235 }
2236
2237
2238 /************************************************************************
2239 * RegNotifyChangeKeyValue
2240 *
2241 * @unimplemented
2242 */
2243 LONG STDCALL
2244 RegNotifyChangeKeyValue (HKEY hKey,
2245 BOOL bWatchSubtree,
2246 DWORD dwNotifyFilter,
2247 HANDLE hEvent,
2248 BOOL fAsynchronous)
2249 {
2250 IO_STATUS_BLOCK IoStatusBlock;
2251 HANDLE KeyHandle;
2252 NTSTATUS Status;
2253 LONG ErrorCode = ERROR_SUCCESS;
2254
2255 if (hKey == HKEY_PERFORMANCE_DATA)
2256 {
2257 return ERROR_INVALID_HANDLE;
2258 }
2259
2260 if (fAsynchronous == TRUE && hEvent == NULL)
2261 {
2262 return ERROR_INVALID_PARAMETER;
2263 }
2264
2265 Status = MapDefaultKey (&KeyHandle,
2266 hKey);
2267 if (!NT_SUCCESS(Status))
2268 {
2269 return RtlNtStatusToDosError (Status);
2270 }
2271
2272 /* FIXME: Remote key handles must fail */
2273
2274 Status = NtNotifyChangeKey (KeyHandle,
2275 hEvent,
2276 0,
2277 0,
2278 &IoStatusBlock,
2279 dwNotifyFilter,
2280 bWatchSubtree,
2281 0,
2282 0,
2283 fAsynchronous);
2284 if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
2285 {
2286 ErrorCode = RtlNtStatusToDosError (Status);
2287 }
2288
2289 CloseDefaultKey(KeyHandle);
2290
2291 return ErrorCode;
2292 }
2293
2294
2295 /************************************************************************
2296 * RegOpenCurrentUser
2297 *
2298 * @implemented
2299 */
2300 LONG STDCALL
2301 RegOpenCurrentUser (IN REGSAM samDesired,
2302 OUT PHKEY phkResult)
2303 {
2304 NTSTATUS Status;
2305
2306 Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
2307 (PHANDLE)phkResult);
2308 if (!NT_SUCCESS(Status))
2309 {
2310 /* NOTE - don't set the last error code! just return the error! */
2311 return RtlNtStatusToDosError(Status);
2312 }
2313
2314 return ERROR_SUCCESS;
2315 }
2316
2317
2318 /************************************************************************
2319 * RegOpenKeyA
2320 *
2321 * 20050503 Fireball - imported from WINE
2322 *
2323 * @implemented
2324 */
2325 LONG STDCALL
2326 RegOpenKeyA (HKEY hKey,
2327 LPCSTR lpSubKey,
2328 PHKEY phkResult)
2329 {
2330 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey, lpSubKey, phkResult);
2331
2332 if (!lpSubKey || !*lpSubKey)
2333 {
2334 *phkResult = hKey;
2335 return ERROR_SUCCESS;
2336 }
2337
2338 return RegOpenKeyExA( hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
2339 }
2340
2341
2342 /************************************************************************
2343 * RegOpenKeyW
2344 *
2345 * 19981101 Ariadne
2346 * 19990525 EA
2347 * 20050503 Fireball - imported from WINE
2348 *
2349 * @implemented
2350 */
2351 LONG STDCALL
2352 RegOpenKeyW (HKEY hKey,
2353 LPCWSTR lpSubKey,
2354 PHKEY phkResult)
2355 {
2356 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey, lpSubKey, phkResult);
2357
2358 if (!lpSubKey || !*lpSubKey)
2359 {
2360 *phkResult = hKey;
2361 return ERROR_SUCCESS;
2362 }
2363 return RegOpenKeyExW(hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
2364 }
2365
2366
2367 /************************************************************************
2368 * RegOpenKeyExA
2369 *
2370 * @implemented
2371 */
2372 LONG STDCALL
2373 RegOpenKeyExA (HKEY hKey,
2374 LPCSTR lpSubKey,
2375 DWORD ulOptions,
2376 REGSAM samDesired,
2377 PHKEY phkResult)
2378 {
2379 OBJECT_ATTRIBUTES ObjectAttributes;
2380 UNICODE_STRING SubKeyString;
2381 HANDLE KeyHandle;
2382 NTSTATUS Status;
2383 LONG ErrorCode = ERROR_SUCCESS;
2384
2385 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2386 hKey, lpSubKey, ulOptions, samDesired, phkResult);
2387
2388 Status = MapDefaultKey (&KeyHandle, hKey);
2389 if (!NT_SUCCESS(Status))
2390 {
2391 return RtlNtStatusToDosError (Status);
2392 }
2393
2394 RtlCreateUnicodeStringFromAsciiz (&SubKeyString, (LPSTR)lpSubKey);
2395 InitializeObjectAttributes (&ObjectAttributes,
2396 &SubKeyString,
2397 OBJ_CASE_INSENSITIVE,
2398 KeyHandle,
2399 NULL);
2400
2401 Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
2402 RtlFreeUnicodeString (&SubKeyString);
2403 if (!NT_SUCCESS(Status))
2404 {
2405 ErrorCode = RtlNtStatusToDosError (Status);
2406 }
2407
2408 CloseDefaultKey(KeyHandle);
2409
2410 return ErrorCode;
2411 }
2412
2413
2414 /************************************************************************
2415 * RegOpenKeyExW
2416 *
2417 * @implemented
2418 */
2419 LONG STDCALL
2420 RegOpenKeyExW (HKEY hKey,
2421 LPCWSTR lpSubKey,
2422 DWORD ulOptions,
2423 REGSAM samDesired,
2424 PHKEY phkResult)
2425 {
2426 OBJECT_ATTRIBUTES ObjectAttributes;
2427 UNICODE_STRING SubKeyString;
2428 HANDLE KeyHandle;
2429 NTSTATUS Status;
2430 LONG ErrorCode = ERROR_SUCCESS;
2431
2432 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2433 hKey, lpSubKey, ulOptions, samDesired, phkResult);
2434
2435 Status = MapDefaultKey (&KeyHandle, hKey);
2436 if (!NT_SUCCESS(Status))
2437 {
2438 return RtlNtStatusToDosError (Status);
2439 }
2440
2441 if (lpSubKey != NULL)
2442 RtlInitUnicodeString (&SubKeyString, (LPWSTR)lpSubKey);
2443 else
2444 RtlInitUnicodeString (&SubKeyString, (LPWSTR)L"");
2445
2446 InitializeObjectAttributes (&ObjectAttributes,
2447 &SubKeyString,
2448 OBJ_CASE_INSENSITIVE,
2449 KeyHandle,
2450 NULL);
2451
2452 Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
2453
2454 if (!NT_SUCCESS(Status))
2455 {
2456 ErrorCode = RtlNtStatusToDosError (Status);
2457 }
2458
2459 CloseDefaultKey(KeyHandle);
2460
2461 return ErrorCode;
2462 }
2463
2464
2465 /************************************************************************
2466 * RegOpenUserClassesRoot
2467 *
2468 * @implemented
2469 */
2470 LONG STDCALL
2471 RegOpenUserClassesRoot (IN HANDLE hToken,
2472 IN DWORD dwOptions,
2473 IN REGSAM samDesired,
2474 OUT PHKEY phkResult)
2475 {
2476 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
2477 const WCHAR UserClassesKeySuffix[] = L"_Classes";
2478 PTOKEN_USER TokenUserData;
2479 ULONG RequiredLength;
2480 UNICODE_STRING UserSidString, UserClassesKeyRoot;
2481 OBJECT_ATTRIBUTES ObjectAttributes;
2482 NTSTATUS Status;
2483
2484 /* check parameters */
2485 if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
2486 {
2487 return ERROR_INVALID_PARAMETER;
2488 }
2489
2490 /*
2491 * Get the user sid from the token
2492 */
2493
2494 ReadTokenSid:
2495 /* determine how much memory we need */
2496 Status = NtQueryInformationToken(hToken,
2497 TokenUser,
2498 NULL,
2499 0,
2500 &RequiredLength);
2501 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
2502 {
2503 /* NOTE - as opposed to all other registry functions windows does indeed
2504 change the last error code in case the caller supplied a invalid
2505 handle for example! */
2506 return RtlNtStatusToDosError (Status);
2507 }
2508
2509 TokenUserData = RtlAllocateHeap(ProcessHeap,
2510 0,
2511 RequiredLength);
2512 if (TokenUserData == NULL)
2513 {
2514 return ERROR_NOT_ENOUGH_MEMORY;
2515 }
2516
2517 /* attempt to read the information */
2518 Status = NtQueryInformationToken(hToken,
2519 TokenUser,
2520 TokenUserData,
2521 RequiredLength,
2522 &RequiredLength);
2523 if (!NT_SUCCESS(Status))
2524 {
2525 RtlFreeHeap(ProcessHeap,
2526 0,
2527 TokenUserData);
2528 if (Status == STATUS_BUFFER_TOO_SMALL)
2529 {
2530 /* the information appears to have changed?! try again */
2531 goto ReadTokenSid;
2532 }
2533
2534 /* NOTE - as opposed to all other registry functions windows does indeed
2535 change the last error code in case the caller supplied a invalid
2536 handle for example! */
2537 return RtlNtStatusToDosError (Status);
2538 }
2539
2540 /*
2541 * Build the absolute path for the user's registry in the form
2542 * "\Registry\User\<SID>_Classes"
2543 */
2544 Status = RtlConvertSidToUnicodeString(&UserSidString,
2545 TokenUserData->User.Sid,
2546 TRUE);
2547
2548 /* we don't need the user data anymore, free it */
2549 RtlFreeHeap(ProcessHeap,
2550 0,
2551 TokenUserData);
2552
2553 if (!NT_SUCCESS(Status))
2554 {
2555 return RtlNtStatusToDosError (Status);
2556 }
2557
2558 /* allocate enough memory for the entire key string */
2559 UserClassesKeyRoot.Length = 0;
2560 UserClassesKeyRoot.MaximumLength = UserSidString.Length +
2561 sizeof(UserClassesKeyPrefix) +
2562 sizeof(UserClassesKeySuffix);
2563 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
2564 0,
2565 UserClassesKeyRoot.MaximumLength);
2566 if (UserClassesKeyRoot.Buffer == NULL)
2567 {
2568 RtlFreeUnicodeString(&UserSidString);
2569 return RtlNtStatusToDosError (Status);
2570 }
2571
2572 /* build the string */
2573 RtlAppendUnicodeToString(&UserClassesKeyRoot,
2574 UserClassesKeyPrefix);
2575 RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
2576 &UserSidString);
2577 RtlAppendUnicodeToString(&UserClassesKeyRoot,
2578 UserClassesKeySuffix);
2579
2580 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
2581
2582 /*
2583 * Open the key
2584 */
2585
2586 InitializeObjectAttributes (&ObjectAttributes,
2587 &UserClassesKeyRoot,
2588 OBJ_CASE_INSENSITIVE,
2589 NULL,
2590 NULL);
2591
2592 Status = NtOpenKey((PHANDLE)phkResult,
2593 samDesired,
2594 &ObjectAttributes);
2595
2596 RtlFreeUnicodeString(&UserSidString);
2597 RtlFreeUnicodeString(&UserClassesKeyRoot);
2598
2599 if (!NT_SUCCESS(Status))
2600 {
2601 return RtlNtStatusToDosError (Status);
2602 }
2603
2604 return ERROR_SUCCESS;
2605 }
2606
2607
2608 /************************************************************************
2609 * RegQueryInfoKeyA
2610 *
2611 * @implemented
2612 */
2613 LONG STDCALL
2614 RegQueryInfoKeyA (HKEY hKey,
2615 LPSTR lpClass,
2616 LPDWORD lpcbClass,
2617 LPDWORD lpReserved,
2618 LPDWORD lpcSubKeys,
2619 LPDWORD lpcbMaxSubKeyLen,
2620 LPDWORD lpcbMaxClassLen,
2621 LPDWORD lpcValues,
2622 LPDWORD lpcbMaxValueNameLen,
2623 LPDWORD lpcbMaxValueLen,
2624 LPDWORD lpcbSecurityDescriptor,
2625 PFILETIME lpftLastWriteTime)
2626 {
2627 WCHAR ClassName[MAX_PATH];
2628 UNICODE_STRING UnicodeString;
2629 ANSI_STRING AnsiString;
2630 LONG ErrorCode;
2631
2632 RtlInitUnicodeString (&UnicodeString,
2633 NULL);
2634 if (lpClass != NULL)
2635 {
2636 UnicodeString.Buffer = &ClassName[0];
2637 UnicodeString.MaximumLength = sizeof(ClassName);
2638 AnsiString.MaximumLength = *lpcbClass;
2639 }
2640
2641 ErrorCode = RegQueryInfoKeyW (hKey,
2642 UnicodeString.Buffer,
2643 lpcbClass,
2644 lpReserved,
2645 lpcSubKeys,
2646 lpcbMaxSubKeyLen,
2647 lpcbMaxClassLen,
2648 lpcValues,
2649 lpcbMaxValueNameLen,
2650 lpcbMaxValueLen,
2651 lpcbSecurityDescriptor,
2652 lpftLastWriteTime);
2653 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
2654 {
2655 AnsiString.Buffer = lpClass;
2656 AnsiString.Length = 0;
2657 UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
2658 RtlUnicodeStringToAnsiString (&AnsiString,
2659 &UnicodeString,
2660 FALSE);
2661 *lpcbClass = AnsiString.Length;
2662 lpClass[AnsiString.Length] = 0;
2663 }
2664
2665 return ErrorCode;
2666 }
2667
2668
2669 /************************************************************************
2670 * RegQueryInfoKeyW
2671 *
2672 * @implemented
2673 */
2674 LONG STDCALL
2675 RegQueryInfoKeyW (HKEY hKey,
2676 LPWSTR lpClass,
2677 LPDWORD lpcbClass,
2678 LPDWORD lpReserved,
2679 LPDWORD lpcSubKeys,
2680 LPDWORD lpcbMaxSubKeyLen,
2681 LPDWORD lpcbMaxClassLen,
2682 LPDWORD lpcValues,
2683 LPDWORD lpcbMaxValueNameLen,
2684 LPDWORD lpcbMaxValueLen,
2685 LPDWORD lpcbSecurityDescriptor,
2686 PFILETIME lpftLastWriteTime)
2687 {
2688 KEY_FULL_INFORMATION FullInfoBuffer;
2689 PKEY_FULL_INFORMATION FullInfo;
2690 ULONG FullInfoSize;
2691 ULONG ClassLength = 0;
2692 HANDLE KeyHandle;
2693 NTSTATUS Status;
2694 ULONG Length;
2695 LONG ErrorCode = ERROR_SUCCESS;
2696
2697 if ((lpClass) && (!lpcbClass))
2698 {
2699 return ERROR_INVALID_PARAMETER;
2700 }
2701
2702 Status = MapDefaultKey (&KeyHandle,
2703 hKey);
2704 if (!NT_SUCCESS(Status))
2705 {
2706 return RtlNtStatusToDosError (Status);
2707 }
2708
2709 if (lpClass != NULL)
2710 {
2711 if (*lpcbClass > 0)
2712 {
2713 ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2714 }
2715 else
2716 {
2717 ClassLength = 0;
2718 }
2719
2720 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
2721 FullInfo = RtlAllocateHeap (ProcessHeap,
2722 0,
2723 FullInfoSize);
2724 if (FullInfo == NULL)
2725 {
2726 ErrorCode = ERROR_OUTOFMEMORY;
2727 goto Cleanup;
2728 }
2729
2730 FullInfo->ClassLength = ClassLength;
2731 }
2732 else
2733 {
2734 FullInfoSize = sizeof(KEY_FULL_INFORMATION);
2735 FullInfo = &FullInfoBuffer;
2736 FullInfo->ClassLength = 0;
2737 }
2738 FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
2739
2740 Status = NtQueryKey (KeyHandle,
2741 KeyFullInformation,
2742 FullInfo,
2743 FullInfoSize,
2744 &Length);
2745 TRACE("NtQueryKey() returned status 0x%X\n", Status);
2746 if (!NT_SUCCESS(Status))
2747 {
2748 if (lpClass != NULL)
2749 {
2750 RtlFreeHeap (ProcessHeap,
2751 0,
2752 FullInfo);
2753 }
2754
2755 ErrorCode = RtlNtStatusToDosError (Status);
2756 goto Cleanup;
2757 }
2758
2759 TRACE("SubKeys %d\n", FullInfo->SubKeys);
2760 if (lpcSubKeys != NULL)
2761 {
2762 *lpcSubKeys = FullInfo->SubKeys;
2763 }
2764
2765 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
2766 if (lpcbMaxSubKeyLen != NULL)
2767 {
2768 *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
2769 }
2770
2771 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
2772 if (lpcbMaxClassLen != NULL)
2773 {
2774 *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
2775 }
2776
2777 TRACE("Values %lu\n", FullInfo->Values);
2778 if (lpcValues != NULL)
2779 {
2780 *lpcValues = FullInfo->Values;
2781 }
2782
2783 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
2784 if (lpcbMaxValueNameLen != NULL)
2785 {
2786 *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
2787 }
2788
2789 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
2790 if (lpcbMaxValueLen != NULL)
2791 {
2792 *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
2793 }
2794
2795 if (lpcbSecurityDescriptor != NULL)
2796 {
2797 Status = NtQuerySecurityObject(KeyHandle,
2798 OWNER_SECURITY_INFORMATION |
2799 GROUP_SECURITY_INFORMATION |
2800 DACL_SECURITY_INFORMATION,
2801 NULL,
2802 0,
2803 lpcbSecurityDescriptor);
2804 if (!NT_SUCCESS(Status))
2805 {
2806 if (lpClass != NULL)
2807 {
2808 RtlFreeHeap(ProcessHeap,
2809 0,
2810 FullInfo);
2811 }
2812
2813 ErrorCode = RtlNtStatusToDosError (Status);
2814 goto Cleanup;
2815 }
2816 }
2817
2818 if (lpftLastWriteTime != NULL)
2819 {
2820 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
2821 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
2822 }
2823
2824 if (lpClass != NULL)
2825 {
2826 if (FullInfo->ClassLength > ClassLength)
2827 {
2828 ErrorCode = ERROR_BUFFER_OVERFLOW;
2829 }
2830 else
2831 {
2832 RtlCopyMemory (lpClass,
2833 FullInfo->Class,
2834 FullInfo->ClassLength);
2835 *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
2836 lpClass[*lpcbClass] = 0;
2837 }
2838
2839 RtlFreeHeap (ProcessHeap,
2840 0,
2841 FullInfo);
2842 }
2843
2844 Cleanup:
2845 CloseDefaultKey(KeyHandle);
2846
2847 return ErrorCode;
2848 }
2849
2850
2851 /************************************************************************
2852 * RegQueryMultipleValuesA
2853 *
2854 * @implemented
2855 */
2856 LONG STDCALL
2857 RegQueryMultipleValuesA (HKEY hKey,
2858 PVALENTA val_list,
2859 DWORD num_vals,
2860 LPSTR lpValueBuf,
2861 LPDWORD ldwTotsize)
2862 {
2863 ULONG i;
2864 DWORD maxBytes = *ldwTotsize;
2865 LPSTR bufptr = (LPSTR)lpValueBuf;
2866 LONG ErrorCode;
2867
2868 if (maxBytes >= (1024*1024))
2869 return ERROR_TRANSFER_TOO_LONG;
2870
2871 *ldwTotsize = 0;
2872
2873 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
2874 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
2875
2876 for (i = 0; i < num_vals; i++)
2877 {
2878 val_list[i].ve_valuelen = 0;
2879 ErrorCode = RegQueryValueExA (hKey,
2880 val_list[i].ve_valuename,
2881 NULL,
2882 NULL,
2883 NULL,
2884 &val_list[i].ve_valuelen);
2885 if (ErrorCode != ERROR_SUCCESS)
2886 {
2887 return ErrorCode;
2888 }
2889
2890 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
2891 {
2892 ErrorCode = RegQueryValueExA (hKey,
2893 val_list[i].ve_valuename,
2894 NULL,
2895 &val_list[i].ve_type,
2896 (LPBYTE)bufptr,
2897 &val_list[i].ve_valuelen);
2898 if (ErrorCode != ERROR_SUCCESS)
2899 {
2900 return ErrorCode;
2901 }
2902
2903 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
2904
2905 bufptr += val_list[i].ve_valuelen;
2906 }
2907
2908 *ldwTotsize += val_list[i].ve_valuelen;
2909 }
2910
2911 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
2912 }
2913
2914
2915 /************************************************************************
2916 * RegQueryMultipleValuesW
2917 *
2918 * @implemented
2919 */
2920 LONG STDCALL
2921 RegQueryMultipleValuesW (HKEY hKey,
2922 PVALENTW val_list,
2923 DWORD num_vals,
2924 LPWSTR lpValueBuf,
2925 LPDWORD ldwTotsize)
2926 {
2927 ULONG i;
2928 DWORD maxBytes = *ldwTotsize;
2929 LPSTR bufptr = (LPSTR)lpValueBuf;
2930 LONG ErrorCode;
2931
2932 if (maxBytes >= (1024*1024))
2933 return ERROR_TRANSFER_TOO_LONG;
2934
2935 *ldwTotsize = 0;
2936
2937 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
2938 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
2939
2940 for (i = 0; i < num_vals; i++)
2941 {
2942 val_list[i].ve_valuelen = 0;
2943 ErrorCode = RegQueryValueExW (hKey,
2944 val_list[i].ve_valuename,
2945 NULL,
2946 NULL,
2947 NULL,
2948 &val_list[i].ve_valuelen);
2949 if (ErrorCode != ERROR_SUCCESS)
2950 {
2951 return ErrorCode;
2952 }
2953
2954 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
2955 {
2956 ErrorCode = RegQueryValueExW (hKey,
2957 val_list[i].ve_valuename,
2958 NULL,
2959 &val_list[i].ve_type,
2960 (LPBYTE)bufptr,
2961 &val_list[i].ve_valuelen);
2962 if (ErrorCode != ERROR_SUCCESS)
2963 {
2964 return ErrorCode;
2965 }
2966
2967 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
2968
2969 bufptr += val_list[i].ve_valuelen;
2970 }
2971
2972 *ldwTotsize += val_list[i].ve_valuelen;
2973 }
2974
2975 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
2976 }
2977
2978
2979 /************************************************************************
2980 * RegQueryValueExW
2981 *
2982 * @implemented
2983 */
2984 LONG STDCALL
2985 RegQueryValueExW (HKEY hKey,
2986 LPCWSTR lpValueName,
2987 LPDWORD lpReserved,
2988 LPDWORD lpType,
2989 LPBYTE lpData,
2990 LPDWORD lpcbData)
2991 {
2992 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
2993 UNICODE_STRING ValueName;
2994 NTSTATUS Status;
2995 ULONG BufferSize;
2996 ULONG ResultSize;
2997 HANDLE KeyHandle;
2998 LONG ErrorCode = ERROR_SUCCESS;
2999 ULONG MaxCopy = lpcbData != NULL && lpData != NULL ? *lpcbData : 0;
3000
3001 TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
3002 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
3003
3004 Status = MapDefaultKey (&KeyHandle,
3005 hKey);
3006 if (!NT_SUCCESS(Status))
3007 {
3008 return RtlNtStatusToDosError (Status);
3009 }
3010
3011 if (lpData != NULL && lpcbData == NULL)
3012 {
3013 ErrorCode = ERROR_INVALID_PARAMETER;
3014 goto Cleanup;
3015 }
3016
3017 RtlInitUnicodeString (&ValueName,
3018 lpValueName);
3019 BufferSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MaxCopy;
3020 ValueInfo = RtlAllocateHeap (ProcessHeap,
3021 0,
3022 BufferSize);
3023 if (ValueInfo == NULL)
3024 {
3025 ErrorCode = ERROR_OUTOFMEMORY;
3026 goto Cleanup;
3027 }
3028
3029 Status = NtQueryValueKey (KeyHandle,
3030 &ValueName,
3031 KeyValuePartialInformation,
3032 ValueInfo,
3033 BufferSize,
3034 &ResultSize);
3035 TRACE("Status 0x%X\n", Status);
3036 if (Status == STATUS_BUFFER_OVERFLOW)
3037 {
3038 /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
3039 MaxCopy = 0;
3040 ErrorCode = lpData ? ERROR_MORE_DATA : ERROR_SUCCESS;
3041 }
3042 else if (!NT_SUCCESS(Status))
3043 {
3044 ErrorCode = RtlNtStatusToDosError (Status);
3045 MaxCopy = 0;
3046 if (lpcbData != NULL)
3047 {
3048 ResultSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + *lpcbData;
3049 }
3050 }
3051
3052 if (lpType != NULL)
3053 {
3054 *lpType = ValueInfo->Type;
3055 }
3056
3057 if (NT_SUCCESS(Status) && lpData != NULL)
3058 {
3059 RtlMoveMemory (lpData,
3060 ValueInfo->Data,
3061 min(ValueInfo->DataLength, MaxCopy));
3062 }
3063
3064 if ((ValueInfo->Type == REG_SZ) ||
3065 (ValueInfo->Type == REG_MULTI_SZ) ||
3066 (ValueInfo->Type == REG_EXPAND_SZ))
3067 {
3068 if (lpData != NULL && MaxCopy > ValueInfo->DataLength)
3069 {
3070 ((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
3071 }
3072
3073 if (lpcbData != NULL)
3074 {
3075 *lpcbData = (ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]));
3076 TRACE("(string) Returning Size: %lu\n", *lpcbData);
3077 }
3078 }
3079 else
3080 {
3081 if (lpcbData != NULL)
3082 {
3083 *lpcbData = ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
3084 TRACE("(other) Returning Size: %lu\n", *lpcbData);
3085 }
3086 }
3087
3088 TRACE("Type %d Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
3089
3090 RtlFreeHeap (ProcessHeap,
3091 0,
3092 ValueInfo);
3093
3094 Cleanup:
3095 CloseDefaultKey(KeyHandle);
3096
3097 return ErrorCode;
3098 }
3099
3100
3101 /************************************************************************
3102 * RegQueryValueExA
3103 *
3104 * @implemented
3105 */
3106 LONG STDCALL
3107 RegQueryValueExA (HKEY hKey,
3108 LPCSTR lpValueName,
3109 LPDWORD lpReserved,
3110 LPDWORD lpType,
3111 LPBYTE lpData,
3112 LPDWORD lpcbData)
3113 {
3114 UNICODE_STRING ValueName;
3115 UNICODE_STRING ValueData;
3116 ANSI_STRING AnsiString;
3117 LONG ErrorCode;
3118 DWORD Length;
3119 DWORD Type;
3120
3121 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3122 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
3123
3124 if (lpData != NULL && lpcbData == NULL)
3125 {
3126 return ERROR_INVALID_PARAMETER;
3127 }
3128
3129 if (lpData)
3130 {
3131 ValueData.Length = 0;
3132 ValueData.MaximumLength = (*lpcbData + 1) * sizeof(WCHAR);
3133 ValueData.Buffer = RtlAllocateHeap (ProcessHeap,
3134 0,
3135 ValueData.MaximumLength);
3136 if (!ValueData.Buffer)
3137 {
3138 return ERROR_OUTOFMEMORY;
3139 }
3140 }
3141 else
3142 {
3143 ValueData.Buffer = NULL;
3144 ValueData.Length = 0;
3145 ValueData.MaximumLength = 0;
3146 }
3147
3148 RtlCreateUnicodeStringFromAsciiz (&ValueName,
3149 (LPSTR)lpValueName);
3150
3151 Length = (lpcbData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
3152 ErrorCode = RegQueryValueExW (hKey,
3153 ValueName.Buffer,
3154 lpReserved,
3155 &Type,
3156 (lpData == NULL) ? NULL : (LPBYTE)ValueData.Buffer,
3157 &Length);
3158 TRACE("ErrorCode %lu\n", ErrorCode);
3159 RtlFreeUnicodeString(&ValueName);
3160
3161 if (ErrorCode == ERROR_SUCCESS ||
3162 ErrorCode == ERROR_MORE_DATA)
3163 {
3164 if (lpType != NULL)
3165 {
3166 *lpType = Type;
3167 }
3168
3169 if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ))
3170 {
3171 if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
3172 {
3173 RtlInitAnsiString(&AnsiString, NULL);
3174 AnsiString.Buffer = (LPSTR)lpData;
3175 AnsiString.MaximumLength = *lpcbData;
3176 ValueData.Length = Length;
3177 ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
3178 RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
3179 }
3180 Length = Length / sizeof(WCHAR);
3181 }
3182 else if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
3183 {
3184 if (*lpcbData < Length)
3185 {
3186 ErrorCode = ERROR_MORE_DATA;
3187 }
3188 else
3189 {
3190 RtlMoveMemory(lpData, ValueData.Buffer, Length);
3191 }
3192 }
3193
3194 if (lpcbData != NULL)
3195 {
3196 *lpcbData = Length;
3197 }
3198 }
3199
3200 if (ValueData.Buffer != NULL)
3201 {
3202 RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
3203 }
3204
3205 return ErrorCode;
3206 }
3207
3208
3209 /************************************************************************
3210 * RegQueryValueA
3211 *
3212 * @implemented
3213 */
3214 LONG STDCALL
3215 RegQueryValueA (HKEY hKey,
3216 LPCSTR lpSubKey,
3217 LPSTR lpValue,
3218 PLONG lpcbValue)
3219 {
3220 WCHAR SubKeyNameBuffer[MAX_PATH+1];
3221 UNICODE_STRING SubKeyName;
3222 UNICODE_STRING Value;
3223 ANSI_STRING AnsiString;
3224 LONG ValueSize;
3225 LONG ErrorCode;
3226
3227 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
3228 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
3229
3230 if (lpValue != NULL &&
3231 lpcbValue == NULL)
3232 {
3233 return ERROR_INVALID_PARAMETER;
3234 }
3235
3236 RtlInitUnicodeString (&SubKeyName,
3237 NULL);
3238 RtlInitUnicodeString (&Value,
3239 NULL);
3240 if (lpSubKey != NULL &&
3241 strlen(lpSubKey) != 0)
3242 {
3243 RtlInitAnsiString (&AnsiString,
3244 (LPSTR)lpSubKey);
3245 SubKeyName.Buffer = &SubKeyNameBuffer[0];
3246 SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
3247 RtlAnsiStringToUnicodeString (&SubKeyName,
3248 &AnsiString,
3249 FALSE);
3250 }
3251
3252 if (lpValue != NULL)
3253 {
3254 ValueSize = *lpcbValue * sizeof(WCHAR);
3255 Value.MaximumLength = ValueSize;
3256 Value.Buffer = RtlAllocateHeap (ProcessHeap,
3257 0,
3258 ValueSize);
3259 if (Value.Buffer == NULL)
3260 {
3261 return ERROR_OUTOFMEMORY;
3262 }
3263 }
3264 else
3265 {
3266 ValueSize = 0;
3267 }
3268
3269 ErrorCode = RegQueryValueW (hKey,
3270 (LPCWSTR)SubKeyName.Buffer,
3271 Value.Buffer,
3272 &ValueSize);
3273 if (ErrorCode == ERROR_SUCCESS)
3274 {
3275 Value.Length = ValueSize;
3276 RtlInitAnsiString (&AnsiString,
3277 NULL);
3278 AnsiString.Buffer = lpValue;
3279 AnsiString.MaximumLength = *lpcbValue;
3280 RtlUnicodeStringToAnsiString (&AnsiString,
3281 &Value,
3282 FALSE);
3283 }
3284
3285 *lpcbValue = ValueSize;
3286 if (Value.Buffer != NULL)
3287 {
3288 RtlFreeHeap (ProcessHeap,
3289 0,
3290 Value.Buffer);
3291 }
3292
3293 return ErrorCode;
3294 }
3295
3296
3297 /************************************************************************
3298 * RegQueryValueW
3299 *
3300 * @implemented
3301 */
3302 LONG STDCALL
3303 RegQueryValueW (HKEY hKey,
3304 LPCWSTR lpSubKey,
3305 LPWSTR lpValue,
3306 PLONG lpcbValue)
3307 {
3308 OBJECT_ATTRIBUTES ObjectAttributes;
3309 UNICODE_STRING SubKeyString;
3310 HANDLE KeyHandle;
3311 HANDLE RealKey;
3312 LONG ErrorCode;
3313 BOOL CloseRealKey;
3314 NTSTATUS Status;
3315
3316 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
3317 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
3318
3319 Status = MapDefaultKey (&KeyHandle,
3320 hKey);
3321 if (!NT_SUCCESS(Status))
3322 {
3323 return RtlNtStatusToDosError (Status);
3324 }
3325
3326 if (lpSubKey != NULL &&
3327 wcslen(lpSubKey) != 0)
3328 {
3329 RtlInitUnicodeString (&SubKeyString,
3330 (LPWSTR)lpSubKey);
3331 InitializeObjectAttributes (&ObjectAttributes,
3332 &SubKeyString,
3333 OBJ_CASE_INSENSITIVE,
3334 KeyHandle,
3335 NULL);
3336 Status = NtOpenKey (&RealKey,
3337 KEY_QUERY_VALUE,
3338 &ObjectAttributes);
3339 if (!NT_SUCCESS(Status))
3340 {
3341 ErrorCode = RtlNtStatusToDosError (Status);
3342 goto Cleanup;
3343 }
3344 CloseRealKey = TRUE;
3345 }
3346 else
3347 {
3348 RealKey = hKey;
3349 CloseRealKey = FALSE;
3350 }
3351
3352 ErrorCode = RegQueryValueExW (RealKey,
3353 NULL,
3354 NULL,
3355 NULL,
3356 (LPBYTE)lpValue,
3357 (LPDWORD)lpcbValue);
3358 if (CloseRealKey)
3359 {
3360 NtClose (RealKey);
3361 }
3362
3363 Cleanup:
3364 CloseDefaultKey(KeyHandle);
3365
3366 return ErrorCode;
3367 }
3368
3369
3370 /************************************************************************
3371 * RegReplaceKeyA
3372 *
3373 * @implemented
3374 */
3375 LONG STDCALL
3376 RegReplaceKeyA (HKEY hKey,
3377 LPCSTR lpSubKey,
3378 LPCSTR lpNewFile,
3379 LPCSTR lpOldFile)
3380 {
3381 UNICODE_STRING SubKey;
3382 UNICODE_STRING NewFile;
3383 UNICODE_STRING OldFile;
3384 LONG ErrorCode;
3385
3386 RtlCreateUnicodeStringFromAsciiz (&SubKey,
3387 (PCSZ)lpSubKey);
3388 RtlCreateUnicodeStringFromAsciiz (&OldFile,
3389 (PCSZ)lpOldFile);
3390 RtlCreateUnicodeStringFromAsciiz (&NewFile,
3391 (PCSZ)lpNewFile);
3392
3393 ErrorCode = RegReplaceKeyW (hKey,
3394 SubKey.Buffer,
3395 NewFile.Buffer,
3396 OldFile.Buffer);
3397
3398 RtlFreeUnicodeString (&OldFile);
3399 RtlFreeUnicodeString (&NewFile);
3400 RtlFreeUnicodeString (&SubKey);
3401
3402 return ErrorCode;
3403 }
3404
3405
3406 /************************************************************************
3407 * RegReplaceKeyW
3408 *
3409 * @unimplemented
3410 */
3411 LONG STDCALL
3412 RegReplaceKeyW (HKEY hKey,
3413 LPCWSTR lpSubKey,
3414 LPCWSTR lpNewFile,
3415 LPCWSTR lpOldFile)
3416 {
3417 OBJECT_ATTRIBUTES KeyObjectAttributes;
3418 OBJECT_ATTRIBUTES NewObjectAttributes;
3419 OBJECT_ATTRIBUTES OldObjectAttributes;
3420 UNICODE_STRING SubKeyName;
3421 UNICODE_STRING NewFileName;
3422 UNICODE_STRING OldFileName;
3423 BOOLEAN CloseRealKey;
3424 HANDLE RealKeyHandle;
3425 HANDLE KeyHandle;
3426 NTSTATUS Status;
3427 LONG ErrorCode = ERROR_SUCCESS;
3428
3429 if (hKey == HKEY_PERFORMANCE_DATA)
3430 {
3431 return ERROR_INVALID_HANDLE;
3432 }
3433
3434 Status = MapDefaultKey (&KeyHandle,
3435 hKey);
3436 if (!NT_SUCCESS(Status))
3437 {
3438 return RtlNtStatusToDosError (Status);
3439 }
3440
3441 /* Open the real key */
3442 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
3443 {
3444 RtlInitUnicodeString (&SubKeyName,
3445 (PWSTR)lpSubKey);
3446 InitializeObjectAttributes (&KeyObjectAttributes,
3447 &SubKeyName,
3448 OBJ_CASE_INSENSITIVE,
3449 KeyHandle,
3450 NULL);
3451 Status = NtOpenKey (&RealKeyHandle,
3452 MAXIMUM_ALLOWED,
3453 &KeyObjectAttributes);
3454 if (!NT_SUCCESS(Status))
3455 {
3456 ErrorCode = RtlNtStatusToDosError (Status);
3457 goto Cleanup;
3458 }
3459 CloseRealKey = TRUE;
3460 }
3461 else
3462 {
3463 RealKeyHandle = KeyHandle;
3464 CloseRealKey = FALSE;
3465 }
3466
3467 /* Convert new file name */
3468 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewFile,
3469 &NewFileName,
3470 NULL,
3471 NULL))
3472 {
3473 if (CloseRealKey)
3474 {
3475 NtClose (RealKeyHandle);
3476 }
3477 ErrorCode = ERROR_INVALID_PARAMETER;
3478 goto Cleanup;
3479 }
3480
3481 InitializeObjectAttributes (&NewObjectAttributes,
3482 &NewFileName,
3483 OBJ_CASE_INSENSITIVE,
3484 NULL,
3485 NULL);
3486
3487 /* Convert old file name */
3488 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpOldFile,
3489 &OldFileName,
3490 NULL,
3491 NULL))