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