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