e0a0b827be86577c1e11b533d048897f4f55c821
[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 * RegCopyTreeW
324 *
325 * @unimplemented
326 */
327 LONG STDCALL
328 RegCopyTreeW(IN HKEY hKeySrc,
329 IN LPCWSTR lpSubKey OPTIONAL,
330 IN HKEY hKeyDest)
331 {
332 HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
333 NTSTATUS Status;
334
335 Status = MapDefaultKey(&KeyHandle,
336 hKeySrc);
337 if (!NT_SUCCESS(Status))
338 {
339 return RtlNtStatusToDosError(Status);
340 }
341
342 Status = MapDefaultKey(&DestKeyHandle,
343 hKeyDest);
344 if (!NT_SUCCESS(Status))
345 {
346 goto Cleanup2;
347 }
348
349 if (lpSubKey != NULL)
350 {
351 OBJECT_ATTRIBUTES ObjectAttributes;
352 UNICODE_STRING SubKeyName;
353
354 RtlInitUnicodeString(&SubKeyName,
355 (LPWSTR)lpSubKey);
356
357 InitializeObjectAttributes(&ObjectAttributes,
358 &SubKeyName,
359 OBJ_CASE_INSENSITIVE,
360 KeyHandle,
361 NULL);
362
363 Status = NtOpenKey(&SubKeyHandle,
364 KEY_READ,
365 &ObjectAttributes);
366 if (!NT_SUCCESS(Status))
367 {
368 goto Cleanup;
369 }
370
371 CurKey = SubKeyHandle;
372 }
373 else
374 CurKey = KeyHandle;
375
376 /* FIXME - copy all keys and values recursively */
377 Status = STATUS_NOT_IMPLEMENTED;
378
379 if (SubKeyHandle != NULL)
380 {
381 NtClose(SubKeyHandle);
382 }
383
384 Cleanup:
385 CloseDefaultKey(DestKeyHandle);
386 Cleanup2:
387 CloseDefaultKey(KeyHandle);
388
389 if (!NT_SUCCESS(Status))
390 {
391 return RtlNtStatusToDosError(Status);
392 }
393
394 return ERROR_SUCCESS;
395 }
396
397
398 /************************************************************************
399 * RegCopyTreeA
400 *
401 * @implemented
402 */
403 LONG STDCALL
404 RegCopyTreeA(IN HKEY hKeySrc,
405 IN LPCSTR lpSubKey OPTIONAL,
406 IN HKEY hKeyDest)
407 {
408 UNICODE_STRING SubKeyName;
409 LONG Ret;
410
411 if (lpSubKey != NULL)
412 {
413 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
414 (LPSTR)lpSubKey))
415 {
416 return ERROR_NOT_ENOUGH_MEMORY;
417 }
418 }
419 else
420 RtlInitUnicodeString(&SubKeyName,
421 NULL);
422
423 Ret = RegCopyTreeW(hKeySrc,
424 SubKeyName.Buffer,
425 hKeyDest);
426
427 RtlFreeUnicodeString(&SubKeyName);
428
429 return Ret;
430 }
431
432
433 /************************************************************************
434 * RegConnectRegistryA
435 *
436 * @implemented
437 */
438 LONG STDCALL
439 RegConnectRegistryA (IN LPCSTR lpMachineName,
440 IN HKEY hKey,
441 OUT PHKEY phkResult)
442 {
443 UNICODE_STRING MachineName;
444 LONG Ret;
445
446 if (lpMachineName != NULL)
447 {
448 if (!RtlCreateUnicodeStringFromAsciiz(&MachineName,
449 (LPSTR)lpMachineName))
450 {
451 return ERROR_NOT_ENOUGH_MEMORY;
452 }
453 }
454 else
455 RtlInitUnicodeString(&MachineName,
456 NULL);
457
458 Ret = RegConnectRegistryW(MachineName.Buffer,
459 hKey,
460 phkResult);
461
462 RtlFreeUnicodeString(&MachineName);
463
464 return Ret;
465 }
466
467
468 /************************************************************************
469 * RegConnectRegistryW
470 *
471 * @unimplemented
472 */
473 LONG STDCALL
474 RegConnectRegistryW (LPCWSTR lpMachineName,
475 HKEY hKey,
476 PHKEY phkResult)
477 {
478 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
479 return ERROR_CALL_NOT_IMPLEMENTED;
480 }
481
482
483 /************************************************************************
484 * CreateNestedKey
485 *
486 * Create key and all necessary intermediate keys
487 */
488 static NTSTATUS
489 CreateNestedKey(PHKEY KeyHandle,
490 POBJECT_ATTRIBUTES ObjectAttributes,
491 PUNICODE_STRING ClassString,
492 DWORD dwOptions,
493 REGSAM samDesired,
494 DWORD *lpdwDisposition)
495 {
496 OBJECT_ATTRIBUTES LocalObjectAttributes;
497 UNICODE_STRING LocalKeyName;
498 ULONG Disposition;
499 NTSTATUS Status;
500 ULONG FullNameLength;
501 ULONG Length;
502 PWCHAR Ptr;
503 HANDLE LocalKeyHandle;
504
505 Status = NtCreateKey((PHANDLE) KeyHandle,
506 samDesired,
507 ObjectAttributes,
508 0,
509 ClassString,
510 dwOptions,
511 (PULONG)lpdwDisposition);
512 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
513 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
514 return Status;
515
516 /* Copy object attributes */
517 RtlCopyMemory (&LocalObjectAttributes,
518 ObjectAttributes,
519 sizeof(OBJECT_ATTRIBUTES));
520 RtlCreateUnicodeString (&LocalKeyName,
521 ObjectAttributes->ObjectName->Buffer);
522 LocalObjectAttributes.ObjectName = &LocalKeyName;
523 FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
524
525 /* Remove the last part of the key name and try to create the key again. */
526 while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
527 {
528 Ptr = wcsrchr (LocalKeyName.Buffer, '\\');
529 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
530 {
531 Status = STATUS_UNSUCCESSFUL;
532 break;
533 }
534 *Ptr = (WCHAR)0;
535 LocalKeyName.Length = wcslen (LocalKeyName.Buffer) * sizeof(WCHAR);
536
537 Status = NtCreateKey (&LocalKeyHandle,
538 KEY_ALL_ACCESS,
539 &LocalObjectAttributes,
540 0,
541 NULL,
542 0,
543 &Disposition);
544 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
545 }
546
547 if (!NT_SUCCESS(Status))
548 {
549 RtlFreeUnicodeString (&LocalKeyName);
550 return Status;
551 }
552
553 /* Add removed parts of the key name and create them too. */
554 Length = wcslen (LocalKeyName.Buffer);
555 while (TRUE)
556 {
557 NtClose (LocalKeyHandle);
558
559 LocalKeyName.Buffer[Length] = L'\\';
560 Length = wcslen (LocalKeyName.Buffer);
561 LocalKeyName.Length = Length * sizeof(WCHAR);
562
563 if (Length == FullNameLength)
564 {
565 Status = NtCreateKey((PHANDLE) KeyHandle,
566 samDesired,
567 ObjectAttributes,
568 0,
569 ClassString,
570 dwOptions,
571 (PULONG)lpdwDisposition);
572 break;
573 }
574 Status = NtCreateKey (&LocalKeyHandle,
575 KEY_CREATE_SUB_KEY,
576 &LocalObjectAttributes,
577 0,
578 NULL,
579 0,
580 &Disposition);
581 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
582 if (!NT_SUCCESS(Status))
583 break;
584 }
585
586 RtlFreeUnicodeString (&LocalKeyName);
587
588 return Status;
589 }
590
591
592 /************************************************************************
593 * RegCreateKeyExA
594 *
595 * @implemented
596 */
597 LONG STDCALL
598 RegCreateKeyExA (HKEY hKey,
599 LPCSTR lpSubKey,
600 DWORD Reserved,
601 LPSTR lpClass,
602 DWORD dwOptions,
603 REGSAM samDesired,
604 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
605 PHKEY phkResult,
606 LPDWORD lpdwDisposition)
607 {
608 UNICODE_STRING SubKeyString;
609 UNICODE_STRING ClassString;
610 OBJECT_ATTRIBUTES Attributes;
611 HANDLE ParentKey;
612 NTSTATUS Status;
613
614 TRACE("RegCreateKeyExA() called\n");
615
616 /* get the real parent key */
617 Status = MapDefaultKey (&ParentKey,
618 hKey);
619 if (!NT_SUCCESS(Status))
620 {
621 return RtlNtStatusToDosError (Status);
622 }
623 TRACE("ParentKey %x\n", (ULONG)ParentKey);
624
625 if (lpClass != NULL)
626 {
627 RtlCreateUnicodeStringFromAsciiz (&ClassString,
628 lpClass);
629 }
630
631 RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
632 (LPSTR)lpSubKey);
633 InitializeObjectAttributes (&Attributes,
634 &SubKeyString,
635 OBJ_CASE_INSENSITIVE,
636 (HANDLE)ParentKey,
637 (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
638 Status = CreateNestedKey(phkResult,
639 &Attributes,
640 (lpClass == NULL)? NULL : &ClassString,
641 dwOptions,
642 samDesired,
643 lpdwDisposition);
644 RtlFreeUnicodeString (&SubKeyString);
645 if (lpClass != NULL)
646 {
647 RtlFreeUnicodeString (&ClassString);
648 }
649
650 CloseDefaultKey(ParentKey);
651
652 TRACE("Status %x\n", Status);
653 if (!NT_SUCCESS(Status))
654 {
655 return RtlNtStatusToDosError (Status);
656 }
657
658 return ERROR_SUCCESS;
659 }
660
661
662 /************************************************************************
663 * RegCreateKeyExW
664 *
665 * @implemented
666 */
667 LONG STDCALL
668 RegCreateKeyExW (HKEY hKey,
669 LPCWSTR lpSubKey,
670 DWORD Reserved,
671 LPWSTR lpClass,
672 DWORD dwOptions,
673 REGSAM samDesired,
674 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
675 PHKEY phkResult,
676 LPDWORD lpdwDisposition)
677 {
678 UNICODE_STRING SubKeyString;
679 UNICODE_STRING ClassString;
680 OBJECT_ATTRIBUTES Attributes;
681 HANDLE ParentKey;
682 NTSTATUS Status;
683
684 TRACE("RegCreateKeyExW() called\n");
685
686 /* get the real parent key */
687 Status = MapDefaultKey (&ParentKey,
688 hKey);
689 if (!NT_SUCCESS(Status))
690 {
691 return RtlNtStatusToDosError(Status);
692 }
693 TRACE("ParentKey %x\n", (ULONG)ParentKey);
694
695 RtlInitUnicodeString (&ClassString,
696 lpClass);
697 RtlInitUnicodeString (&SubKeyString,
698 lpSubKey);
699 InitializeObjectAttributes (&Attributes,
700 &SubKeyString,
701 OBJ_CASE_INSENSITIVE,
702 (HANDLE)ParentKey,
703 (PSECURITY_DESCRIPTOR)lpSecurityAttributes);
704 Status = CreateNestedKey(phkResult,
705 &Attributes,
706 (lpClass == NULL)? NULL : &ClassString,
707 dwOptions,
708 samDesired,
709 lpdwDisposition);
710
711 CloseDefaultKey(ParentKey);
712
713 TRACE("Status %x\n", Status);
714 if (!NT_SUCCESS(Status))
715 {
716 return RtlNtStatusToDosError (Status);
717 }
718
719 return ERROR_SUCCESS;
720 }
721
722
723 /************************************************************************
724 * RegCreateKeyA
725 *
726 * @implemented
727 */
728 LONG STDCALL
729 RegCreateKeyA (HKEY hKey,
730 LPCSTR lpSubKey,
731 PHKEY phkResult)
732 {
733 return RegCreateKeyExA (hKey,
734 lpSubKey,
735 0,
736 NULL,
737 0,
738 MAXIMUM_ALLOWED,
739 NULL,
740 phkResult,
741 NULL);
742 }
743
744
745 /************************************************************************
746 * RegCreateKeyW
747 *
748 * @implemented
749 */
750 LONG STDCALL
751 RegCreateKeyW (HKEY hKey,
752 LPCWSTR lpSubKey,
753 PHKEY phkResult)
754 {
755 return RegCreateKeyExW (hKey,
756 lpSubKey,
757 0,
758 NULL,
759 0,
760 MAXIMUM_ALLOWED,
761 NULL,
762 phkResult,
763 NULL);
764 }
765
766
767 /************************************************************************
768 * RegDeleteKeyA
769 *
770 * @implemented
771 */
772 LONG STDCALL
773 RegDeleteKeyA (HKEY hKey,
774 LPCSTR lpSubKey)
775 {
776 OBJECT_ATTRIBUTES ObjectAttributes;
777 UNICODE_STRING SubKeyName;
778 HANDLE ParentKey;
779 HANDLE TargetKey;
780 NTSTATUS Status;
781
782 Status = MapDefaultKey (&ParentKey,
783 hKey);
784 if (!NT_SUCCESS(Status))
785 {
786 return RtlNtStatusToDosError (Status);
787 }
788
789 RtlCreateUnicodeStringFromAsciiz (&SubKeyName,
790 (LPSTR)lpSubKey);
791 InitializeObjectAttributes(&ObjectAttributes,
792 &SubKeyName,
793 OBJ_CASE_INSENSITIVE,
794 ParentKey,
795 NULL);
796
797 Status = NtOpenKey (&TargetKey,
798 DELETE,
799 &ObjectAttributes);
800 RtlFreeUnicodeString (&SubKeyName);
801 if (!NT_SUCCESS(Status))
802 {
803 goto Cleanup;
804 }
805
806 Status = NtDeleteKey (TargetKey);
807 NtClose (TargetKey);
808
809 Cleanup:
810 CloseDefaultKey(ParentKey);
811
812 if (!NT_SUCCESS(Status))
813 {
814 return RtlNtStatusToDosError(Status);
815 }
816
817 return ERROR_SUCCESS;
818 }
819
820
821 /************************************************************************
822 * RegDeleteKeyW
823 *
824 * @implemented
825 */
826 LONG STDCALL
827 RegDeleteKeyW (HKEY hKey,
828 LPCWSTR lpSubKey)
829 {
830 OBJECT_ATTRIBUTES ObjectAttributes;
831 UNICODE_STRING SubKeyName;
832 HANDLE ParentKey;
833 HANDLE TargetKey;
834 NTSTATUS Status;
835
836 Status = MapDefaultKey (&ParentKey,
837 hKey);
838 if (!NT_SUCCESS(Status))
839 {
840 return RtlNtStatusToDosError (Status);
841 }
842
843 RtlInitUnicodeString (&SubKeyName,
844 (LPWSTR)lpSubKey);
845 InitializeObjectAttributes (&ObjectAttributes,
846 &SubKeyName,
847 OBJ_CASE_INSENSITIVE,
848 ParentKey,
849 NULL);
850 Status = NtOpenKey (&TargetKey,
851 DELETE,
852 &ObjectAttributes);
853 if (!NT_SUCCESS(Status))
854 {
855 goto Cleanup;
856 }
857
858 Status = NtDeleteKey (TargetKey);
859 NtClose (TargetKey);
860
861 Cleanup:
862 CloseDefaultKey(ParentKey);
863
864 if (!NT_SUCCESS(Status))
865 {
866 return RtlNtStatusToDosError (Status);
867 }
868
869 return ERROR_SUCCESS;
870 }
871
872
873 /************************************************************************
874 * RegDeleteKeyValueW
875 *
876 * @implemented
877 */
878 LONG STDCALL
879 RegDeleteKeyValueW(IN HKEY hKey,
880 IN LPCWSTR lpSubKey OPTIONAL,
881 IN LPCWSTR lpValueName OPTIONAL)
882 {
883 UNICODE_STRING ValueName;
884 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
885 NTSTATUS Status;
886
887 Status = MapDefaultKey(&KeyHandle,
888 hKey);
889 if (!NT_SUCCESS(Status))
890 {
891 return RtlNtStatusToDosError(Status);
892 }
893
894 if (lpSubKey != NULL)
895 {
896 OBJECT_ATTRIBUTES ObjectAttributes;
897 UNICODE_STRING SubKeyName;
898
899 RtlInitUnicodeString(&SubKeyName,
900 (LPWSTR)lpSubKey);
901
902 InitializeObjectAttributes(&ObjectAttributes,
903 &SubKeyName,
904 OBJ_CASE_INSENSITIVE,
905 KeyHandle,
906 NULL);
907
908 Status = NtOpenKey(&SubKeyHandle,
909 KEY_SET_VALUE,
910 &ObjectAttributes);
911 if (!NT_SUCCESS(Status))
912 {
913 goto Cleanup;
914 }
915
916 CurKey = SubKeyHandle;
917 }
918 else
919 CurKey = KeyHandle;
920
921 RtlInitUnicodeString(&ValueName,
922 (LPWSTR)lpValueName);
923
924 Status = NtDeleteValueKey(CurKey,
925 &ValueName);
926
927 if (SubKeyHandle != NULL)
928 {
929 NtClose(SubKeyHandle);
930 }
931
932 Cleanup:
933 CloseDefaultKey(KeyHandle);
934
935 if (!NT_SUCCESS(Status))
936 {
937 return RtlNtStatusToDosError(Status);
938 }
939
940 return ERROR_SUCCESS;
941 }
942
943
944 /************************************************************************
945 * RegDeleteKeyValueA
946 *
947 * @implemented
948 */
949 LONG STDCALL
950 RegDeleteKeyValueA(IN HKEY hKey,
951 IN LPCSTR lpSubKey OPTIONAL,
952 IN LPCSTR lpValueName OPTIONAL)
953 {
954 UNICODE_STRING SubKey, ValueName;
955 LONG Ret;
956
957 if (lpSubKey != NULL)
958 {
959 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey,
960 (LPSTR)lpSubKey))
961 {
962 return ERROR_NOT_ENOUGH_MEMORY;
963 }
964 }
965 else
966 RtlInitUnicodeString(&SubKey,
967 NULL);
968
969 if (lpValueName != NULL)
970 {
971 if (!RtlCreateUnicodeStringFromAsciiz(&ValueName,
972 (LPSTR)lpValueName))
973 {
974 RtlFreeUnicodeString(&SubKey);
975 return ERROR_NOT_ENOUGH_MEMORY;
976 }
977 }
978 else
979 RtlInitUnicodeString(&ValueName,
980 NULL);
981
982 Ret = RegDeleteKeyValueW(hKey,
983 SubKey.Buffer,
984 SubKey.Buffer);
985
986 RtlFreeUnicodeString(&SubKey);
987 RtlFreeUnicodeString(&ValueName);
988
989 return Ret;
990 }
991
992
993 static NTSTATUS
994 RegpDeleteTree(IN HKEY hKey,
995 OUT PBOOLEAN KeysDeleted)
996 {
997 typedef struct
998 {
999 LIST_ENTRY ListEntry;
1000 HANDLE KeyHandle;
1001 } REGP_DEL_KEYS, *PREG_DEL_KEYS;
1002
1003 LIST_ENTRY delQueueHead;
1004 PREG_DEL_KEYS delKeys, newDelKeys;
1005 HANDLE ProcessHeap;
1006 ULONG BufferSize;
1007 PKEY_BASIC_INFORMATION BasicInfo;
1008 PREG_DEL_KEYS KeyDelRoot;
1009 NTSTATUS Status = STATUS_SUCCESS;
1010 NTSTATUS Status2 = STATUS_SUCCESS;
1011
1012 *KeysDeleted = FALSE;
1013
1014 InitializeListHead(&delQueueHead);
1015
1016 ProcessHeap = RtlGetProcessHeap();
1017
1018 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1019 structure for the root key, we only do that for subkeys as we need to
1020 allocate REGP_DEL_KEYS structures anyway! */
1021 KeyDelRoot = RtlAllocateHeap(ProcessHeap,
1022 0,
1023 sizeof(REGP_DEL_KEYS));
1024 if (KeyDelRoot != NULL)
1025 {
1026 KeyDelRoot->KeyHandle = hKey;
1027 InsertTailList(&delQueueHead,
1028 &KeyDelRoot->ListEntry);
1029
1030 do
1031 {
1032 delKeys = CONTAINING_RECORD(delQueueHead.Flink,
1033 REGP_DEL_KEYS,
1034 ListEntry);
1035
1036 BufferSize = 0;
1037 BasicInfo = NULL;
1038 newDelKeys = NULL;
1039
1040 ReadFirstSubKey:
1041 /* check if this key contains subkeys and delete them first by queuing
1042 them at the head of the list */
1043 Status2 = NtEnumerateKey(delKeys->KeyHandle,
1044 0,
1045 KeyBasicInformation,
1046 BasicInfo,
1047 BufferSize,
1048 &BufferSize);
1049
1050 if (NT_SUCCESS(Status2))
1051 {
1052 OBJECT_ATTRIBUTES ObjectAttributes;
1053 UNICODE_STRING SubKeyName;
1054
1055 ASSERT(newDelKeys != NULL);
1056 ASSERT(BasicInfo != NULL);
1057
1058 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1059 SubKeyName.Length = BasicInfo->NameLength;
1060 SubKeyName.MaximumLength = BasicInfo->NameLength;
1061 SubKeyName.Buffer = BasicInfo->Name;
1062
1063 InitializeObjectAttributes(&ObjectAttributes,
1064 &SubKeyName,
1065 OBJ_CASE_INSENSITIVE,
1066 delKeys->KeyHandle,
1067 NULL);
1068
1069 /* open the subkey */
1070 Status2 = NtOpenKey(&newDelKeys->KeyHandle,
1071 DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
1072 &ObjectAttributes);
1073 if (!NT_SUCCESS(Status2))
1074 {
1075 goto SubKeyFailure;
1076 }
1077
1078 /* enqueue this key to the head of the deletion queue */
1079 InsertHeadList(&delQueueHead,
1080 &newDelKeys->ListEntry);
1081
1082 /* try again from the head of the list */
1083 continue;
1084 }
1085 else
1086 {
1087 if (Status2 == STATUS_BUFFER_TOO_SMALL)
1088 {
1089 newDelKeys = RtlAllocateHeap(ProcessHeap,
1090 0,
1091 BufferSize + sizeof(REGP_DEL_KEYS));
1092 if (newDelKeys != NULL)
1093 {
1094 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1095
1096 /* try again */
1097 goto ReadFirstSubKey;
1098 }
1099 else
1100 {
1101 /* don't break, let's try to delete as many keys as possible */
1102 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1103 goto SubKeyFailureNoFree;
1104 }
1105 }
1106 else if (Status2 == STATUS_BUFFER_OVERFLOW)
1107 {
1108 PREG_DEL_KEYS newDelKeys2;
1109
1110 ASSERT(newDelKeys != NULL);
1111
1112 /* we need more memory to query the key name */
1113 newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
1114 0,
1115 newDelKeys,
1116 BufferSize + sizeof(REGP_DEL_KEYS));
1117 if (newDelKeys2 != NULL)
1118 {
1119 newDelKeys = newDelKeys2;
1120 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
1121
1122 /* try again */
1123 goto ReadFirstSubKey;
1124 }
1125 else
1126 {
1127 /* don't break, let's try to delete as many keys as possible */
1128 Status2 = STATUS_INSUFFICIENT_RESOURCES;
1129 }
1130 }
1131
1132 SubKeyFailure:
1133 ASSERT(newDelKeys != NULL);
1134 RtlFreeHeap(ProcessHeap,
1135 0,
1136 newDelKeys);
1137
1138 SubKeyFailureNoFree:
1139 /* don't break, let's try to delete as many keys as possible */
1140 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
1141 {
1142 Status = Status2;
1143 }
1144 }
1145
1146 Status2 = NtDeleteKey(delKeys->KeyHandle);
1147
1148 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1149
1150 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
1151 {
1152 /* don't break, let's try to delete as many keys as possible */
1153 Status = Status2;
1154 }
1155
1156 /* remove the entry from the list */
1157 RemoveEntryList(&delKeys->ListEntry);
1158
1159 RtlFreeHeap(ProcessHeap,
1160 0,
1161 delKeys);
1162 } while (!IsListEmpty(&delQueueHead));
1163
1164 *KeysDeleted = TRUE;
1165 }
1166 else
1167 Status = STATUS_INSUFFICIENT_RESOURCES;
1168
1169 return Status;
1170 }
1171
1172
1173 /************************************************************************
1174 * RegDeleteTreeW
1175 *
1176 * @implemented
1177 */
1178 LONG STDCALL
1179 RegDeleteTreeW(IN HKEY hKey,
1180 IN LPCWSTR lpSubKey OPTIONAL)
1181 {
1182 BOOLEAN KeysDeleted;
1183 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1184 NTSTATUS Status;
1185
1186 Status = MapDefaultKey(&KeyHandle,
1187 hKey);
1188 if (!NT_SUCCESS(Status))
1189 {
1190 return RtlNtStatusToDosError(Status);
1191 }
1192
1193 if (lpSubKey != NULL)
1194 {
1195 OBJECT_ATTRIBUTES ObjectAttributes;
1196 UNICODE_STRING SubKeyName;
1197
1198 RtlInitUnicodeString(&SubKeyName,
1199 (LPWSTR)lpSubKey);
1200
1201 InitializeObjectAttributes(&ObjectAttributes,
1202 &SubKeyName,
1203 OBJ_CASE_INSENSITIVE,
1204 KeyHandle,
1205 NULL);
1206
1207 Status = NtOpenKey(&SubKeyHandle,
1208 DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
1209 &ObjectAttributes);
1210 if (!NT_SUCCESS(Status))
1211 {
1212 goto Cleanup;
1213 }
1214
1215 CurKey = SubKeyHandle;
1216 }
1217 else
1218 CurKey = KeyHandle;
1219
1220 Status = RegpDeleteTree(CurKey,
1221 &KeysDeleted);
1222
1223 if (!KeysDeleted)
1224 {
1225 /* only close handles of keys that weren't deleted! */
1226 if (SubKeyHandle != NULL)
1227 {
1228 NtClose(SubKeyHandle);
1229 }
1230
1231 Cleanup:
1232 CloseDefaultKey(KeyHandle);
1233 }
1234
1235 if (!NT_SUCCESS(Status))
1236 {
1237 return RtlNtStatusToDosError(Status);
1238 }
1239
1240 return ERROR_SUCCESS;
1241 }
1242
1243
1244 /************************************************************************
1245 * RegDeleteTreeA
1246 *
1247 * @implemented
1248 */
1249 LONG STDCALL
1250 RegDeleteTreeA(IN HKEY hKey,
1251 IN LPCSTR lpSubKey OPTIONAL)
1252 {
1253 UNICODE_STRING SubKeyName;
1254 LONG Ret;
1255
1256 if (lpSubKey != NULL)
1257 {
1258 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1259 (LPSTR)lpSubKey))
1260 {
1261 return ERROR_NOT_ENOUGH_MEMORY;
1262 }
1263 }
1264 else
1265 RtlInitUnicodeString(&SubKeyName,
1266 NULL);
1267
1268 Ret = RegDeleteTreeW(hKey,
1269 SubKeyName.Buffer);
1270
1271 RtlFreeUnicodeString(&SubKeyName);
1272
1273 return Ret;
1274 }
1275
1276
1277 /************************************************************************
1278 * RegSetKeyValueW
1279 *
1280 * @implemented
1281 */
1282 LONG STDCALL
1283 RegSetKeyValueW(IN HKEY hKey,
1284 IN LPCWSTR lpSubKey OPTIONAL,
1285 IN LPCWSTR lpValueName OPTIONAL,
1286 IN DWORD dwType,
1287 IN LPCVOID lpData OPTIONAL,
1288 IN DWORD cbData)
1289 {
1290 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1291 NTSTATUS Status;
1292 LONG Ret;
1293
1294 Status = MapDefaultKey(&KeyHandle,
1295 hKey);
1296 if (!NT_SUCCESS(Status))
1297 {
1298 return RtlNtStatusToDosError(Status);
1299 }
1300
1301 if (lpSubKey != NULL)
1302 {
1303 OBJECT_ATTRIBUTES ObjectAttributes;
1304 UNICODE_STRING SubKeyName;
1305
1306 RtlInitUnicodeString(&SubKeyName,
1307 (LPWSTR)lpSubKey);
1308
1309 InitializeObjectAttributes(&ObjectAttributes,
1310 &SubKeyName,
1311 OBJ_CASE_INSENSITIVE,
1312 KeyHandle,
1313 NULL);
1314
1315 Status = NtOpenKey(&SubKeyHandle,
1316 KEY_SET_VALUE,
1317 &ObjectAttributes);
1318 if (!NT_SUCCESS(Status))
1319 {
1320 Ret = RtlNtStatusToDosError(Status);
1321 goto Cleanup;
1322 }
1323
1324 CurKey = SubKeyHandle;
1325 }
1326 else
1327 CurKey = KeyHandle;
1328
1329 Ret = RegSetValueExW(CurKey,
1330 lpValueName,
1331 0,
1332 dwType,
1333 lpData,
1334 cbData);
1335
1336 if (SubKeyHandle != NULL)
1337 {
1338 NtClose(SubKeyHandle);
1339 }
1340
1341 Cleanup:
1342 CloseDefaultKey(KeyHandle);
1343
1344 return Ret;
1345 }
1346
1347
1348 /************************************************************************
1349 * RegSetKeyValueA
1350 *
1351 * @implemented
1352 */
1353 LONG STDCALL
1354 RegSetKeyValueA(IN HKEY hKey,
1355 IN LPCSTR lpSubKey OPTIONAL,
1356 IN LPCSTR lpValueName OPTIONAL,
1357 IN DWORD dwType,
1358 IN LPCVOID lpData OPTIONAL,
1359 IN DWORD cbData)
1360 {
1361 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
1362 NTSTATUS Status;
1363 LONG Ret;
1364
1365 Status = MapDefaultKey(&KeyHandle,
1366 hKey);
1367 if (!NT_SUCCESS(Status))
1368 {
1369 return RtlNtStatusToDosError(Status);
1370 }
1371
1372 if (lpSubKey != NULL)
1373 {
1374 OBJECT_ATTRIBUTES ObjectAttributes;
1375 UNICODE_STRING SubKeyName;
1376
1377 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
1378 (LPSTR)lpSubKey))
1379 {
1380 Ret = ERROR_NOT_ENOUGH_MEMORY;
1381 goto Cleanup;
1382 }
1383
1384 InitializeObjectAttributes(&ObjectAttributes,
1385 &SubKeyName,
1386 OBJ_CASE_INSENSITIVE,
1387 KeyHandle,
1388 NULL);
1389
1390 Status = NtOpenKey(&SubKeyHandle,
1391 KEY_SET_VALUE,
1392 &ObjectAttributes);
1393
1394 RtlFreeUnicodeString(&SubKeyName);
1395
1396 if (!NT_SUCCESS(Status))
1397 {
1398 Ret = RtlNtStatusToDosError(Status);
1399 goto Cleanup;
1400 }
1401
1402 CurKey = SubKeyHandle;
1403 }
1404 else
1405 CurKey = KeyHandle;
1406
1407 Ret = RegSetValueExA(CurKey,
1408 lpValueName,
1409 0,
1410 dwType,
1411 lpData,
1412 cbData);
1413
1414 if (SubKeyHandle != NULL)
1415 {
1416 NtClose(SubKeyHandle);
1417 }
1418
1419 Cleanup:
1420 CloseDefaultKey(KeyHandle);
1421
1422 return Ret;
1423 }
1424
1425
1426 /************************************************************************
1427 * RegDeleteValueA
1428 *
1429 * @implemented
1430 */
1431 LONG STDCALL
1432 RegDeleteValueA (HKEY hKey,
1433 LPCSTR lpValueName)
1434 {
1435 UNICODE_STRING ValueName;
1436 HANDLE KeyHandle;
1437 NTSTATUS Status;
1438
1439 Status = MapDefaultKey (&KeyHandle,
1440 hKey);
1441 if (!NT_SUCCESS(Status))
1442 {
1443 return RtlNtStatusToDosError (Status);
1444 }
1445
1446 RtlCreateUnicodeStringFromAsciiz (&ValueName,
1447 (LPSTR)lpValueName);
1448 Status = NtDeleteValueKey (KeyHandle,
1449 &ValueName);
1450 RtlFreeUnicodeString (&ValueName);
1451
1452 CloseDefaultKey(KeyHandle);
1453
1454 if (!NT_SUCCESS(Status))
1455 {
1456 return RtlNtStatusToDosError (Status);
1457 }
1458
1459 return ERROR_SUCCESS;
1460 }
1461
1462
1463 /************************************************************************
1464 * RegDeleteValueW
1465 *
1466 * @implemented
1467 */
1468 LONG STDCALL
1469 RegDeleteValueW (HKEY hKey,
1470 LPCWSTR lpValueName)
1471 {
1472 UNICODE_STRING ValueName;
1473 NTSTATUS Status;
1474 HANDLE KeyHandle;
1475
1476 Status = MapDefaultKey (&KeyHandle,
1477 hKey);
1478 if (!NT_SUCCESS(Status))
1479 {
1480 return RtlNtStatusToDosError (Status);
1481 }
1482
1483 RtlInitUnicodeString (&ValueName,
1484 (LPWSTR)lpValueName);
1485
1486 Status = NtDeleteValueKey (KeyHandle,
1487 &ValueName);
1488
1489 CloseDefaultKey(KeyHandle);
1490
1491 if (!NT_SUCCESS(Status))
1492 {
1493 return RtlNtStatusToDosError (Status);
1494 }
1495
1496 return ERROR_SUCCESS;
1497 }
1498
1499
1500 /************************************************************************
1501 * RegEnumKeyA
1502 *
1503 * @implemented
1504 */
1505 LONG STDCALL
1506 RegEnumKeyA (HKEY hKey,
1507 DWORD dwIndex,
1508 LPSTR lpName,
1509 DWORD cbName)
1510 {
1511 DWORD dwLength;
1512
1513 dwLength = cbName;
1514 return RegEnumKeyExA (hKey,
1515 dwIndex,
1516 lpName,
1517 &dwLength,
1518 NULL,
1519 NULL,
1520 NULL,
1521 NULL);
1522 }
1523
1524
1525 /************************************************************************
1526 * RegEnumKeyW
1527 *
1528 * @implemented
1529 */
1530 LONG STDCALL
1531 RegEnumKeyW (HKEY hKey,
1532 DWORD dwIndex,
1533 LPWSTR lpName,
1534 DWORD cbName)
1535 {
1536 DWORD dwLength;
1537
1538 dwLength = cbName;
1539 return RegEnumKeyExW (hKey,
1540 dwIndex,
1541 lpName,
1542 &dwLength,
1543 NULL,
1544 NULL,
1545 NULL,
1546 NULL);
1547 }
1548
1549
1550 /************************************************************************
1551 * RegEnumKeyExA
1552 *
1553 * @implemented
1554 */
1555 LONG STDCALL
1556 RegEnumKeyExA (HKEY hKey,
1557 DWORD dwIndex,
1558 LPSTR lpName,
1559 LPDWORD lpcbName,
1560 LPDWORD lpReserved,
1561 LPSTR lpClass,
1562 LPDWORD lpcbClass,
1563 PFILETIME lpftLastWriteTime)
1564 {
1565 union
1566 {
1567 KEY_NODE_INFORMATION Node;
1568 KEY_BASIC_INFORMATION Basic;
1569 } *KeyInfo;
1570
1571 UNICODE_STRING StringU;
1572 ANSI_STRING StringA;
1573 LONG ErrorCode = ERROR_SUCCESS;
1574 DWORD NameLength;
1575 DWORD ClassLength = 0;
1576 DWORD BufferSize;
1577 DWORD ResultSize;
1578 HANDLE KeyHandle;
1579 NTSTATUS Status;
1580
1581 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
1582 hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
1583
1584 if ((lpClass) && (!lpcbClass))
1585 {
1586 return ERROR_INVALID_PARAMETER;
1587 }
1588
1589 Status = MapDefaultKey(&KeyHandle, hKey);
1590 if (!NT_SUCCESS(Status))
1591 {
1592 return RtlNtStatusToDosError (Status);
1593 }
1594
1595 if (*lpcbName > 0)
1596 {
1597 NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
1598 }
1599 else
1600 {
1601 NameLength = 0;
1602 }
1603
1604 if (lpClass)
1605 {
1606 if (*lpcbClass > 0)
1607 {
1608 ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
1609 }
1610 else
1611 {
1612 ClassLength = 0;
1613 }
1614
1615 /* The class name should start at a dword boundary */
1616 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
1617 }
1618 else
1619 {
1620 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
1621 }
1622
1623 KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
1624 if (KeyInfo == NULL)
1625 {
1626 ErrorCode = ERROR_OUTOFMEMORY;
1627 goto Cleanup;
1628 }
1629
1630 Status = NtEnumerateKey (KeyHandle,
1631 (ULONG)dwIndex,
1632 lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
1633 KeyInfo,
1634 BufferSize,
1635 &ResultSize);
1636 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
1637 if (!NT_SUCCESS(Status))
1638 {
1639 ErrorCode = RtlNtStatusToDosError (Status);
1640 }
1641 else
1642 {
1643 if (lpClass == NULL)
1644 {
1645 if (KeyInfo->Basic.NameLength > NameLength)
1646 {
1647 ErrorCode = ERROR_BUFFER_OVERFLOW;
1648 }
1649 else
1650 {
1651 StringU.Buffer = KeyInfo->Basic.Name;
1652 StringU.Length = KeyInfo->Basic.NameLength;
1653 StringU.MaximumLength = KeyInfo->Basic.NameLength;
1654 }
1655 }
1656 else
1657 {
1658 if (KeyInfo->Node.NameLength > NameLength ||
1659 KeyInfo->Node.ClassLength > ClassLength)
1660 {
1661 ErrorCode = ERROR_BUFFER_OVERFLOW;
1662 }
1663 else
1664 {
1665 StringA.Buffer = lpClass;
1666 StringA.Length = 0;
1667 StringA.MaximumLength = *lpcbClass;
1668 StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
1669 StringU.Length = KeyInfo->Node.ClassLength;
1670 StringU.MaximumLength = KeyInfo->Node.ClassLength;
1671 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
1672 lpClass[StringA.Length] = 0;
1673 *lpcbClass = StringA.Length;
1674 StringU.Buffer = KeyInfo->Node.Name;
1675 StringU.Length = KeyInfo->Node.NameLength;
1676 StringU.MaximumLength = KeyInfo->Node.NameLength;
1677 }
1678 }
1679
1680 if (ErrorCode == ERROR_SUCCESS)
1681 {
1682 StringA.Buffer = lpName;
1683 StringA.Length = 0;
1684 StringA.MaximumLength = *lpcbName;
1685 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
1686 lpName[StringA.Length] = 0;
1687 *lpcbName = StringA.Length;
1688 if (lpftLastWriteTime != NULL)
1689 {
1690 if (lpClass == NULL)
1691 {
1692 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
1693 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
1694 }
1695 else
1696 {
1697 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
1698 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
1699 }
1700 }
1701 }
1702 }
1703
1704 TRACE("Key Namea0 Length %d\n", StringU.Length);
1705 TRACE("Key Namea1 Length %d\n", NameLength);
1706 TRACE("Key Namea Length %d\n", *lpcbName);
1707 TRACE("Key Namea %s\n", lpName);
1708
1709 RtlFreeHeap (ProcessHeap,
1710 0,
1711 KeyInfo);
1712
1713 Cleanup:
1714 CloseDefaultKey(KeyHandle);
1715
1716 return ErrorCode;
1717 }
1718
1719
1720 /************************************************************************
1721 * RegEnumKeyExW
1722 *
1723 * @implemented
1724 */
1725 LONG STDCALL
1726 RegEnumKeyExW (HKEY hKey,
1727 DWORD dwIndex,
1728 LPWSTR lpName,
1729 LPDWORD lpcbName,
1730 LPDWORD lpReserved,
1731 LPWSTR lpClass,
1732 LPDWORD lpcbClass,
1733 PFILETIME lpftLastWriteTime)
1734 {
1735 union
1736 {
1737 KEY_NODE_INFORMATION Node;
1738 KEY_BASIC_INFORMATION Basic;
1739 } *KeyInfo;
1740
1741 ULONG BufferSize;
1742 ULONG ResultSize;
1743 ULONG NameLength;
1744 ULONG ClassLength = 0;
1745 HANDLE KeyHandle;
1746 LONG ErrorCode = ERROR_SUCCESS;
1747 NTSTATUS Status;
1748
1749 Status = MapDefaultKey(&KeyHandle,
1750 hKey);
1751 if (!NT_SUCCESS(Status))
1752 {
1753 return RtlNtStatusToDosError (Status);
1754 }
1755
1756 if (*lpcbName > 0)
1757 {
1758 NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
1759 }
1760 else
1761 {
1762 NameLength = 0;
1763 }
1764
1765 if (lpClass)
1766 {
1767 if (*lpcbClass > 0)
1768 {
1769 ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
1770 }
1771 else
1772 {
1773 ClassLength = 0;
1774 }
1775
1776 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
1777 }
1778 else
1779 {
1780 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
1781 }
1782
1783 KeyInfo = RtlAllocateHeap (ProcessHeap,
1784 0,
1785 BufferSize);
1786 if (KeyInfo == NULL)
1787 {
1788 ErrorCode = ERROR_OUTOFMEMORY;
1789 goto Cleanup;
1790 }
1791
1792 Status = NtEnumerateKey (KeyHandle,
1793 (ULONG)dwIndex,
1794 lpClass ? KeyNodeInformation : KeyBasicInformation,
1795 KeyInfo,
1796 BufferSize,
1797 &ResultSize);
1798 TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
1799 if (!NT_SUCCESS(Status))
1800 {
1801 ErrorCode = RtlNtStatusToDosError (Status);
1802 }
1803 else
1804 {
1805 if (lpClass == NULL)
1806 {
1807 if (KeyInfo->Basic.NameLength > NameLength)
1808 {
1809 ErrorCode = ERROR_BUFFER_OVERFLOW;
1810 }
1811 else
1812 {
1813 RtlCopyMemory (lpName,
1814 KeyInfo->Basic.Name,
1815 KeyInfo->Basic.NameLength);
1816 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
1817 lpName[*lpcbName] = 0;
1818 }
1819 }
1820 else
1821 {
1822 if (KeyInfo->Node.NameLength > NameLength ||
1823 KeyInfo->Node.ClassLength > ClassLength)
1824 {
1825 ErrorCode = ERROR_BUFFER_OVERFLOW;
1826 }
1827 else
1828 {
1829 RtlCopyMemory (lpName,
1830 KeyInfo->Node.Name,
1831 KeyInfo->Node.NameLength);
1832 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
1833 lpName[*lpcbName] = 0;
1834 RtlCopyMemory (lpClass,
1835 (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
1836 KeyInfo->Node.ClassLength);
1837 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
1838 lpClass[*lpcbClass] = 0;
1839 }
1840 }
1841
1842 if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
1843 {
1844 if (lpClass == NULL)
1845 {
1846 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
1847 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
1848 }
1849 else
1850 {
1851 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
1852 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
1853 }
1854 }
1855 }
1856
1857 RtlFreeHeap (ProcessHeap,
1858 0,
1859 KeyInfo);
1860
1861 Cleanup:
1862 CloseDefaultKey(KeyHandle);
1863
1864 return ErrorCode;
1865 }
1866
1867 /************************************************************************
1868 * RegEnumValueA
1869 *
1870 * @implemented
1871 */
1872 LONG STDCALL
1873 RegEnumValueA( HKEY hKey, DWORD index, LPSTR value, LPDWORD val_count,
1874 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1875 {
1876 HANDLE KeyHandle;
1877 NTSTATUS status;
1878 DWORD total_size;
1879 char buffer[256], *buf_ptr = buffer;
1880 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1881 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1882
1883 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1884 // hkey, index, value, val_count, reserved, type, data, count );
1885
1886 /* NT only checks count, not val_count */
1887 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1888 status = MapDefaultKey (&KeyHandle, hKey);
1889 if (!NT_SUCCESS(status))
1890 {
1891 return RtlNtStatusToDosError (status);
1892 }
1893
1894 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1895 if (data) total_size += *count;
1896 total_size = min( sizeof(buffer), total_size );
1897
1898 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
1899 buffer, total_size, &total_size );
1900 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1901
1902 /* we need to fetch the contents for a string type even if not requested,
1903 * because we need to compute the length of the ASCII string. */
1904 if (value || data || is_string(info->Type))
1905 {
1906 /* retry with a dynamically allocated buffer */
1907 while (status == STATUS_BUFFER_OVERFLOW)
1908 {
1909 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1910 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1911 {
1912 status = STATUS_INSUFFICIENT_RESOURCES;
1913 goto done;
1914 }
1915 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1916 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
1917 buf_ptr, total_size, &total_size );
1918 }
1919
1920 if (status) goto done;
1921
1922 if (is_string(info->Type))
1923 {
1924 DWORD len;
1925 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1926 total_size - info->DataOffset );
1927 if (data && len)
1928 {
1929 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1930 else
1931 {
1932 RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1933 total_size - info->DataOffset );
1934 /* if the type is REG_SZ and data is not 0-terminated
1935 * and there is enough space in the buffer NT appends a \0 */
1936 if (len < *count && data[len-1]) data[len] = 0;
1937 }
1938 }
1939 info->DataLength = len;
1940 }
1941 else if (data)
1942 {
1943 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1944 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1945 }
1946
1947 if (value && !status)
1948 {
1949 DWORD len;
1950
1951 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1952 if (len >= *val_count)
1953 {
1954 status = STATUS_BUFFER_OVERFLOW;
1955 if (*val_count)
1956 {
1957 len = *val_count - 1;
1958 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1959 value[len] = 0;
1960 }
1961 }
1962 else
1963 {
1964 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1965 value[len] = 0;
1966 *val_count = len;
1967 }
1968 }
1969 }
1970 else status = STATUS_SUCCESS;
1971
1972 if (type) *type = info->Type;
1973 if (count) *count = info->DataLength;
1974
1975 done:
1976 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1977 CloseDefaultKey(KeyHandle);
1978 return RtlNtStatusToDosError(status);
1979 }
1980
1981 /******************************************************************************
1982 * RegEnumValueW [ADVAPI32.@]
1983 * @implemented
1984 *
1985 * PARAMS
1986 * hkey [I] Handle to key to query
1987 * index [I] Index of value to query
1988 * value [O] Value string
1989 * val_count [I/O] Size of value buffer (in wchars)
1990 * reserved [I] Reserved
1991 * type [O] Type code
1992 * data [O] Value data
1993 * count [I/O] Size of data buffer (in bytes)
1994 *
1995 * RETURNS
1996 * Success: ERROR_SUCCESS
1997 * Failure: nonzero error code from Winerror.h
1998 */
1999 LONG STDCALL
2000 RegEnumValueW( HKEY hKey, DWORD index, LPWSTR value, PDWORD val_count,
2001 PDWORD reserved, PDWORD type, LPBYTE data, PDWORD count )
2002 {
2003 HANDLE KeyHandle;
2004 NTSTATUS status;
2005 DWORD total_size;
2006 char buffer[256], *buf_ptr = buffer;
2007 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2008 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
2009
2010 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2011 // hkey, index, value, val_count, reserved, type, data, count );
2012
2013 /* NT only checks count, not val_count */
2014 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
2015
2016 status = MapDefaultKey (&KeyHandle, hKey);
2017 if (!NT_SUCCESS(status))
2018 {
2019 return RtlNtStatusToDosError (status);
2020 }
2021
2022 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2023 if (data) total_size += *count;
2024 total_size = min( sizeof(buffer), total_size );
2025
2026 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2027 buffer, total_size, &total_size );
2028 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
2029
2030 if (value || data)
2031 {
2032 /* retry with a dynamically allocated buffer */
2033 while (status == STATUS_BUFFER_OVERFLOW)
2034 {
2035 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2036 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2037 {
2038 status = ERROR_NOT_ENOUGH_MEMORY;
2039 goto done;
2040 }
2041 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2042 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
2043 buf_ptr, total_size, &total_size );
2044 }
2045
2046 if (status) goto done;
2047
2048 if (value)
2049 {
2050 if (info->NameLength/sizeof(WCHAR) >= *val_count)
2051 {
2052 status = STATUS_BUFFER_OVERFLOW;
2053 goto overflow;
2054 }
2055 memcpy( value, info->Name, info->NameLength );
2056 *val_count = info->NameLength / sizeof(WCHAR);
2057 value[*val_count] = 0;
2058 }
2059
2060 if (data)
2061 {
2062 if (total_size - info->DataOffset > *count)
2063 {
2064 status = STATUS_BUFFER_OVERFLOW;
2065 goto overflow;
2066 }
2067 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2068 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
2069 {
2070 /* if the type is REG_SZ and data is not 0-terminated
2071 * and there is enough space in the buffer NT appends a \0 */
2072 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
2073 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
2074 }
2075 }
2076 }
2077 else status = STATUS_SUCCESS;
2078
2079 overflow:
2080 if (type) *type = info->Type;
2081 if (count) *count = info->DataLength;
2082
2083 done:
2084 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2085 CloseDefaultKey(KeyHandle);
2086 return RtlNtStatusToDosError(status);
2087 }
2088
2089 /************************************************************************
2090 * RegFlushKey
2091 *
2092 * @implemented
2093 */
2094 LONG STDCALL
2095 RegFlushKey(HKEY hKey)
2096 {
2097 HANDLE KeyHandle;
2098 NTSTATUS Status;
2099
2100 if (hKey == HKEY_PERFORMANCE_DATA)
2101 {
2102 return ERROR_SUCCESS;
2103 }
2104
2105 Status = MapDefaultKey (&KeyHandle,
2106 hKey);
2107 if (!NT_SUCCESS(Status))
2108 {
2109 return RtlNtStatusToDosError (Status);
2110 }
2111
2112 Status = NtFlushKey (KeyHandle);
2113
2114 CloseDefaultKey(KeyHandle);
2115
2116 if (!NT_SUCCESS(Status))
2117 {
2118 return RtlNtStatusToDosError (Status);
2119 }
2120
2121 return ERROR_SUCCESS;
2122 }
2123
2124
2125 /************************************************************************
2126 * RegGetKeySecurity
2127 *
2128 * @implemented
2129 */
2130 LONG STDCALL
2131 RegGetKeySecurity(HKEY hKey,
2132 SECURITY_INFORMATION SecurityInformation,
2133 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2134 LPDWORD lpcbSecurityDescriptor)
2135 {
2136 HANDLE KeyHandle;
2137 NTSTATUS Status;
2138
2139 if (hKey == HKEY_PERFORMANCE_DATA)
2140 {
2141 return ERROR_INVALID_HANDLE;
2142 }
2143
2144 Status = MapDefaultKey(&KeyHandle,
2145 hKey);
2146 if (!NT_SUCCESS(Status))
2147 {
2148 TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
2149 return RtlNtStatusToDosError (Status);
2150 }
2151
2152 Status = NtQuerySecurityObject(KeyHandle,
2153 SecurityInformation,
2154 pSecurityDescriptor,
2155 *lpcbSecurityDescriptor,
2156 lpcbSecurityDescriptor);
2157
2158 CloseDefaultKey(KeyHandle);
2159
2160 if (!NT_SUCCESS(Status))
2161 {
2162 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
2163 return RtlNtStatusToDosError (Status);
2164 }
2165
2166 return ERROR_SUCCESS;
2167 }
2168
2169
2170 /************************************************************************
2171 * RegLoadKeyA
2172 *
2173 * @implemented
2174 */
2175 LONG STDCALL
2176 RegLoadKeyA (HKEY hKey,
2177 LPCSTR lpSubKey,
2178 LPCSTR lpFile)
2179 {
2180 UNICODE_STRING FileName;
2181 UNICODE_STRING KeyName;
2182 LONG ErrorCode;
2183
2184 RtlCreateUnicodeStringFromAsciiz (&KeyName,
2185 (LPSTR)lpSubKey);
2186 RtlCreateUnicodeStringFromAsciiz (&FileName,
2187 (LPSTR)lpFile);
2188
2189 ErrorCode = RegLoadKeyW (hKey,
2190 KeyName.Buffer,
2191 FileName.Buffer);
2192
2193 RtlFreeUnicodeString (&FileName);
2194 RtlFreeUnicodeString (&KeyName);
2195
2196 return ErrorCode;
2197 }
2198
2199
2200 /************************************************************************
2201 * RegLoadKeyW
2202 *
2203 * @implemented
2204 */
2205 LONG STDCALL
2206 RegLoadKeyW (HKEY hKey,
2207 LPCWSTR lpSubKey,
2208 LPCWSTR lpFile)
2209 {
2210 OBJECT_ATTRIBUTES FileObjectAttributes;
2211 OBJECT_ATTRIBUTES KeyObjectAttributes;
2212 UNICODE_STRING FileName;
2213 UNICODE_STRING KeyName;
2214 HANDLE KeyHandle;
2215 NTSTATUS Status;
2216 LONG ErrorCode = ERROR_SUCCESS;
2217
2218 if (hKey == HKEY_PERFORMANCE_DATA)
2219 {
2220 return ERROR_INVALID_HANDLE;
2221 }
2222
2223 Status = MapDefaultKey (&KeyHandle,
2224 hKey);
2225 if (!NT_SUCCESS(Status))
2226 {
2227 return RtlNtStatusToDosError (Status);
2228 }
2229
2230 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
2231 &FileName,
2232 NULL,
2233 NULL))
2234 {
2235 ErrorCode = ERROR_BAD_PATHNAME;
2236 goto Cleanup;
2237 }
2238
2239 InitializeObjectAttributes (&FileObjectAttributes,
2240 &FileName,
2241 OBJ_CASE_INSENSITIVE,
2242 NULL,
2243 NULL);
2244
2245 RtlInitUnicodeString (&KeyName,
2246 (LPWSTR)lpSubKey);
2247
2248 InitializeObjectAttributes (&KeyObjectAttributes,
2249 &KeyName,
2250 OBJ_CASE_INSENSITIVE,
2251 KeyHandle,
2252 NULL);
2253
2254 Status = NtLoadKey (&KeyObjectAttributes,
2255 &FileObjectAttributes);
2256
2257 RtlFreeUnicodeString (&FileName);
2258
2259 if (!NT_SUCCESS(Status))
2260 {
2261 ErrorCode = RtlNtStatusToDosError (Status);
2262 goto Cleanup;
2263 }
2264
2265 Cleanup:
2266 CloseDefaultKey(KeyHandle);
2267
2268 return ErrorCode;
2269 }
2270
2271
2272 /************************************************************************
2273 * RegNotifyChangeKeyValue
2274 *
2275 * @unimplemented
2276 */
2277 LONG STDCALL
2278 RegNotifyChangeKeyValue (HKEY hKey,
2279 BOOL bWatchSubtree,
2280 DWORD dwNotifyFilter,
2281 HANDLE hEvent,
2282 BOOL fAsynchronous)
2283 {
2284 IO_STATUS_BLOCK IoStatusBlock;
2285 HANDLE KeyHandle;
2286 NTSTATUS Status;
2287 LONG ErrorCode = ERROR_SUCCESS;
2288
2289 if (hKey == HKEY_PERFORMANCE_DATA)
2290 {
2291 return ERROR_INVALID_HANDLE;
2292 }
2293
2294 if (fAsynchronous == TRUE && hEvent == NULL)
2295 {
2296 return ERROR_INVALID_PARAMETER;
2297 }
2298
2299 Status = MapDefaultKey (&KeyHandle,
2300 hKey);
2301 if (!NT_SUCCESS(Status))
2302 {
2303 return RtlNtStatusToDosError (Status);
2304 }
2305
2306 /* FIXME: Remote key handles must fail */
2307
2308 Status = NtNotifyChangeKey (KeyHandle,
2309 hEvent,
2310 0,
2311 0,
2312 &IoStatusBlock,
2313 dwNotifyFilter,
2314 bWatchSubtree,
2315 0,
2316 0,
2317 fAsynchronous);
2318 if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
2319 {
2320 ErrorCode = RtlNtStatusToDosError (Status);
2321 }
2322
2323 CloseDefaultKey(KeyHandle);
2324
2325 return ErrorCode;
2326 }
2327
2328
2329 /************************************************************************
2330 * RegOpenCurrentUser
2331 *
2332 * @implemented
2333 */
2334 LONG STDCALL
2335 RegOpenCurrentUser (IN REGSAM samDesired,
2336 OUT PHKEY phkResult)
2337 {
2338 NTSTATUS Status;
2339
2340 Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
2341 (PHANDLE)phkResult);
2342 if (!NT_SUCCESS(Status))
2343 {
2344 /* NOTE - don't set the last error code! just return the error! */
2345 return RtlNtStatusToDosError(Status);
2346 }
2347
2348 return ERROR_SUCCESS;
2349 }
2350
2351
2352 /************************************************************************
2353 * RegOpenKeyA
2354 *
2355 * 20050503 Fireball - imported from WINE
2356 *
2357 * @implemented
2358 */
2359 LONG STDCALL
2360 RegOpenKeyA (HKEY hKey,
2361 LPCSTR lpSubKey,
2362 PHKEY phkResult)
2363 {
2364 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey, lpSubKey, phkResult);
2365
2366 if (!lpSubKey || !*lpSubKey)
2367 {
2368 *phkResult = hKey;
2369 return ERROR_SUCCESS;
2370 }
2371
2372 return RegOpenKeyExA( hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
2373 }
2374
2375
2376 /************************************************************************
2377 * RegOpenKeyW
2378 *
2379 * 19981101 Ariadne
2380 * 19990525 EA
2381 * 20050503 Fireball - imported from WINE
2382 *
2383 * @implemented
2384 */
2385 LONG STDCALL
2386 RegOpenKeyW (HKEY hKey,
2387 LPCWSTR lpSubKey,
2388 PHKEY phkResult)
2389 {
2390 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey, lpSubKey, phkResult);
2391
2392 if (!lpSubKey || !*lpSubKey)
2393 {
2394 *phkResult = hKey;
2395 return ERROR_SUCCESS;
2396 }
2397 return RegOpenKeyExW(hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
2398 }
2399
2400
2401 /************************************************************************
2402 * RegOpenKeyExA
2403 *
2404 * @implemented
2405 */
2406 LONG STDCALL
2407 RegOpenKeyExA (HKEY hKey,
2408 LPCSTR lpSubKey,
2409 DWORD ulOptions,
2410 REGSAM samDesired,
2411 PHKEY phkResult)
2412 {
2413 OBJECT_ATTRIBUTES ObjectAttributes;
2414 UNICODE_STRING SubKeyString;
2415 HANDLE KeyHandle;
2416 NTSTATUS Status;
2417 LONG ErrorCode = ERROR_SUCCESS;
2418
2419 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2420 hKey, lpSubKey, ulOptions, samDesired, phkResult);
2421
2422 Status = MapDefaultKey (&KeyHandle, hKey);
2423 if (!NT_SUCCESS(Status))
2424 {
2425 return RtlNtStatusToDosError (Status);
2426 }
2427
2428 RtlCreateUnicodeStringFromAsciiz (&SubKeyString, (LPSTR)lpSubKey);
2429 InitializeObjectAttributes (&ObjectAttributes,
2430 &SubKeyString,
2431 OBJ_CASE_INSENSITIVE,
2432 KeyHandle,
2433 NULL);
2434
2435 Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
2436 RtlFreeUnicodeString (&SubKeyString);
2437 if (!NT_SUCCESS(Status))
2438 {
2439 ErrorCode = RtlNtStatusToDosError (Status);
2440 }
2441
2442 CloseDefaultKey(KeyHandle);
2443
2444 return ErrorCode;
2445 }
2446
2447
2448 /************************************************************************
2449 * RegOpenKeyExW
2450 *
2451 * @implemented
2452 */
2453 LONG STDCALL
2454 RegOpenKeyExW (HKEY hKey,
2455 LPCWSTR lpSubKey,
2456 DWORD ulOptions,
2457 REGSAM samDesired,
2458 PHKEY phkResult)
2459 {
2460 OBJECT_ATTRIBUTES ObjectAttributes;
2461 UNICODE_STRING SubKeyString;
2462 HANDLE KeyHandle;
2463 NTSTATUS Status;
2464 LONG ErrorCode = ERROR_SUCCESS;
2465
2466 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2467 hKey, lpSubKey, ulOptions, samDesired, phkResult);
2468
2469 Status = MapDefaultKey (&KeyHandle, hKey);
2470 if (!NT_SUCCESS(Status))
2471 {
2472 return RtlNtStatusToDosError (Status);
2473 }
2474
2475 if (lpSubKey != NULL)
2476 RtlInitUnicodeString (&SubKeyString, (LPWSTR)lpSubKey);
2477 else
2478 RtlInitUnicodeString (&SubKeyString, (LPWSTR)L"");
2479
2480 InitializeObjectAttributes (&ObjectAttributes,
2481 &SubKeyString,
2482 OBJ_CASE_INSENSITIVE,
2483 KeyHandle,
2484 NULL);
2485
2486 Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
2487
2488 if (!NT_SUCCESS(Status))
2489 {
2490 ErrorCode = RtlNtStatusToDosError (Status);
2491 }
2492
2493 CloseDefaultKey(KeyHandle);
2494
2495 return ErrorCode;
2496 }
2497
2498
2499 /************************************************************************
2500 * RegOpenUserClassesRoot
2501 *
2502 * @implemented
2503 */
2504 LONG STDCALL
2505 RegOpenUserClassesRoot (IN HANDLE hToken,
2506 IN DWORD dwOptions,
2507 IN REGSAM samDesired,
2508 OUT PHKEY phkResult)
2509 {
2510 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
2511 const WCHAR UserClassesKeySuffix[] = L"_Classes";
2512 PTOKEN_USER TokenUserData;
2513 ULONG RequiredLength;
2514 UNICODE_STRING UserSidString, UserClassesKeyRoot;
2515 OBJECT_ATTRIBUTES ObjectAttributes;
2516 NTSTATUS Status;
2517
2518 /* check parameters */
2519 if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
2520 {
2521 return ERROR_INVALID_PARAMETER;
2522 }
2523
2524 /*
2525 * Get the user sid from the token
2526 */
2527
2528 ReadTokenSid:
2529 /* determine how much memory we need */
2530 Status = NtQueryInformationToken(hToken,
2531 TokenUser,
2532 NULL,
2533 0,
2534 &RequiredLength);
2535 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
2536 {
2537 /* NOTE - as opposed to all other registry functions windows does indeed
2538 change the last error code in case the caller supplied a invalid
2539 handle for example! */
2540 return RtlNtStatusToDosError (Status);
2541 }
2542
2543 TokenUserData = RtlAllocateHeap(ProcessHeap,
2544 0,
2545 RequiredLength);
2546 if (TokenUserData == NULL)
2547 {
2548 return ERROR_NOT_ENOUGH_MEMORY;
2549 }
2550
2551 /* attempt to read the information */
2552 Status = NtQueryInformationToken(hToken,
2553 TokenUser,
2554 TokenUserData,
2555 RequiredLength,
2556 &RequiredLength);
2557 if (!NT_SUCCESS(Status))
2558 {
2559 RtlFreeHeap(ProcessHeap,
2560 0,
2561 TokenUserData);
2562 if (Status == STATUS_BUFFER_TOO_SMALL)
2563 {
2564 /* the information appears to have changed?! try again */
2565 goto ReadTokenSid;
2566 }
2567
2568 /* NOTE - as opposed to all other registry functions windows does indeed
2569 change the last error code in case the caller supplied a invalid
2570 handle for example! */
2571 return RtlNtStatusToDosError (Status);
2572 }
2573
2574 /*
2575 * Build the absolute path for the user's registry in the form
2576 * "\Registry\User\<SID>_Classes"
2577 */
2578 Status = RtlConvertSidToUnicodeString(&UserSidString,
2579 TokenUserData->User.Sid,
2580 TRUE);
2581
2582 /* we don't need the user data anymore, free it */
2583 RtlFreeHeap(ProcessHeap,
2584 0,
2585 TokenUserData);
2586
2587 if (!NT_SUCCESS(Status))
2588 {
2589 return RtlNtStatusToDosError (Status);
2590 }
2591
2592 /* allocate enough memory for the entire key string */
2593 UserClassesKeyRoot.Length = 0;
2594 UserClassesKeyRoot.MaximumLength = UserSidString.Length +
2595 sizeof(UserClassesKeyPrefix) +
2596 sizeof(UserClassesKeySuffix);
2597 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
2598 0,
2599 UserClassesKeyRoot.MaximumLength);
2600 if (UserClassesKeyRoot.Buffer == NULL)
2601 {
2602 RtlFreeUnicodeString(&UserSidString);
2603 return RtlNtStatusToDosError (Status);
2604 }
2605
2606 /* build the string */
2607 RtlAppendUnicodeToString(&UserClassesKeyRoot,
2608 UserClassesKeyPrefix);
2609 RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
2610 &UserSidString);
2611 RtlAppendUnicodeToString(&UserClassesKeyRoot,
2612 UserClassesKeySuffix);
2613
2614 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
2615
2616 /*
2617 * Open the key
2618 */
2619
2620 InitializeObjectAttributes (&ObjectAttributes,
2621 &UserClassesKeyRoot,
2622 OBJ_CASE_INSENSITIVE,
2623 NULL,
2624 NULL);
2625
2626 Status = NtOpenKey((PHANDLE)phkResult,
2627 samDesired,
2628 &ObjectAttributes);
2629
2630 RtlFreeUnicodeString(&UserSidString);
2631 RtlFreeUnicodeString(&UserClassesKeyRoot);
2632
2633 if (!NT_SUCCESS(Status))
2634 {
2635 return RtlNtStatusToDosError (Status);
2636 }
2637
2638 return ERROR_SUCCESS;
2639 }
2640
2641
2642 /************************************************************************
2643 * RegQueryInfoKeyA
2644 *
2645 * @implemented
2646 */
2647 LONG STDCALL
2648 RegQueryInfoKeyA (HKEY hKey,
2649 LPSTR lpClass,
2650 LPDWORD lpcbClass,
2651 LPDWORD lpReserved,
2652 LPDWORD lpcSubKeys,
2653 LPDWORD lpcbMaxSubKeyLen,
2654 LPDWORD lpcbMaxClassLen,
2655 LPDWORD lpcValues,
2656 LPDWORD lpcbMaxValueNameLen,
2657 LPDWORD lpcbMaxValueLen,
2658 LPDWORD lpcbSecurityDescriptor,
2659 PFILETIME lpftLastWriteTime)
2660 {
2661 WCHAR ClassName[MAX_PATH];
2662 UNICODE_STRING UnicodeString;
2663 ANSI_STRING AnsiString;
2664 LONG ErrorCode;
2665
2666 RtlInitUnicodeString (&UnicodeString,
2667 NULL);
2668 if (lpClass != NULL)
2669 {
2670 UnicodeString.Buffer = &ClassName[0];
2671 UnicodeString.MaximumLength = sizeof(ClassName);
2672 AnsiString.MaximumLength = *lpcbClass;
2673 }
2674
2675 ErrorCode = RegQueryInfoKeyW (hKey,
2676 UnicodeString.Buffer,
2677 lpcbClass,
2678 lpReserved,
2679 lpcSubKeys,
2680 lpcbMaxSubKeyLen,
2681 lpcbMaxClassLen,
2682 lpcValues,
2683 lpcbMaxValueNameLen,
2684 lpcbMaxValueLen,
2685 lpcbSecurityDescriptor,
2686 lpftLastWriteTime);
2687 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
2688 {
2689 AnsiString.Buffer = lpClass;
2690 AnsiString.Length = 0;
2691 UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
2692 RtlUnicodeStringToAnsiString (&AnsiString,
2693 &UnicodeString,
2694 FALSE);
2695 *lpcbClass = AnsiString.Length;
2696 lpClass[AnsiString.Length] = 0;
2697 }
2698
2699 return ErrorCode;
2700 }
2701
2702
2703 /************************************************************************
2704 * RegQueryInfoKeyW
2705 *
2706 * @implemented
2707 */
2708 LONG STDCALL
2709 RegQueryInfoKeyW (HKEY hKey,
2710 LPWSTR lpClass,
2711 LPDWORD lpcbClass,
2712 LPDWORD lpReserved,
2713 LPDWORD lpcSubKeys,
2714 LPDWORD lpcbMaxSubKeyLen,
2715 LPDWORD lpcbMaxClassLen,
2716 LPDWORD lpcValues,
2717 LPDWORD lpcbMaxValueNameLen,
2718 LPDWORD lpcbMaxValueLen,
2719 LPDWORD lpcbSecurityDescriptor,
2720 PFILETIME lpftLastWriteTime)
2721 {
2722 KEY_FULL_INFORMATION FullInfoBuffer;
2723 PKEY_FULL_INFORMATION FullInfo;
2724 ULONG FullInfoSize;
2725 ULONG ClassLength = 0;
2726 HANDLE KeyHandle;
2727 NTSTATUS Status;
2728 ULONG Length;
2729 LONG ErrorCode = ERROR_SUCCESS;
2730
2731 if ((lpClass) && (!lpcbClass))
2732 {
2733 return ERROR_INVALID_PARAMETER;
2734 }
2735
2736 Status = MapDefaultKey (&KeyHandle,
2737 hKey);
2738 if (!NT_SUCCESS(Status))
2739 {
2740 return RtlNtStatusToDosError (Status);
2741 }
2742
2743 if (lpClass != NULL)
2744 {
2745 if (*lpcbClass > 0)
2746 {
2747 ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2748 }
2749 else
2750 {
2751 ClassLength = 0;
2752 }
2753
2754 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
2755 FullInfo = RtlAllocateHeap (ProcessHeap,
2756 0,
2757 FullInfoSize);
2758 if (FullInfo == NULL)
2759 {
2760 ErrorCode = ERROR_OUTOFMEMORY;
2761 goto Cleanup;
2762 }
2763
2764 FullInfo->ClassLength = ClassLength;
2765 }
2766 else
2767 {
2768 FullInfoSize = sizeof(KEY_FULL_INFORMATION);
2769 FullInfo = &FullInfoBuffer;
2770 FullInfo->ClassLength = 0;
2771 }
2772 FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
2773
2774 Status = NtQueryKey (KeyHandle,
2775 KeyFullInformation,
2776 FullInfo,
2777 FullInfoSize,
2778 &Length);
2779 TRACE("NtQueryKey() returned status 0x%X\n", Status);
2780 if (!NT_SUCCESS(Status))
2781 {
2782 if (lpClass != NULL)
2783 {
2784 RtlFreeHeap (ProcessHeap,
2785 0,
2786 FullInfo);
2787 }
2788
2789 ErrorCode = RtlNtStatusToDosError (Status);
2790 goto Cleanup;
2791 }
2792
2793 TRACE("SubKeys %d\n", FullInfo->SubKeys);
2794 if (lpcSubKeys != NULL)
2795 {
2796 *lpcSubKeys = FullInfo->SubKeys;
2797 }
2798
2799 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
2800 if (lpcbMaxSubKeyLen != NULL)
2801 {
2802 *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
2803 }
2804
2805 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
2806 if (lpcbMaxClassLen != NULL)
2807 {
2808 *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
2809 }
2810
2811 TRACE("Values %lu\n", FullInfo->Values);
2812 if (lpcValues != NULL)
2813 {
2814 *lpcValues = FullInfo->Values;
2815 }
2816
2817 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
2818 if (lpcbMaxValueNameLen != NULL)
2819 {
2820 *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
2821 }
2822
2823 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
2824 if (lpcbMaxValueLen != NULL)
2825 {
2826 *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
2827 }
2828
2829 if (lpcbSecurityDescriptor != NULL)
2830 {
2831 Status = NtQuerySecurityObject(KeyHandle,
2832 OWNER_SECURITY_INFORMATION |
2833 GROUP_SECURITY_INFORMATION |
2834 DACL_SECURITY_INFORMATION,
2835 NULL,
2836 0,
2837 lpcbSecurityDescriptor);
2838 if (!NT_SUCCESS(Status))
2839 {
2840 if (lpClass != NULL)
2841 {
2842 RtlFreeHeap(ProcessHeap,
2843 0,
2844 FullInfo);
2845 }
2846
2847 ErrorCode = RtlNtStatusToDosError (Status);
2848 goto Cleanup;
2849 }
2850 }
2851
2852 if (lpftLastWriteTime != NULL)
2853 {
2854 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
2855 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
2856 }
2857
2858 if (lpClass != NULL)
2859 {
2860 if (FullInfo->ClassLength > ClassLength)
2861 {
2862 ErrorCode = ERROR_BUFFER_OVERFLOW;
2863 }
2864 else
2865 {
2866 RtlCopyMemory (lpClass,
2867 FullInfo->Class,
2868 FullInfo->ClassLength);
2869 *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
2870 lpClass[*lpcbClass] = 0;
2871 }
2872
2873 RtlFreeHeap (ProcessHeap,
2874 0,
2875 FullInfo);
2876 }
2877
2878 Cleanup:
2879 CloseDefaultKey(KeyHandle);
2880
2881 return ErrorCode;
2882 }
2883
2884
2885 /************************************************************************
2886 * RegQueryMultipleValuesA
2887 *
2888 * @implemented
2889 */
2890 LONG STDCALL
2891 RegQueryMultipleValuesA (HKEY hKey,
2892 PVALENTA val_list,
2893 DWORD num_vals,
2894 LPSTR lpValueBuf,
2895 LPDWORD ldwTotsize)
2896 {
2897 ULONG i;
2898 DWORD maxBytes = *ldwTotsize;
2899 LPSTR bufptr = (LPSTR)lpValueBuf;
2900 LONG ErrorCode;
2901
2902 if (maxBytes >= (1024*1024))
2903 return ERROR_TRANSFER_TOO_LONG;
2904
2905 *ldwTotsize = 0;
2906
2907 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
2908 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
2909
2910 for (i = 0; i < num_vals; i++)
2911 {
2912 val_list[i].ve_valuelen = 0;
2913 ErrorCode = RegQueryValueExA (hKey,
2914 val_list[i].ve_valuename,
2915 NULL,
2916 NULL,
2917 NULL,
2918 &val_list[i].ve_valuelen);
2919 if (ErrorCode != ERROR_SUCCESS)
2920 {
2921 return ErrorCode;
2922 }
2923
2924 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
2925 {
2926 ErrorCode = RegQueryValueExA (hKey,
2927 val_list[i].ve_valuename,
2928 NULL,
2929 &val_list[i].ve_type,
2930 (LPBYTE)bufptr,
2931 &val_list[i].ve_valuelen);
2932 if (ErrorCode != ERROR_SUCCESS)
2933 {
2934 return ErrorCode;
2935 }
2936
2937 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
2938
2939 bufptr += val_list[i].ve_valuelen;
2940 }
2941
2942 *ldwTotsize += val_list[i].ve_valuelen;
2943 }
2944
2945 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
2946 }
2947
2948
2949 /************************************************************************
2950 * RegQueryMultipleValuesW
2951 *
2952 * @implemented
2953 */
2954 LONG STDCALL
2955 RegQueryMultipleValuesW (HKEY hKey,
2956 PVALENTW val_list,
2957 DWORD num_vals,
2958 LPWSTR lpValueBuf,
2959 LPDWORD ldwTotsize)
2960 {
2961 ULONG i;
2962 DWORD maxBytes = *ldwTotsize;
2963 LPSTR bufptr = (LPSTR)lpValueBuf;
2964 LONG ErrorCode;
2965
2966 if (maxBytes >= (1024*1024))
2967 return ERROR_TRANSFER_TOO_LONG;
2968
2969 *ldwTotsize = 0;
2970
2971 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
2972 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
2973
2974 for (i = 0; i < num_vals; i++)
2975 {
2976 val_list[i].ve_valuelen = 0;
2977 ErrorCode = RegQueryValueExW (hKey,
2978 val_list[i].ve_valuename,
2979 NULL,
2980 NULL,
2981 NULL,
2982 &val_list[i].ve_valuelen);
2983 if (ErrorCode != ERROR_SUCCESS)
2984 {
2985 return ErrorCode;
2986 }
2987
2988 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
2989 {
2990 ErrorCode = RegQueryValueExW (hKey,
2991 val_list[i].ve_valuename,
2992 NULL,
2993 &val_list[i].ve_type,
2994 (LPBYTE)bufptr,
2995 &val_list[i].ve_valuelen);
2996 if (ErrorCode != ERROR_SUCCESS)
2997 {
2998 return ErrorCode;
2999 }
3000
3001 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
3002
3003 bufptr += val_list[i].ve_valuelen;
3004 }
3005
3006 *ldwTotsize += val_list[i].ve_valuelen;
3007 }
3008
3009 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
3010 }
3011
3012
3013 /************************************************************************
3014 * RegQueryValueExW
3015 *
3016 * @implemented
3017 */
3018 LONG STDCALL
3019 RegQueryValueExW (HKEY hKey,
3020 LPCWSTR lpValueName,
3021 LPDWORD lpReserved,
3022 LPDWORD lpType,
3023 LPBYTE lpData,
3024 LPDWORD lpcbData)
3025 {
3026 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
3027 UNICODE_STRING ValueName;
3028 NTSTATUS Status;
3029 ULONG BufferSize;
3030 ULONG ResultSize;
3031 HANDLE KeyHandle;
3032 LONG ErrorCode = ERROR_SUCCESS;
3033 ULONG MaxCopy = lpcbData != NULL && lpData != NULL ? *lpcbData : 0;
3034
3035 TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
3036 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
3037
3038 Status = MapDefaultKey (&KeyHandle,
3039 hKey);
3040 if (!NT_SUCCESS(Status))
3041 {
3042 return RtlNtStatusToDosError (Status);
3043 }
3044
3045 if (lpData != NULL && lpcbData == NULL)
3046 {
3047 ErrorCode = ERROR_INVALID_PARAMETER;
3048 goto Cleanup;
3049 }
3050
3051 RtlInitUnicodeString (&ValueName,
3052 lpValueName);
3053 BufferSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MaxCopy;
3054 ValueInfo = RtlAllocateHeap (ProcessHeap,
3055 0,
3056 BufferSize);
3057 if (ValueInfo == NULL)
3058 {
3059 ErrorCode = ERROR_OUTOFMEMORY;
3060 goto Cleanup;
3061 }
3062
3063 Status = NtQueryValueKey (KeyHandle,
3064 &ValueName,
3065 KeyValuePartialInformation,
3066 ValueInfo,
3067 BufferSize,
3068 &ResultSize);
3069 TRACE("Status 0x%X\n", Status);
3070 if (Status == STATUS_BUFFER_OVERFLOW)
3071 {
3072 /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
3073 MaxCopy = 0;
3074 ErrorCode = lpData ? ERROR_MORE_DATA : ERROR_SUCCESS;
3075 }
3076 else if (!NT_SUCCESS(Status))
3077 {
3078 ErrorCode = RtlNtStatusToDosError (Status);
3079 MaxCopy = 0;
3080 if (lpcbData != NULL)
3081 {
3082 ResultSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + *lpcbData;
3083 }
3084 }
3085
3086 if (lpType != NULL)
3087 {
3088 *lpType = ValueInfo->Type;
3089 }
3090
3091 if (NT_SUCCESS(Status) && lpData != NULL)
3092 {
3093 RtlMoveMemory (lpData,
3094 ValueInfo->Data,
3095 min(ValueInfo->DataLength, MaxCopy));
3096 }
3097
3098 if ((ValueInfo->Type == REG_SZ) ||
3099 (ValueInfo->Type == REG_MULTI_SZ) ||
3100 (ValueInfo->Type == REG_EXPAND_SZ))
3101 {
3102 if (lpData != NULL && MaxCopy > ValueInfo->DataLength)
3103 {
3104 ((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
3105 }
3106
3107 if (lpcbData != NULL)
3108 {
3109 *lpcbData = (ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]));
3110 TRACE("(string) Returning Size: %lu\n", *lpcbData);
3111 }
3112 }
3113 else
3114 {
3115 if (lpcbData != NULL)
3116 {
3117 *lpcbData = ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
3118 TRACE("(other) Returning Size: %lu\n", *lpcbData);
3119 }
3120 }
3121
3122 TRACE("Type %d Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
3123
3124 RtlFreeHeap (ProcessHeap,
3125 0,
3126 ValueInfo);
3127
3128 Cleanup:
3129 CloseDefaultKey(KeyHandle);
3130
3131 return ErrorCode;
3132 }
3133
3134
3135 /************************************************************************
3136 * RegQueryValueExA
3137 *
3138 * @implemented
3139 */
3140 LONG STDCALL
3141 RegQueryValueExA (HKEY hKey,
3142 LPCSTR lpValueName,
3143 LPDWORD lpReserved,
3144 LPDWORD lpType,
3145 LPBYTE lpData,
3146 LPDWORD lpcbData)
3147 {
3148 UNICODE_STRING ValueName;
3149 UNICODE_STRING ValueData;
3150 ANSI_STRING AnsiString;
3151 LONG ErrorCode;
3152 DWORD Length;
3153 DWORD Type;
3154
3155 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3156 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
3157
3158 if (lpData != NULL && lpcbData == NULL)
3159 {
3160 return ERROR_INVALID_PARAMETER;
3161 }
3162
3163 if (lpData)
3164 {
3165 ValueData.Length = 0;
3166 ValueData.MaximumLength = (*lpcbData + 1) * sizeof(WCHAR);
3167 ValueData.Buffer = RtlAllocateHeap (ProcessHeap,
3168 0,
3169 ValueData.MaximumLength);
3170 if (!ValueData.Buffer)
3171 {
3172 return ERROR_OUTOFMEMORY;
3173 }
3174 }
3175 else
3176 {
3177 ValueData.Buffer = NULL;
3178 ValueData.Length = 0;
3179 ValueData.MaximumLength = 0;
3180 }
3181
3182 RtlCreateUnicodeStringFromAsciiz (&ValueName,
3183 (LPSTR)lpValueName);
3184
3185 Length = (lpcbData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
3186 ErrorCode = RegQueryValueExW (hKey,
3187 ValueName.Buffer,
3188 lpReserved,
3189 &Type,
3190 (lpData == NULL) ? NULL : (LPBYTE)ValueData.Buffer,
3191 &Length);
3192 TRACE("ErrorCode %lu\n", ErrorCode);
3193 RtlFreeUnicodeString(&ValueName);
3194
3195 if (ErrorCode == ERROR_SUCCESS ||
3196 ErrorCode == ERROR_MORE_DATA)
3197 {
3198 if (lpType != NULL)
3199 {
3200 *lpType = Type;
3201 }
3202
3203 if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ))
3204 {
3205 if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
3206 {
3207 RtlInitAnsiString(&AnsiString, NULL);
3208 AnsiString.Buffer = (LPSTR)lpData;
3209 AnsiString.MaximumLength = *lpcbData;
3210 ValueData.Length = Length;
3211 ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
3212 RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
3213 }
3214 Length = Length / sizeof(WCHAR);
3215 }
3216 else if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
3217 {
3218 if (*lpcbData < Length)
3219 {
3220 ErrorCode = ERROR_MORE_DATA;
3221 }
3222 else
3223 {
3224 RtlMoveMemory(lpData, ValueData.Buffer, Length);
3225 }
3226 }
3227
3228 if (lpcbData != NULL)
3229 {
3230 *lpcbData = Length;
3231 }
3232 }
3233
3234 if (ValueData.Buffer != NULL)
3235 {
3236 RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
3237 }
3238
3239 return ErrorCode;
3240 }
3241
3242
3243 /************************************************************************
3244 * RegQueryValueA
3245 *
3246 * @implemented
3247 */
3248 LONG STDCALL
3249 RegQueryValueA (HKEY hKey,
3250 LPCSTR lpSubKey,
3251 LPSTR lpValue,
3252 PLONG lpcbValue)
3253 {
3254 WCHAR SubKeyNameBuffer[MAX_PATH+1];
3255 UNICODE_STRING SubKeyName;
3256 UNICODE_STRING Value;
3257 ANSI_STRING AnsiString;
3258 LONG ValueSize;
3259 LONG ErrorCode;
3260
3261 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
3262 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
3263
3264 if (lpValue != NULL &&
3265 lpcbValue == NULL)
3266 {
3267 return ERROR_INVALID_PARAMETER;
3268 }
3269
3270 RtlInitUnicodeString (&SubKeyName,
3271 NULL);
3272 RtlInitUnicodeString (&Value,
3273 NULL);
3274 if (lpSubKey != NULL &&
3275 strlen(lpSubKey) != 0)
3276 {
3277 RtlInitAnsiString (&AnsiString,
3278 (LPSTR)lpSubKey);
3279 SubKeyName.Buffer = &SubKeyNameBuffer[0];
3280 SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
3281 RtlAnsiStringToUnicodeString (&SubKeyName,
3282 &AnsiString,
3283 FALSE);
3284 }
3285
3286 if (lpValue != NULL)
3287 {
3288 ValueSize = *lpcbValue * sizeof(WCHAR);
3289 Value.MaximumLength = ValueSize;
3290 Value.Buffer = RtlAllocateHeap (ProcessHeap,
3291 0,
3292 ValueSize);
3293 if (Value.Buffer == NULL)
3294 {
3295 return ERROR_OUTOFMEMORY;
3296 }
3297 }
3298 else
3299 {
3300 ValueSize = 0;
3301 }
3302
3303 ErrorCode = RegQueryValueW (hKey,
3304 (LPCWSTR)SubKeyName.Buffer,
3305 Value.Buffer,
3306 &ValueSize);
3307 if (ErrorCode == ERROR_SUCCESS)
3308 {
3309 Value.Length = ValueSize;
3310 RtlInitAnsiString (&AnsiString,
3311 NULL);
3312 AnsiString.Buffer = lpValue;
3313 AnsiString.MaximumLength = *lpcbValue;
3314 RtlUnicodeStringToAnsiString (&AnsiString,
3315 &Value,
3316 FALSE);
3317 }
3318
3319 *lpcbValue = ValueSize;
3320 if (Value.Buffer != NULL)
3321 {
3322 RtlFreeHeap (ProcessHeap,
3323 0,
3324 Value.Buffer);
3325 }
3326
3327 return ErrorCode;
3328 }
3329
3330
3331 /************************************************************************
3332 * RegQueryValueW
3333 *
3334 * @implemented
3335 */
3336 LONG STDCALL
3337 RegQueryValueW (HKEY hKey,
3338 LPCWSTR lpSubKey,
3339 LPWSTR lpValue,
3340 PLONG lpcbValue)
3341 {
3342 OBJECT_ATTRIBUTES ObjectAttributes;
3343 UNICODE_STRING SubKeyString;
3344 HANDLE KeyHandle;
3345 HANDLE RealKey;
3346 LONG ErrorCode;
3347 BOOL CloseRealKey;
3348 NTSTATUS Status;
3349
3350 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
3351 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
3352
3353 Status = MapDefaultKey (&KeyHandle,
3354 hKey);
3355 if (!NT_SUCCESS(Status))
3356 {
3357 return RtlNtStatusToDosError (Status);
3358 }
3359
3360 if (lpSubKey != NULL &&
3361 wcslen(lpSubKey) != 0)
3362 {
3363 RtlInitUnicodeString (&SubKeyString,
3364 (LPWSTR)lpSubKey);
3365 InitializeObjectAttributes (&ObjectAttributes,
3366 &SubKeyString,
3367 OBJ_CASE_INSENSITIVE,
3368 KeyHandle,
3369 NULL);
3370 Status = NtOpenKey (&RealKey,
3371 KEY_QUERY_VALUE,
3372 &ObjectAttributes);
3373 if (!NT_SUCCESS(Status))
3374 {
3375 ErrorCode = RtlNtStatusToDosError (Status);
3376 goto Cleanup;
3377 }
3378 CloseRealKey = TRUE;
3379 }
3380 else
3381 {
3382 RealKey = hKey;
3383 CloseRealKey = FALSE;
3384 }
3385
3386 ErrorCode = RegQueryValueExW (RealKey,
3387 NULL,
3388 NULL,
3389 NULL,
3390 (LPBYTE)lpValue,
3391 (LPDWORD)lpcbValue);
3392 if (CloseRealKey)
3393 {
3394 NtClose (RealKey);
3395 }
3396
3397 Cleanup:
3398 CloseDefaultKey(KeyHandle);
3399
3400 return ErrorCode;
3401 }
3402
3403
3404 /************************************************************************
3405 * RegReplaceKeyA
3406 *
3407 * @implemented
3408 */
3409 LONG STDCALL
3410 RegReplaceKeyA (HKEY hKey,
3411 LPCSTR lpSubKey,
3412 LPCSTR lpNewFile,
3413 LPCSTR lpOldFile)
3414 {
3415 UNICODE_STRING SubKey;
3416 UNICODE_STRING NewFile;
3417 UNICODE_STRING OldFile;
3418 LONG ErrorCode;
3419
3420 RtlCreateUnicodeStringFromAsciiz (&SubKey,
3421 (PCSZ)lpSubKey);
3422 RtlCreateUnicodeStringFromAsciiz (&OldFile,
3423 (PCSZ)lpOldFile);
3424 RtlCreateUnicodeStringFromAsciiz (&NewFile,
3425 (PCSZ)lpNewFile);
3426
3427 ErrorCode = RegReplaceKeyW (hKey,
3428 SubKey.Buffer,
3429 NewFile.Buffer,
3430 OldFile.Buffer);
3431
3432 RtlFreeUnicodeString (&OldFile);
3433 RtlFreeUnicodeString (&NewFile);
3434 RtlFreeUnicodeString (&SubKey);
3435
3436 return ErrorCode;
3437 }
3438
3439
3440 /************************************************************************
3441 * RegReplaceKeyW
3442 *
3443 * @unimplemented
3444 */
3445 LONG STDCALL
3446 RegReplaceKeyW (HKEY hKey,
3447 LPCWSTR lpSubKey,
3448 LPCWSTR lpNewFile,
3449 LPCWSTR lpOldFile)
3450 {
3451 OBJECT_ATTRIBUTES KeyObjectAttributes;
3452 OBJECT_ATTRIBUTES NewObjectAttributes;
3453 OBJECT_ATTRIBUTES OldObjectAttributes;
3454 UNICODE_STRING SubKeyName;
3455 UNICODE_STRING NewFileName;
3456 UNICODE_STRING OldFileName;
3457 BOOLEAN CloseRealKey;
3458 HANDLE RealKeyHandle;
3459 HANDLE KeyHandle;
3460 NTSTATUS Status;
3461 LONG ErrorCode = ERROR_SUCCESS;
3462
3463 if (hKey == HKEY_PERFORMANCE_DATA)
3464 {
3465 return ERROR_INVALID_HANDLE;
3466 }
3467
3468 Status = MapDefaultKey (&KeyHandle,
3469 hKey);
3470 if (!NT_SUCCESS(Status))
3471 {
3472 return RtlNtStatusToDosError (Status);
3473 }
3474
3475 /* Open the real key */
3476 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
3477 {
3478 RtlInitUnicodeString (&SubKeyName,
3479 (PWSTR)lpSubKey);
3480 InitializeObjectAttributes (&KeyObjectAttributes,
3481 &SubKeyName,
3482 OBJ_CASE_INSENSITIVE,
3483 KeyHandle,
3484 NULL);
3485 Status = NtOpenKey (&RealKeyHandle,
3486 MAXIMUM_ALLOWED,
3487 &KeyObjectAttributes);
3488 if (!NT_SUCCESS(Status))
3489 {
3490 ErrorCode = RtlNtStatusToDosError (Status);
3491 goto Cleanup;
3492 }
3493 CloseRealKey = TRUE;
3494 }
3495 else
3496 {
3497 RealKeyHandle = KeyHandle;
3498 CloseRealKey = FALSE;
3499 }
3500
3501 /* Convert new file name */
3502 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewFile,
3503 &NewFileName,
3504 NULL,
3505 NULL))
3506 {
3507 if (CloseRealKey)
3508 {
3509 NtClose (RealKeyHandle);
3510 }
3511 ErrorCode = ERROR_INVALID_PARAMETER;
3512 goto Cleanup;
3513 }
3514
3515 InitializeObjectAttributes (&NewObjectAttributes,
3516 &NewFileName,
3517 OBJ_CASE_INSENSITIVE,
3518 NULL,
3519 NULL);
3520
3521 /* Convert old file name */
3522 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpOldFile,
3523 &OldFileName,
3524 NULL,
3525 NULL))
3526 {
3527 RtlFreeUnicodeString (&NewFileName);
3528 if (CloseRealKey)
3529 {
3530 NtClose (RealKeyHandle);
3531 }
3532 ErrorCode = ERROR_INVALID_PARAMETER;
3533 goto Cleanup;
3534 }
3535
3536 InitializeObjectAttributes (&OldObjectAttributes,
3537 &OldFileName,
3538 OBJ_CASE_INSENSITIVE,
3539 NULL,
3540 NULL);
3541
3542 Status = NtReplaceKey (&NewObjectAttributes,
3543 RealKeyHandle,
3544 &OldObjectAttributes);
3545
3546 RtlFreeUnicodeString (&OldFileName);
3547 RtlFreeUnicodeString (&NewFileName);
3548
3549 if (CloseRealKey)
3550 {
3551 NtClose (RealKeyHandle);
3552 }
3553
3554 if (!NT_SUCCESS(Status))
3555 {
3556 return RtlNtStatusToDosError (Status);
3557 }
3558
3559 Cleanup:
3560 CloseDefaultKey(KeyHandle);
3561
3562 return ErrorCode;
3563 }
3564
3565
3566 /************************************************************************
3567 * RegRestoreKeyA
3568 *
3569 * @implemented
3570 */
3571 LONG STDCALL
3572 RegRestoreKeyA (HKEY hKey,
3573 LPCSTR lpFile,
3574 DWORD dwFlags)
3575 {
3576 UNICODE_STRING FileName;
3577 LONG ErrorCode;
3578
3579 RtlCreateUnicodeStringFromAsciiz (&FileName,
3580 (PCSZ)lpFile);
3581
3582 ErrorCode = RegRestoreKeyW (hKey,
3583 FileName.Buffer,
3584 dwFlags);
3585
3586 RtlFreeUnicodeString (&FileName);
3587
3588 return ErrorCode;
3589 }
3590
3591
3592 /************************************************************************
3593 * RegRestoreKeyW
3594 *
3595 * @implemented
3596 */
3597 LONG STDCALL
3598 RegRestoreKeyW (HKEY hKey,
3599 LPCWSTR lpFile,
3600 DWORD dwFlags)
3601 {
3602 OBJECT_ATTRIBUTES ObjectAttributes;
3603 IO_STATUS_BLOCK IoStatusBlock;
3604 UNICODE_STRING FileName;
3605 HANDLE FileHandle;
3606 HANDLE KeyHandle;
3607 NTSTATUS Status;
3608
3609 if (hKey == HKEY_PERFORMANCE_DATA)
3610 {
3611 return ERROR_INVALID_HANDLE;
3612 }
3613
3614 Status = MapDefaultKey (&KeyHandle,
3615 hKey);
3616 if (!NT_SUCCESS(Status))
3617 {
3618 return RtlNtStatusToDosError (Status);
3619 }
3620
3621 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
3622 &FileName,
3623 NULL,
3624 NULL))
3625 {
3626 Status = STATUS_INVALID_PARAMETER;
3627 goto Cleanup;
3628 }
3629
3630 InitializeObjectAttributes (&ObjectAttributes,
3631 &FileName,
3632 OBJ_CASE_INSENSITIVE,
3633 NULL,
3634 NULL);
3635
3636 Status = NtOpenFile (&FileHandle,
3637 FILE_GENERIC_READ,
3638 &ObjectAttributes,
3639 &IoStatusBlock,
3640 FILE_SHARE_READ,
3641 FILE_SYNCHRONOUS_IO_NONALERT);
3642 RtlFreeUnicodeString (&FileName);
3643 if (!NT_SUCCESS(Status))
3644 {
3645 goto Cleanup;
3646 }
3647
3648 Status = NtRestoreKey (KeyHandle,
3649 FileHandle,
3650 (ULONG)dwFlags);
3651 NtClose (FileHandle);
3652
3653 Cleanup:
3654 CloseDefaultKey(KeyHandle);
3655
3656 if (!NT_SUCCESS(Status))
3657 {
3658 return RtlNtStatusToDosError (Status);
3659 }
3660
3661 return ERROR_SUCCESS;
3662 }
3663
3664
3665 /************************************************************************
3666 * RegSaveKeyA
3667 *
3668 * @implemented
3669 */
3670 LONG STDCALL
3671 RegSaveKeyA (HKEY hKey,
3672 LPCSTR lpFile,
3673 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
3674 {
3675 UNICODE_STRING FileName;
3676 LONG ErrorCode;
3677
3678 RtlCreateUnicodeStringFromAsciiz (&FileName,
3679 (LPSTR)lpFile);
3680 ErrorCode = RegSaveKeyW (hKey,
3681 FileName.Buffer,
3682 lpSecurityAttributes);
3683 RtlFreeUnicodeString (&FileName);
3684
3685 return ErrorCode;
3686 }
3687
3688
3689 /************************************************************************
3690 * RegSaveKeyW
3691 *
3692 * @implemented
3693 */
3694 LONG STDCALL
3695 RegSaveKeyW (HKEY hKey,
3696 LPCWSTR lpFile,
3697 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
3698 {
3699 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
3700 OBJECT_ATTRIBUTES ObjectAttributes;
3701 UNICODE_STRING FileName;
3702 IO_STATUS_BLOCK IoStatusBlock;
3703 HANDLE FileHandle;
3704 HANDLE KeyHandle;
3705 NTSTATUS Status;
3706
3707 Status = MapDefaultKey (&KeyHandle,
3708 hKey);
3709 if (!NT_SUCCESS(Status))
3710 {
3711 return RtlNtStatusToDosError (Status);
3712 }
3713
3714 if (!RtlDosPathNameToNtPathName_U ((PWSTR)lpFile,
3715 &FileName,
3716 NULL,
3717 NULL))
3718 {
3719 Status = STATUS_INVALID_PARAMETER;
3720 goto Cleanup;
3721 }
3722
3723 if (lpSecurityAttributes != NULL)
3724 {
3725 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
3726 }
3727
3728 InitializeObjectAttributes (&ObjectAttributes,
3729 &FileName,
3730 OBJ_CASE_INSENSITIVE,
3731 NULL,
3732 SecurityDescriptor);
3733 Status = NtCreateFile (&FileHandle,
3734 GENERIC_WRITE | SYNCHRONIZE,
3735 &ObjectAttributes,
3736 &IoStatusBlock,
3737 NULL,
3738 FILE_ATTRIBUTE_NORMAL,
3739 FILE_SHARE_READ,
3740 FILE_CREATE,
3741 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
3742 NULL,
3743 0);
3744 RtlFreeUnicodeString (&FileName);
3745 if (!NT_SUCCESS(Status))
3746 {
3747 goto Cleanup;
3748 }
3749
3750 Status = NtSaveKey (KeyHandle,
3751 FileHandle);
3752 NtClose (FileHandle);
3753
3754 Cleanup:
3755 CloseDefaultKey(KeyHandle);
3756
3757 if (!NT_SUCCESS(Status))
3758 {
3759 return RtlNtStatusToDosError (Status);
3760 }
3761
3762 return ERROR_SUCCESS;
3763 }
3764
3765
3766 /************************************************************************
3767 * RegSetKeySecurity
3768 *
3769 * @implemented
3770 */
3771 LONG STDCALL
3772 RegSetKeySecurity (HKEY hKey,
3773 SECURITY_INFORMATION SecurityInformation,
3774 PSECURITY_DESCRIPTOR pSecurityDescriptor)
3775 {
3776 HANDLE KeyHandle;
3777 NTSTATUS Status;
3778
3779 if (hKey == HKEY_PERFORMANCE_DATA)
3780 {
3781 return ERROR_INVALID_HANDLE;
3782 }
3783
3784 Status = MapDefaultKey (&KeyHandle,
3785 hKey);
3786 if (!NT_SUCCESS(Status))
3787 {
3788 return RtlNtStatusToDosError (Status);
3789 }
3790
3791 Status = NtSetSecurityObject (KeyHandle,
3792 SecurityInformation,
3793 pSecurityDescriptor);
3794
3795 CloseDefaultKey(KeyHandle);
3796
3797 if (!NT_SUCCESS(Status))
3798 {
3799 return RtlNtStatusToDosError (Status);
3800 }
3801
3802 return ERROR_SUCCESS;
3803 }
3804
3805
3806 /************************************************************************
3807 * RegSetValueExA
3808 *
3809 * @implemented
3810 */
3811 LONG STDCALL
3812 RegSetValueExA (HKEY hKey,
3813 LPCSTR lpValueName,
3814 DWORD Reserved,
3815 DWORD dwType,
3816 CONST BYTE* lpData,
3817 DWORD cbData)
3818 {
3819 UNICODE_STRING ValueName;
3820 LPWSTR pValueName;
3821 ANSI_STRING AnsiString;
3822 UNICODE_STRING Data;
3823 LONG ErrorCode;
3824 LPBYTE pData;
3825 DWORD DataSize;
3826
3827 if (lpValueName != NULL &&
3828 strlen(lpValueName) != 0)
3829 {
3830 RtlCreateUnicodeStringFromAsciiz (&ValueName,
3831 (PSTR)lpValueName);
3832 pValueName = (LPWSTR)ValueName.Buffer;
3833 }
3834 else
3835 {
3836 pValueName = NULL;
3837 }
3838
3839 if (((dwType == REG_SZ) ||
3840 (dwType == REG_MULTI_SZ) ||
3841 (dwType == REG_EXPAND_SZ)) &&
3842 (cbData != 0))
3843 {
3844 /* NT adds one if the caller forgot the NULL-termination character */
3845 if (lpData[cbData - 1] != '\0')
3846 {
3847 cbData++;
3848 }
3849
3850 RtlInitAnsiString (&AnsiString,
3851 NULL);
3852 AnsiString.Buffer = (PSTR)lpData;
3853 AnsiString.Length = cbData - 1;
3854 AnsiString.MaximumLength = cbData;
3855 RtlAnsiStringToUnicodeString (&Data,
3856 &AnsiString,
3857 TRUE);
3858 pData = (LPBYTE)Data.Buffer;
3859 DataSize = cbData * sizeof(WCHAR);
3860 }
3861 else
3862 {
3863 RtlInitUnicodeString (&Data,
3864 NULL);
3865 pData = (LPBYTE)lpData;
3866 DataSize = cbData;
3867 }
3868
3869 ErrorCode = RegSetValueExW (hKey,
3870 pValueName,
3871 Reserved,
3872 dwType,
3873 pData,
3874 DataSize);
3875 if (pValueName != NULL)
3876 {
3877 RtlFreeHeap (ProcessHeap,
3878 0,
3879 ValueName.Buffer);
3880 }
3881
3882 if (Data.Buffer != NULL)
3883 {
3884 RtlFreeHeap (ProcessHeap,
3885 0,
3886 Data.Buffer);
3887 }
3888
3889 return ErrorCode;
3890 }
3891
3892
3893 /************************************************************************
3894 * RegSetValueExW
3895 *
3896 * @implemented
3897 */
3898 LONG STDCALL
3899 RegSetValueExW (HKEY hKey,
3900 LPCWSTR lpValueName,
3901 DWORD Reserved,
3902 DWORD dwType,
3903 CONST BYTE* lpData,
3904 DWORD cbData)
3905 {
3906 UNICODE_STRING ValueName;
3907 PUNICODE_STRING pValueName;
3908 HANDLE KeyHandle;
3909 NTSTATUS Status;
3910
3911 Status = MapDefaultKey (&KeyHandle,
3912 hKey);
3913 if (!NT_SUCCESS(Status))
3914 {
3915 return RtlNtStatusToDosError (Status);
3916 }
3917
3918 if (lpValueName != NULL)
3919 {
3920 RtlInitUnicodeString (&ValueName,
3921 lpValueName);
3922 }
3923 else
3924 {
3925 RtlInitUnicodeString (&ValueName, L"");
3926 }
3927 pValueName = &ValueName;
3928
3929 if (((dwType == REG_SZ) ||
3930 (dwType == REG_MULTI_SZ) ||
3931 (dwType == REG_EXPAND_SZ)) &&
3932 (cbData != 0) && (*(((PWCHAR)lpData) + (cbData / sizeof(WCHAR)) - 1) != L'\0'))
3933 {
3934 /* NT adds one if the caller forgot the NULL-termination character */
3935 cbData += sizeof(WCHAR);
3936 }
3937
3938 Status = NtSetValueKey (KeyHandle,
3939 pValueName,
3940 0,
3941 dwType,
3942 (PVOID)lpData,
3943 (ULONG)cbData);
3944
3945 CloseDefaultKey(KeyHandle);
3946
3947 if (!NT_SUCCESS(Status))
3948 {
3949 return RtlNtStatusToDosError (Status);
3950 }
3951
3952 return ERROR_SUCCESS;
3953 }
3954
3955
3956 /************************************************************************
3957 * RegSetValueA
3958 *
3959 * @implemented
3960 */
3961 LONG STDCALL
3962 RegSetValueA (HKEY hKey,
3963 LPCSTR lpSubKey,
3964 DWORD dwType,
3965 LPCSTR lpData,
3966 DWORD cbData)
3967 {
3968 LONG ret;
3969 HKEY hSubKey;
3970
3971 if (dwType != REG_SZ)
3972 {
3973 return ERROR_INVALID_PARAMETER;
3974 }
3975
3976 if (lpSubKey != NULL && lpSubKey[0] != '\0')
3977 {
3978 ret = RegCreateKeyA(hKey,
3979 lpSubKey,
3980 &hSubKey);
3981
3982 if (ret != ERROR_SUCCESS)
3983 {
3984 return ret;
3985 }
3986 }
3987 else
3988 hSubKey = hKey;
3989
3990 ret = RegSetValueExA(hSubKey,
3991 NULL,
3992 0,
3993 REG_SZ,
3994 (CONST BYTE*)lpData,
3995 strlen(lpData) + 1);
3996
3997 if (hSubKey != hKey)
3998 {
3999 RegCloseKey(hSubKey);
4000 }
4001
4002 return ret;
4003 }
4004
4005
4006 /************************************************************************
4007 * RegSetValueW
4008 *
4009 * @implemented
4010 */
4011 LONG STDCALL
4012 RegSetValueW (HKEY hKey,
4013 LPCWSTR lpSubKey,
4014 DWORD dwType,
4015 LPCWSTR lpData,
4016 DWORD cbData)
4017 {
4018 OBJECT_ATTRIBUTES ObjectAttributes;
4019 UNICODE_STRING SubKeyString;
4020 HANDLE KeyHandle;
4021 HANDLE RealKey;
4022 BOOL CloseRealKey;
4023 NTSTATUS Status;
4024 LONG ErrorCode;
4025
4026 Status = MapDefaultKey (&KeyHandle,
4027 hKey);
4028 if (!NT_SUCCESS(Status))
4029 {
4030 return RtlNtStatusToDosError (Status);
4031 }
4032
4033 if ((lpSubKey) && (wcslen(lpSubKey) != 0))
4034 {
4035 RtlInitUnicodeString (&SubKeyString,
4036 (LPWSTR)lpSubKey);
4037 InitializeObjectAttributes (&ObjectAttributes,
4038 &SubKeyString,
4039 OBJ_CASE_INSENSITIVE,
4040 KeyHandle,
4041 NULL);
4042 Status = NtOpenKey (&RealKey,
4043 KEY_SET_VALUE,
4044 &ObjectAttributes);
4045 if (!NT_SUCCESS(Status))
4046 {
4047 ErrorCode = RtlNtStatusToDosError (Status);
4048 goto Cleanup;
4049 }
4050 CloseRealKey = TRUE;
4051 }
4052 else
4053 {
4054 RealKey = hKey;
4055 CloseRealKey = FALSE;
4056 }
4057
4058 ErrorCode = RegSetValueExW (RealKey,
4059 NULL,
4060 0,
4061 dwType,
4062 (LPBYTE)lpData,
4063 cbData);
4064 if (CloseRealKey == TRUE)
4065 {
4066 NtClose (RealKey);
4067 }
4068
4069 Cleanup:
4070 CloseDefaultKey(KeyHandle);
4071
4072 return ErrorCode;
4073 }
4074
4075
4076 /************************************************************************
4077 * RegUnLoadKeyA
4078 *
4079 * @implemented
4080 */
4081 LONG STDCALL
4082 RegUnLoadKeyA (HKEY hKey,
4083 LPCSTR lpSubKey)
4084 {
4085 UNICODE_STRING KeyName;
4086 DWORD ErrorCode;
4087
4088 RtlCreateUnicodeStringFromAsciiz (&KeyName,
4089 (LPSTR)lpSubKey);
4090
4091 ErrorCode = RegUnLoadKeyW (hKey,
4092 KeyName.Buffer);
4093
4094 RtlFreeUnicodeString (&KeyName);
4095
4096 return ErrorCode;
4097 }
4098
4099
4100 /************************************************************************
4101 * RegUnLoadKeyW
4102 *
4103 * @implemented
4104 */
4105 LONG STDCALL
4106 RegUnLoadKeyW (HKEY hKey,
4107 LPCWSTR lpSubKey)
4108 {
4109 OBJECT_ATTRIBUTES ObjectAttributes;
4110 UNICODE_STRING KeyName;
4111 HANDLE KeyHandle;
4112 NTSTATUS Status;
4113
4114 if (hKey == HKEY_PERFORMANCE_DATA)
4115 {
4116 return ERROR_INVALID_HANDLE;
4117 }
4118
4119 Status = MapDefaultKey (&KeyHandle, hKey);
4120 if (!NT_SUCCESS(Status))
4121 {
4122 return RtlNtStatusToDosError (Status);
4123 }
4124
4125 RtlInitUnicodeString (&KeyName,
4126 (LPWSTR)lpSubKey);
4127
4128 InitializeObjectAttributes (&ObjectAttributes,
4129 &KeyName,
4130 OBJ_CASE_INSENSITIVE,
4131 KeyHandle,
4132 NULL);
4133
4134 Status = NtUnloadKey (&ObjectAttributes);
4135
4136 CloseDefaultKey(KeyHandle);
4137
4138 if (!NT_SUCCESS(Status))
4139 {
4140 return RtlNtStatusToDosError (Status);
4141 }
4142
4143 return ERROR_SUCCESS;
4144 }
4145
4146
4147 /************************************************************************
4148 * RegLoadMUIStringW
4149 *
4150 * @unimplemented
4151 */
4152 LONG STDCALL
4153 RegLoadMUIStringW(IN HKEY hKey,
4154 IN LPCWSTR pszValue OPTIONAL,
4155 OUT LPWSTR pszOutBuf,
4156 IN ULONG cbOutBuf,
4157 IN ULONG Reserved,
4158 IN LPCWSTR pszDirectory OPTIONAL)
4159 {
4160 DPRINT1("RegLoadMUIStringW(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4161 hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
4162 return ERROR_CALL_NOT_IMPLEMENTED;
4163 }
4164
4165
4166 /************************************************************************
4167 * RegLoadMUIStringA
4168 *
4169 * @unimplemented
4170 */
4171 LONG STDCALL
4172 RegLoadMUIStringA(IN HKEY hKey,
4173 IN LPCSTR pszValue OPTIONAL,
4174 OUT LPSTR pszOutBuf,
4175 IN ULONG cbOutBuf,
4176 IN ULONG Reserved,
4177 IN LPCSTR pszDirectory OPTIONAL)
4178 {
4179 DPRINT1("RegLoadMUIStringA(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4180 hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
4181 return ERROR_CALL_NOT_IMPLEMENTED;
4182 }
4183
4184
4185 /* EOF */