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