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