73fd16ced11ea2b4b07c0911ba6277cd2f3050e6
[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 NTSTATUS Status;
2312
2313 /* check parameters */
2314 if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
2315 {
2316 return ERROR_INVALID_PARAMETER;
2317 }
2318
2319 /*
2320 * Get the user sid from the token
2321 */
2322
2323 ReadTokenSid:
2324 /* determine how much memory we need */
2325 Status = NtQueryInformationToken(hToken,
2326 TokenUser,
2327 NULL,
2328 0,
2329 &RequiredLength);
2330 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
2331 {
2332 /* NOTE - as opposed to all other registry functions windows does indeed
2333 change the last error code in case the caller supplied a invalid
2334 handle for example! */
2335 return RtlNtStatusToDosError (Status);
2336 }
2337
2338 TokenUserData = RtlAllocateHeap(ProcessHeap,
2339 0,
2340 RequiredLength);
2341 if (TokenUserData == NULL)
2342 {
2343 return ERROR_NOT_ENOUGH_MEMORY;
2344 }
2345
2346 /* attempt to read the information */
2347 Status = NtQueryInformationToken(hToken,
2348 TokenUser,
2349 TokenUserData,
2350 RequiredLength,
2351 &RequiredLength);
2352 if (!NT_SUCCESS(Status))
2353 {
2354 RtlFreeHeap(ProcessHeap,
2355 0,
2356 TokenUserData);
2357 if (Status == STATUS_BUFFER_TOO_SMALL)
2358 {
2359 /* the information appears to have changed?! try again */
2360 goto ReadTokenSid;
2361 }
2362
2363 /* NOTE - as opposed to all other registry functions windows does indeed
2364 change the last error code in case the caller supplied a invalid
2365 handle for example! */
2366 return RtlNtStatusToDosError (Status);
2367 }
2368
2369 /*
2370 * Build the absolute path for the user's registry in the form
2371 * "\Registry\User\<SID>_Classes"
2372 */
2373 Status = RtlConvertSidToUnicodeString(&UserSidString,
2374 TokenUserData->User.Sid,
2375 TRUE);
2376
2377 /* we don't need the user data anymore, free it */
2378 RtlFreeHeap(ProcessHeap,
2379 0,
2380 TokenUserData);
2381
2382 if (!NT_SUCCESS(Status))
2383 {
2384 return RtlNtStatusToDosError (Status);
2385 }
2386
2387 /* allocate enough memory for the entire key string */
2388 UserClassesKeyRoot.Length = 0;
2389 UserClassesKeyRoot.MaximumLength = UserSidString.Length +
2390 sizeof(UserClassesKeyPrefix) +
2391 sizeof(UserClassesKeySuffix);
2392 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
2393 0,
2394 UserClassesKeyRoot.MaximumLength);
2395 if (UserClassesKeyRoot.Buffer == NULL)
2396 {
2397 RtlFreeUnicodeString(&UserSidString);
2398 return RtlNtStatusToDosError (Status);
2399 }
2400
2401 /* build the string */
2402 RtlAppendUnicodeToString(&UserClassesKeyRoot,
2403 UserClassesKeyPrefix);
2404 RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
2405 &UserSidString);
2406 RtlAppendUnicodeToString(&UserClassesKeyRoot,
2407 UserClassesKeySuffix);
2408
2409 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
2410
2411 /*
2412 * Open the key
2413 */
2414
2415 InitializeObjectAttributes (&ObjectAttributes,
2416 &UserClassesKeyRoot,
2417 OBJ_CASE_INSENSITIVE,
2418 NULL,
2419 NULL);
2420
2421 Status = NtOpenKey((PHANDLE)phkResult,
2422 samDesired,
2423 &ObjectAttributes);
2424
2425 RtlFreeUnicodeString(&UserSidString);
2426 RtlFreeUnicodeString(&UserClassesKeyRoot);
2427
2428 if (!NT_SUCCESS(Status))
2429 {
2430 return RtlNtStatusToDosError (Status);
2431 }
2432
2433 return ERROR_SUCCESS;
2434 }
2435
2436
2437 /************************************************************************
2438 * RegQueryInfoKeyA
2439 *
2440 * @implemented
2441 */
2442 LONG STDCALL
2443 RegQueryInfoKeyA (HKEY hKey,
2444 LPSTR lpClass,
2445 LPDWORD lpcbClass,
2446 LPDWORD lpReserved,
2447 LPDWORD lpcSubKeys,
2448 LPDWORD lpcbMaxSubKeyLen,
2449 LPDWORD lpcbMaxClassLen,
2450 LPDWORD lpcValues,
2451 LPDWORD lpcbMaxValueNameLen,
2452 LPDWORD lpcbMaxValueLen,
2453 LPDWORD lpcbSecurityDescriptor,
2454 PFILETIME lpftLastWriteTime)
2455 {
2456 WCHAR ClassName[MAX_PATH];
2457 UNICODE_STRING UnicodeString;
2458 ANSI_STRING AnsiString;
2459 LONG ErrorCode;
2460
2461 RtlInitUnicodeString (&UnicodeString,
2462 NULL);
2463 if (lpClass != NULL)
2464 {
2465 UnicodeString.Buffer = &ClassName[0];
2466 UnicodeString.MaximumLength = sizeof(ClassName);
2467 AnsiString.MaximumLength = *lpcbClass;
2468 }
2469
2470 ErrorCode = RegQueryInfoKeyW (hKey,
2471 UnicodeString.Buffer,
2472 lpcbClass,
2473 lpReserved,
2474 lpcSubKeys,
2475 lpcbMaxSubKeyLen,
2476 lpcbMaxClassLen,
2477 lpcValues,
2478 lpcbMaxValueNameLen,
2479 lpcbMaxValueLen,
2480 lpcbSecurityDescriptor,
2481 lpftLastWriteTime);
2482 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
2483 {
2484 AnsiString.Buffer = lpClass;
2485 AnsiString.Length = 0;
2486 UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
2487 RtlUnicodeStringToAnsiString (&AnsiString,
2488 &UnicodeString,
2489 FALSE);
2490 *lpcbClass = AnsiString.Length;
2491 lpClass[AnsiString.Length] = 0;
2492 }
2493
2494 return ErrorCode;
2495 }
2496
2497
2498 /************************************************************************
2499 * RegQueryInfoKeyW
2500 *
2501 * @implemented
2502 */
2503 LONG STDCALL
2504 RegQueryInfoKeyW (HKEY hKey,
2505 LPWSTR lpClass,
2506 LPDWORD lpcbClass,
2507 LPDWORD lpReserved,
2508 LPDWORD lpcSubKeys,
2509 LPDWORD lpcbMaxSubKeyLen,
2510 LPDWORD lpcbMaxClassLen,
2511 LPDWORD lpcValues,
2512 LPDWORD lpcbMaxValueNameLen,
2513 LPDWORD lpcbMaxValueLen,
2514 LPDWORD lpcbSecurityDescriptor,
2515 PFILETIME lpftLastWriteTime)
2516 {
2517 KEY_FULL_INFORMATION FullInfoBuffer;
2518 PKEY_FULL_INFORMATION FullInfo;
2519 ULONG FullInfoSize;
2520 ULONG ClassLength = 0;
2521 HANDLE KeyHandle;
2522 NTSTATUS Status;
2523 ULONG Length;
2524 LONG ErrorCode = ERROR_SUCCESS;
2525
2526 if ((lpClass) && (!lpcbClass))
2527 {
2528 return ERROR_INVALID_PARAMETER;
2529 }
2530
2531 Status = MapDefaultKey (&KeyHandle,
2532 hKey);
2533 if (!NT_SUCCESS(Status))
2534 {
2535 return RtlNtStatusToDosError (Status);
2536 }
2537
2538 if (lpClass != NULL)
2539 {
2540 if (*lpcbClass > 0)
2541 {
2542 ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
2543 }
2544 else
2545 {
2546 ClassLength = 0;
2547 }
2548
2549 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
2550 FullInfo = RtlAllocateHeap (ProcessHeap,
2551 0,
2552 FullInfoSize);
2553 if (FullInfo == NULL)
2554 {
2555 ErrorCode = ERROR_OUTOFMEMORY;
2556 goto Cleanup;
2557 }
2558
2559 FullInfo->ClassLength = ClassLength;
2560 }
2561 else
2562 {
2563 FullInfoSize = sizeof(KEY_FULL_INFORMATION);
2564 FullInfo = &FullInfoBuffer;
2565 FullInfo->ClassLength = 0;
2566 }
2567 FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
2568
2569 Status = NtQueryKey (KeyHandle,
2570 KeyFullInformation,
2571 FullInfo,
2572 FullInfoSize,
2573 &Length);
2574 TRACE("NtQueryKey() returned status 0x%X\n", Status);
2575 if (!NT_SUCCESS(Status))
2576 {
2577 if (lpClass != NULL)
2578 {
2579 RtlFreeHeap (ProcessHeap,
2580 0,
2581 FullInfo);
2582 }
2583
2584 ErrorCode = RtlNtStatusToDosError (Status);
2585 goto Cleanup;
2586 }
2587
2588 TRACE("SubKeys %d\n", FullInfo->SubKeys);
2589 if (lpcSubKeys != NULL)
2590 {
2591 *lpcSubKeys = FullInfo->SubKeys;
2592 }
2593
2594 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
2595 if (lpcbMaxSubKeyLen != NULL)
2596 {
2597 *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
2598 }
2599
2600 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
2601 if (lpcbMaxClassLen != NULL)
2602 {
2603 *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
2604 }
2605
2606 TRACE("Values %lu\n", FullInfo->Values);
2607 if (lpcValues != NULL)
2608 {
2609 *lpcValues = FullInfo->Values;
2610 }
2611
2612 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
2613 if (lpcbMaxValueNameLen != NULL)
2614 {
2615 *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
2616 }
2617
2618 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
2619 if (lpcbMaxValueLen != NULL)
2620 {
2621 *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
2622 }
2623
2624 if (lpcbSecurityDescriptor != NULL)
2625 {
2626 Status = NtQuerySecurityObject(KeyHandle,
2627 OWNER_SECURITY_INFORMATION |
2628 GROUP_SECURITY_INFORMATION |
2629 DACL_SECURITY_INFORMATION,
2630 NULL,
2631 0,
2632 lpcbSecurityDescriptor);
2633 if (!NT_SUCCESS(Status))
2634 {
2635 if (lpClass != NULL)
2636 {
2637 RtlFreeHeap(ProcessHeap,
2638 0,
2639 FullInfo);
2640 }
2641
2642 ErrorCode = RtlNtStatusToDosError (Status);
2643 goto Cleanup;
2644 }
2645 }
2646
2647 if (lpftLastWriteTime != NULL)
2648 {
2649 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
2650 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
2651 }
2652
2653 if (lpClass != NULL)
2654 {
2655 if (FullInfo->ClassLength > ClassLength)
2656 {
2657 ErrorCode = ERROR_BUFFER_OVERFLOW;
2658 }
2659 else
2660 {
2661 RtlCopyMemory (lpClass,
2662 FullInfo->Class,
2663 FullInfo->ClassLength);
2664 *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
2665 lpClass[*lpcbClass] = 0;
2666 }
2667
2668 RtlFreeHeap (ProcessHeap,
2669 0,
2670 FullInfo);
2671 }
2672
2673 Cleanup:
2674 CloseDefaultKey(KeyHandle);
2675
2676 return ErrorCode;
2677 }
2678
2679
2680 /************************************************************************
2681 * RegQueryMultipleValuesA
2682 *
2683 * @implemented
2684 */
2685 LONG STDCALL
2686 RegQueryMultipleValuesA (HKEY hKey,
2687 PVALENTA val_list,
2688 DWORD num_vals,
2689 LPSTR lpValueBuf,
2690 LPDWORD ldwTotsize)
2691 {
2692 ULONG i;
2693 DWORD maxBytes = *ldwTotsize;
2694 LPSTR bufptr = (LPSTR)lpValueBuf;
2695 LONG ErrorCode;
2696
2697 if (maxBytes >= (1024*1024))
2698 return ERROR_TRANSFER_TOO_LONG;
2699
2700 *ldwTotsize = 0;
2701
2702 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
2703 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
2704
2705 for (i = 0; i < num_vals; i++)
2706 {
2707 val_list[i].ve_valuelen = 0;
2708 ErrorCode = RegQueryValueExA (hKey,
2709 val_list[i].ve_valuename,
2710 NULL,
2711 NULL,
2712 NULL,
2713 &val_list[i].ve_valuelen);
2714 if (ErrorCode != ERROR_SUCCESS)
2715 {
2716 return ErrorCode;
2717 }
2718
2719 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
2720 {
2721 ErrorCode = RegQueryValueExA (hKey,
2722 val_list[i].ve_valuename,
2723 NULL,
2724 &val_list[i].ve_type,
2725 (LPBYTE)bufptr,
2726 &val_list[i].ve_valuelen);
2727 if (ErrorCode != ERROR_SUCCESS)
2728 {
2729 return ErrorCode;
2730 }
2731
2732 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
2733
2734 bufptr += val_list[i].ve_valuelen;
2735 }
2736
2737 *ldwTotsize += val_list[i].ve_valuelen;
2738 }
2739
2740 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
2741 }
2742
2743
2744 /************************************************************************
2745 * RegQueryMultipleValuesW
2746 *
2747 * @implemented
2748 */
2749 LONG STDCALL
2750 RegQueryMultipleValuesW (HKEY hKey,
2751 PVALENTW val_list,
2752 DWORD num_vals,
2753 LPWSTR lpValueBuf,
2754 LPDWORD ldwTotsize)
2755 {
2756 ULONG i;
2757 DWORD maxBytes = *ldwTotsize;
2758 LPSTR bufptr = (LPSTR)lpValueBuf;
2759 LONG ErrorCode;
2760
2761 if (maxBytes >= (1024*1024))
2762 return ERROR_TRANSFER_TOO_LONG;
2763
2764 *ldwTotsize = 0;
2765
2766 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
2767 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
2768
2769 for (i = 0; i < num_vals; i++)
2770 {
2771 val_list[i].ve_valuelen = 0;
2772 ErrorCode = RegQueryValueExW (hKey,
2773 val_list[i].ve_valuename,
2774 NULL,
2775 NULL,
2776 NULL,
2777 &val_list[i].ve_valuelen);
2778 if (ErrorCode != ERROR_SUCCESS)
2779 {
2780 return ErrorCode;
2781 }
2782
2783 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
2784 {
2785 ErrorCode = RegQueryValueExW (hKey,
2786 val_list[i].ve_valuename,
2787 NULL,
2788 &val_list[i].ve_type,
2789 (LPBYTE)bufptr,
2790 &val_list[i].ve_valuelen);
2791 if (ErrorCode != ERROR_SUCCESS)
2792 {
2793 return ErrorCode;
2794 }
2795
2796 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
2797
2798 bufptr += val_list[i].ve_valuelen;
2799 }
2800
2801 *ldwTotsize += val_list[i].ve_valuelen;
2802 }
2803
2804 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
2805 }
2806
2807
2808 /************************************************************************
2809 * RegQueryValueExW
2810 *
2811 * @implemented
2812 */
2813 LONG STDCALL
2814 RegQueryValueExW (HKEY hKey,
2815 LPCWSTR lpValueName,
2816 LPDWORD lpReserved,
2817 LPDWORD lpType,
2818 LPBYTE lpData,
2819 LPDWORD lpcbData)
2820 {
2821 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
2822 UNICODE_STRING ValueName;
2823 NTSTATUS Status;
2824 ULONG BufferSize;
2825 ULONG ResultSize;
2826 HANDLE KeyHandle;
2827 LONG ErrorCode = ERROR_SUCCESS;
2828 ULONG MaxCopy = lpcbData != NULL && lpData != NULL ? *lpcbData : 0;
2829
2830 TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
2831 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
2832
2833 Status = MapDefaultKey (&KeyHandle,
2834 hKey);
2835 if (!NT_SUCCESS(Status))
2836 {
2837 return RtlNtStatusToDosError (Status);
2838 }
2839
2840 if (lpData != NULL && lpcbData == NULL)
2841 {
2842 ErrorCode = ERROR_INVALID_PARAMETER;
2843 goto Cleanup;
2844 }
2845
2846 RtlInitUnicodeString (&ValueName,
2847 lpValueName);
2848 BufferSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MaxCopy;
2849 ValueInfo = RtlAllocateHeap (ProcessHeap,
2850 0,
2851 BufferSize);
2852 if (ValueInfo == NULL)
2853 {
2854 ErrorCode = ERROR_OUTOFMEMORY;
2855 goto Cleanup;
2856 }
2857
2858 Status = NtQueryValueKey (KeyHandle,
2859 &ValueName,
2860 KeyValuePartialInformation,
2861 ValueInfo,
2862 BufferSize,
2863 &ResultSize);
2864 TRACE("Status 0x%X\n", Status);
2865 if (Status == STATUS_BUFFER_OVERFLOW)
2866 {
2867 /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
2868 MaxCopy = 0;
2869 ErrorCode = lpData ? ERROR_MORE_DATA : ERROR_SUCCESS;
2870 }
2871 else if (!NT_SUCCESS(Status))
2872 {
2873 ErrorCode = RtlNtStatusToDosError (Status);
2874 MaxCopy = 0;
2875 if (lpcbData != NULL)
2876 {
2877 ResultSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + *lpcbData;
2878 }
2879 }
2880
2881 if (lpType != NULL)
2882 {
2883 *lpType = ValueInfo->Type;
2884 }
2885
2886 if (NT_SUCCESS(Status) && lpData != NULL)
2887 {
2888 RtlMoveMemory (lpData,
2889 ValueInfo->Data,
2890 min(ValueInfo->DataLength, MaxCopy));
2891 }
2892
2893 if ((ValueInfo->Type == REG_SZ) ||
2894 (ValueInfo->Type == REG_MULTI_SZ) ||
2895 (ValueInfo->Type == REG_EXPAND_SZ))
2896 {
2897 if (lpData != NULL && MaxCopy > ValueInfo->DataLength)
2898 {
2899 ((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
2900 }
2901
2902 if (lpcbData != NULL)
2903 {
2904 *lpcbData = (ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]));
2905 TRACE("(string) Returning Size: %lu\n", *lpcbData);
2906 }
2907 }
2908 else
2909 {
2910 if (lpcbData != NULL)
2911 {
2912 *lpcbData = ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
2913 TRACE("(other) Returning Size: %lu\n", *lpcbData);
2914 }
2915 }
2916
2917 TRACE("Type %d Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
2918
2919 RtlFreeHeap (ProcessHeap,
2920 0,
2921 ValueInfo);
2922
2923 Cleanup:
2924 CloseDefaultKey(KeyHandle);
2925
2926 return ErrorCode;
2927 }
2928
2929
2930 /************************************************************************
2931 * RegQueryValueExA
2932 *
2933 * @implemented
2934 */
2935 LONG STDCALL
2936 RegQueryValueExA (HKEY hKey,
2937 LPCSTR lpValueName,
2938 LPDWORD lpReserved,
2939 LPDWORD lpType,
2940 LPBYTE lpData,
2941 LPDWORD lpcbData)
2942 {
2943 UNICODE_STRING ValueName;
2944 UNICODE_STRING ValueData;
2945 ANSI_STRING AnsiString;
2946 LONG ErrorCode;
2947 DWORD Length;
2948 DWORD Type;
2949
2950 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
2951 hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
2952
2953 if (lpData != NULL && lpcbData == NULL)
2954 {
2955 return ERROR_INVALID_PARAMETER;
2956 }
2957
2958 if (lpData)
2959 {
2960 ValueData.Length = 0;
2961 ValueData.MaximumLength = (*lpcbData + 1) * sizeof(WCHAR);
2962 ValueData.Buffer = RtlAllocateHeap (ProcessHeap,
2963 0,
2964 ValueData.MaximumLength);
2965 if (!ValueData.Buffer)
2966 {
2967 return ERROR_OUTOFMEMORY;
2968 }
2969 }
2970 else
2971 {
2972 ValueData.Buffer = NULL;
2973 ValueData.Length = 0;
2974 ValueData.MaximumLength = 0;
2975 }
2976
2977 RtlCreateUnicodeStringFromAsciiz (&ValueName,
2978 (LPSTR)lpValueName);
2979
2980 Length = (lpcbData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
2981 ErrorCode = RegQueryValueExW (hKey,
2982 ValueName.Buffer,
2983 lpReserved,
2984 &Type,
2985 (lpData == NULL) ? NULL : (LPBYTE)ValueData.Buffer,
2986 &Length);
2987 TRACE("ErrorCode %lu\n", ErrorCode);
2988 RtlFreeUnicodeString(&ValueName);
2989
2990 if (ErrorCode == ERROR_SUCCESS ||
2991 ErrorCode == ERROR_MORE_DATA)
2992 {
2993 if (lpType != NULL)
2994 {
2995 *lpType = Type;
2996 }
2997
2998 if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ))
2999 {
3000 if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
3001 {
3002 RtlInitAnsiString(&AnsiString, NULL);
3003 AnsiString.Buffer = (LPSTR)lpData;
3004 AnsiString.MaximumLength = *lpcbData;
3005 ValueData.Length = Length;
3006 ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
3007 RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
3008 }
3009 Length = Length / sizeof(WCHAR);
3010 }
3011 else if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
3012 {
3013 if (*lpcbData < Length)
3014 {
3015 ErrorCode = ERROR_MORE_DATA;
3016 }
3017 else
3018 {
3019 RtlMoveMemory(lpData, ValueData.Buffer, Length);
3020 }
3021 }
3022
3023 if (lpcbData != NULL)
3024 {
3025 *lpcbData = Length;
3026 }
3027 }
3028
3029 if (ValueData.Buffer != NULL)
3030 {
3031 RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
3032 }
3033
3034 return ErrorCode;
3035 }
3036
3037
3038 /************************************************************************
3039 * RegQueryValueA
3040 *
3041 * @implemented
3042 */
3043 LONG STDCALL
3044 RegQueryValueA (HKEY hKey,
3045 LPCSTR lpSubKey,
3046 LPSTR lpValue,
3047 PLONG lpcbValue)
3048 {
3049 WCHAR SubKeyNameBuffer[MAX_PATH+1];
3050 UNICODE_STRING SubKeyName;
3051 UNICODE_STRING Value;
3052 ANSI_STRING AnsiString;
3053 LONG ValueSize;
3054 LONG ErrorCode;
3055
3056 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
3057 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
3058
3059 if (lpValue != NULL &&
3060 lpcbValue == NULL)
3061 {
3062 return ERROR_INVALID_PARAMETER;
3063 }
3064
3065 RtlInitUnicodeString (&SubKeyName,
3066 NULL);
3067 RtlInitUnicodeString (&Value,
3068 NULL);
3069 if (lpSubKey != NULL &&
3070 strlen(lpSubKey) != 0)
3071 {
3072 RtlInitAnsiString (&AnsiString,
3073 (LPSTR)lpSubKey);
3074 SubKeyName.Buffer = &SubKeyNameBuffer[0];
3075 SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
3076 RtlAnsiStringToUnicodeString (&SubKeyName,
3077 &AnsiString,
3078 FALSE);
3079 }
3080
3081 if (lpValue != NULL)
3082 {
3083 ValueSize = *lpcbValue * sizeof(WCHAR);
3084 Value.MaximumLength = ValueSize;
3085 Value.Buffer = RtlAllocateHeap (ProcessHeap,
3086 0,
3087 ValueSize);
3088 if (Value.Buffer == NULL)
3089 {
3090 return ERROR_OUTOFMEMORY;
3091 }
3092 }
3093 else
3094 {
3095 ValueSize = 0;
3096 }
3097
3098 ErrorCode = RegQueryValueW (hKey,
3099 (LPCWSTR)SubKeyName.Buffer,
3100 Value.Buffer,
3101 &ValueSize);
3102 if (ErrorCode == ERROR_SUCCESS)
3103 {
3104 Value.Length = ValueSize;
3105 RtlInitAnsiString (&AnsiString,
3106 NULL);
3107 AnsiString.Buffer = lpValue;
3108 AnsiString.MaximumLength = *lpcbValue;
3109 RtlUnicodeStringToAnsiString (&AnsiString,
3110 &Value,
3111 FALSE);
3112 }
3113
3114 *lpcbValue = ValueSize;
3115 if (Value.Buffer != NULL)
3116 {
3117 RtlFreeHeap (ProcessHeap,
3118 0,
3119 Value.Buffer);
3120 }
3121
3122 return ErrorCode;
3123 }
3124
3125
3126 /************************************************************************
3127 * RegQueryValueW
3128 *
3129 * @implemented
3130 */
3131 LONG STDCALL
3132 RegQueryValueW (HKEY hKey,
3133 LPCWSTR lpSubKey,
3134 LPWSTR lpValue,
3135 PLONG lpcbValue)
3136 {
3137 OBJECT_ATTRIBUTES ObjectAttributes;
3138 UNICODE_STRING SubKeyString;
3139 HANDLE KeyHandle;
3140 HANDLE RealKey;
3141 LONG ErrorCode;
3142 BOOL CloseRealKey;
3143 NTSTATUS Status;
3144
3145 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
3146 hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
3147
3148 Status = MapDefaultKey (&KeyHandle,
3149 hKey);
3150 if (!NT_SUCCESS(Status))
3151 {
3152 return RtlNtStatusToDosError (Status);
3153 }
3154
3155 if (lpSubKey != NULL &&
3156 wcslen(lpSubKey) != 0)
3157 {
3158 RtlInitUnicodeString (&SubKeyString,
3159 (LPWSTR)lpSubKey);
3160 InitializeObjectAttributes (&ObjectAttributes,
3161 &SubKeyString,
3162 OBJ_CASE_INSENSITIVE,
3163 KeyHandle,
3164 NULL);
3165 Status = NtOpenKey (&RealKey,
3166 KEY_QUERY_VALUE,
3167 &ObjectAttributes);
3168 if (!NT_SUCCESS(Status))
3169 {
3170 ErrorCode = RtlNtStatusToDosError (Status);
3171 goto Cleanup;
3172 }
3173 CloseRealKey = TRUE;
3174 }
3175 else
3176 {
3177 RealKey = hKey;
3178 CloseRealKey = FALSE;
3179 }
3180
3181 ErrorCode = RegQueryValueExW (RealKey,
3182 NULL,
3183 NULL,
3184 NULL,
3185 (LPBYTE)lpValue,
3186 (LPDWORD)lpcbValue);
3187 if (CloseRealKey)
3188 {
3189 NtClose (RealKey);
3190 }
3191
3192 Cleanup:
3193 CloseDefaultKey(KeyHandle);
3194
3195 return ErrorCode;
3196 }
3197
3198
3199 /************************************************************************
3200 * RegReplaceKeyA
3201 *
3202 * @implemented
3203 */
3204 LONG STDCALL
3205 RegReplaceKeyA (HKEY hKey,
3206 LPCSTR lpSubKey,
3207 LPCSTR lpNewFile,
3208 LPCSTR lpOldFile)
3209 {
3210 UNICODE_STRING SubKey;
3211 UNICODE_STRING NewFile;
3212 UNICODE_STRING OldFile;
3213 LONG ErrorCode;
3214
3215 RtlCreateUnicodeStringFromAsciiz (&SubKey,
3216 (PCSZ)lpSubKey);
3217 RtlCreateUnicodeStringFromAsciiz (&OldFile,
3218 (PCSZ)lpOldFile);
3219 RtlCreateUnicodeStringFromAsciiz (&NewFile,
3220 (PCSZ)lpNewFile);
3221
3222 ErrorCode = RegReplaceKeyW (hKey,
3223 SubKey.Buffer,
3224 NewFile.Buffer,
3225 OldFile.Buffer);
3226
3227 RtlFreeUnicodeString (&OldFile);
3228 RtlFreeUnicodeString (&NewFile);
3229 RtlFreeUnicodeString (&SubKey);
3230
3231 return ErrorCode;
3232 }
3233
3234
3235 /************************************************************************
3236 * RegReplaceKeyW
3237 *
3238 * @unimplemented
3239 */
3240 LONG STDCALL
3241 RegReplaceKeyW (HKEY hKey,
3242 LPCWSTR lpSubKey,
3243 LPCWSTR lpNewFile,
3244 LPCWSTR lpOldFile)
3245 {
3246 OBJECT_ATTRIBUTES KeyObjectAttributes;
3247 OBJECT_ATTRIBUTES NewObjectAttributes;
3248 OBJECT_ATTRIBUTES OldObjectAttributes;
3249 UNICODE_STRING SubKeyName;
3250 UNICODE_STRING NewFileName;
3251 UNICODE_STRING OldFileName;
3252 BOOLEAN CloseRealKey;
3253 HANDLE RealKeyHandle;
3254 HANDLE KeyHandle;
3255 NTSTATUS Status;
3256 LONG ErrorCode = ERROR_SUCCESS;
3257
3258 if (hKey == HKEY_PERFORMANCE_DATA)
3259 {
3260 return ERROR_INVALID_HANDLE;
3261 }
3262
3263 Status = MapDefaultKey (&KeyHandle,
3264 hKey);
3265 if (!NT_SUCCESS(Status))
3266 {
3267 return RtlNtStatusToDosError (Status);
3268 }
3269
3270 /* Open the real key */
3271 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
3272 {
3273 RtlInitUnicodeString (&SubKeyName,
3274 (PWSTR)lpSubKey);
3275 InitializeObjectAttributes (&KeyObjectAttributes,
3276 &SubKeyName,
3277 OBJ_CASE_INSENSITIVE,
3278 KeyHandle,
3279 NULL);
3280 Status = NtOpenKey (&RealKeyHandle,
3281 MAXIMUM_ALLOWED,
3282 &KeyObjectAttributes);
3283 if (!NT_SUCCESS(Status))
3284 {
3285 ErrorCode = RtlNtStatusToDosError (Status);
3286 goto Cleanup;
3287 }
3288 CloseRealKey = TRUE;
3289 }
3290 else
3291 {
3292 RealKeyHandle = KeyHandle;
3293 CloseRealKey = FALSE;
3294 }
3295
3296 /* Convert new file name */
3297 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewFile,
3298 &NewFileName,
3299 NULL,
3300 NULL))
3301 {
3302 if (CloseRealKey)
3303 {
3304 NtClose (RealKeyHandle);
3305 }
3306 ErrorCode = ERROR_INVALID_PARAMETER;
3307 goto Cleanup;
3308 }
3309
3310 InitializeObjectAttributes (&NewObjectAttributes,
3311 &NewFileName,
3312 OBJ_CASE_INSENSITIVE,
3313 NULL,
3314 NULL);
3315
3316 /* Convert old file name */
3317 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpOldFile,
3318 &OldFileName,
3319 NULL,
3320 NULL))
3321 {
3322 RtlFreeUnicodeString (&NewFileName);
3323 if (CloseRealKey)
3324 {
3325 NtClose (RealKeyHandle);
3326 }
3327 ErrorCode = ERROR_INVALID_PARAMETER;
3328 goto Cleanup;
3329 }
3330
3331 InitializeObjectAttributes (&OldObjectAttributes,
3332 &OldFileName,
3333 OBJ_CASE_INSENSITIVE,
3334 NULL,
3335 NULL);
3336
3337 Status = NtReplaceKey (&NewObjectAttributes,
3338 RealKeyHandle,
3339 &OldObjectAttributes);
3340
3341 RtlFreeUnicodeString (&OldFileName);
3342 RtlFreeUnicodeString (&NewFileName);
3343
3344 if (CloseRealKey)
3345 {
3346 NtClose (RealKeyHandle);
3347 }
3348
3349 if (!NT_SUCCESS(Status))
3350 {
3351 return RtlNtStatusToDosError (Status);
3352 }
3353
3354 Cleanup:
3355 CloseDefaultKey(KeyHandle);
3356
3357 return ErrorCode;
3358 }
3359
3360
3361 /************************************************************************
3362 * RegRestoreKeyA
3363 *
3364 * @implemented
3365 */
3366 LONG STDCALL
3367 RegRestoreKeyA (HKEY hKey,
3368 LPCSTR lpFile,
3369 DWORD dwFlags)
3370 {
3371 UNICODE_STRING FileName;
3372 LONG ErrorCode;
3373
3374 RtlCreateUnicodeStringFromAsciiz (&FileName,
3375 (PCSZ)lpFile);
3376
3377 ErrorCode = RegRestoreKeyW (hKey,
3378 FileName.Buffer,
3379 dwFlags);
3380
3381 RtlFreeUnicodeString (&FileName);
3382
3383 return ErrorCode;
3384 }
3385
3386
3387 /************************************************************************
3388 * RegRestoreKeyW
3389 *
3390 * @implemented
3391 */
3392 LONG STDCALL
3393 RegRestoreKeyW (HKEY hKey,
3394 LPCWSTR lpFile,
3395 DWORD dwFlags)
3396 {
3397 OBJECT_ATTRIBUTES ObjectAttributes;
3398 IO_STATUS_BLOCK IoStatusBlock;
3399 UNICODE_STRING FileName;
3400 HANDLE FileHandle;
3401 HANDLE KeyHandle;
3402 NTSTATUS Status;
3403
3404 if (hKey == HKEY_PERFORMANCE_DATA)
3405 {
3406 return ERROR_INVALID_HANDLE;
3407 }
3408
3409 Status = MapDefaultKey (&KeyHandle,
3410 hKey);
3411 if (!NT_SUCCESS(Status))
3412 {
3413 return RtlNtStatusToDosError (Status);
3414 }
3415
3416 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
3417 &FileName,
3418 NULL,
3419 NULL))
3420 {
3421 Status = STATUS_INVALID_PARAMETER;
3422 goto Cleanup;
3423 }
3424
3425 InitializeObjectAttributes (&ObjectAttributes,
3426 &FileName,
3427 OBJ_CASE_INSENSITIVE,
3428 NULL,
3429 NULL);
3430
3431 Status = NtOpenFile (&FileHandle,
3432 FILE_GENERIC_READ,
3433 &ObjectAttributes,
3434 &IoStatusBlock,
3435 FILE_SHARE_READ,
3436 FILE_SYNCHRONOUS_IO_NONALERT);
3437 RtlFreeUnicodeString (&FileName);
3438 if (!NT_SUCCESS(Status))
3439 {
3440 goto Cleanup;
3441 }
3442
3443 Status = NtRestoreKey (KeyHandle,
3444 FileHandle,
3445 (ULONG)dwFlags);
3446 NtClose (FileHandle);
3447
3448 Cleanup:
3449 CloseDefaultKey(KeyHandle);
3450
3451 if (!NT_SUCCESS(Status))
3452 {
3453 return RtlNtStatusToDosError (Status);
3454 }
3455
3456 return ERROR_SUCCESS;
3457 }
3458
3459
3460 /************************************************************************
3461 * RegSaveKeyA
3462 *
3463 * @implemented
3464 */
3465 LONG STDCALL
3466 RegSaveKeyA (HKEY hKey,
3467 LPCSTR lpFile,
3468 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
3469 {
3470 UNICODE_STRING FileName;
3471 LONG ErrorCode;
3472
3473 RtlCreateUnicodeStringFromAsciiz (&FileName,
3474 (LPSTR)lpFile);
3475 ErrorCode = RegSaveKeyW (hKey,
3476 FileName.Buffer,
3477 lpSecurityAttributes);
3478 RtlFreeUnicodeString (&FileName);
3479
3480 return ErrorCode;
3481 }
3482
3483
3484 /************************************************************************
3485 * RegSaveKeyW
3486 *
3487 * @implemented
3488 */
3489 LONG STDCALL
3490 RegSaveKeyW (HKEY hKey,
3491 LPCWSTR lpFile,
3492 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
3493 {
3494 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
3495 OBJECT_ATTRIBUTES ObjectAttributes;
3496 UNICODE_STRING FileName;
3497 IO_STATUS_BLOCK IoStatusBlock;
3498 HANDLE FileHandle;
3499 HANDLE KeyHandle;
3500 NTSTATUS Status;
3501
3502 Status = MapDefaultKey (&KeyHandle,
3503 hKey);
3504 if (!NT_SUCCESS(Status))
3505 {
3506 return RtlNtStatusToDosError (Status);
3507 }
3508
3509 if (!RtlDosPathNameToNtPathName_U ((PWSTR)lpFile,
3510 &FileName,
3511 NULL,
3512 NULL))
3513 {
3514 Status = STATUS_INVALID_PARAMETER;
3515 goto Cleanup;
3516 }
3517
3518 if (lpSecurityAttributes != NULL)
3519 {
3520 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
3521 }
3522
3523 InitializeObjectAttributes (&ObjectAttributes,
3524 &FileName,
3525 OBJ_CASE_INSENSITIVE,
3526 NULL,
3527 SecurityDescriptor);
3528 Status = NtCreateFile (&FileHandle,
3529 GENERIC_WRITE | SYNCHRONIZE,
3530 &ObjectAttributes,
3531 &IoStatusBlock,
3532 NULL,
3533 FILE_ATTRIBUTE_NORMAL,
3534 FILE_SHARE_READ,
3535 FILE_CREATE,
3536 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
3537 NULL,
3538 0);
3539 RtlFreeUnicodeString (&FileName);
3540 if (!NT_SUCCESS(Status))
3541 {
3542 goto Cleanup;
3543 }
3544
3545 Status = NtSaveKey (KeyHandle,
3546 FileHandle);
3547 NtClose (FileHandle);
3548
3549 Cleanup:
3550 CloseDefaultKey(KeyHandle);
3551
3552 if (!NT_SUCCESS(Status))
3553 {
3554 return RtlNtStatusToDosError (Status);
3555 }
3556
3557 return ERROR_SUCCESS;
3558 }
3559
3560
3561 /************************************************************************
3562 * RegSetKeySecurity
3563 *
3564 * @implemented
3565 */
3566 LONG STDCALL
3567 RegSetKeySecurity (HKEY hKey,
3568 SECURITY_INFORMATION SecurityInformation,
3569 PSECURITY_DESCRIPTOR pSecurityDescriptor)
3570 {
3571 HANDLE KeyHandle;
3572 NTSTATUS Status;
3573
3574 if (hKey == HKEY_PERFORMANCE_DATA)
3575 {
3576 return ERROR_INVALID_HANDLE;
3577 }
3578
3579 Status = MapDefaultKey (&KeyHandle,
3580 hKey);
3581 if (!NT_SUCCESS(Status))
3582 {
3583 return RtlNtStatusToDosError (Status);
3584 }
3585
3586 Status = NtSetSecurityObject (KeyHandle,
3587 SecurityInformation,
3588 pSecurityDescriptor);
3589
3590 CloseDefaultKey(KeyHandle);
3591
3592 if (!NT_SUCCESS(Status))
3593 {
3594 return RtlNtStatusToDosError (Status);
3595 }
3596
3597 return ERROR_SUCCESS;
3598 }
3599
3600
3601 /************************************************************************
3602 * RegSetValueExA
3603 *
3604 * @implemented
3605 */
3606 LONG STDCALL
3607 RegSetValueExA (HKEY hKey,
3608 LPCSTR lpValueName,
3609 DWORD Reserved,
3610 DWORD dwType,
3611 CONST BYTE* lpData,
3612 DWORD cbData)
3613 {
3614 UNICODE_STRING ValueName;
3615 LPWSTR pValueName;
3616 ANSI_STRING AnsiString;
3617 UNICODE_STRING Data;
3618 LONG ErrorCode;
3619 LPBYTE pData;
3620 DWORD DataSize;
3621
3622 if (lpValueName != NULL &&
3623 strlen(lpValueName) != 0)
3624 {
3625 RtlCreateUnicodeStringFromAsciiz (&ValueName,
3626 (PSTR)lpValueName);
3627 pValueName = (LPWSTR)ValueName.Buffer;
3628 }
3629 else
3630 {
3631 pValueName = NULL;
3632 }
3633
3634 if (((dwType == REG_SZ) ||
3635 (dwType == REG_MULTI_SZ) ||
3636 (dwType == REG_EXPAND_SZ)) &&
3637 (cbData != 0))
3638 {
3639 /* NT adds one if the caller forgot the NULL-termination character */
3640 if (lpData[cbData - 1] != '\0')
3641 {
3642 cbData++;
3643 }
3644
3645 RtlInitAnsiString (&AnsiString,
3646 NULL);
3647 AnsiString.Buffer = (PSTR)lpData;
3648 AnsiString.Length = cbData - 1;
3649 AnsiString.MaximumLength = cbData;
3650 RtlAnsiStringToUnicodeString (&Data,
3651 &AnsiString,
3652 TRUE);
3653 pData = (LPBYTE)Data.Buffer;
3654 DataSize = cbData * sizeof(WCHAR);
3655 }
3656 else
3657 {
3658 RtlInitUnicodeString (&Data,
3659 NULL);
3660 pData = (LPBYTE)lpData;
3661 DataSize = cbData;
3662 }
3663
3664 ErrorCode = RegSetValueExW (hKey,
3665 pValueName,
3666 Reserved,
3667 dwType,
3668 pData,
3669 DataSize);
3670 if (pValueName != NULL)
3671 {
3672 RtlFreeHeap (ProcessHeap,
3673 0,
3674 ValueName.Buffer);
3675 }
3676
3677 if (Data.Buffer != NULL)
3678 {
3679 RtlFreeHeap (ProcessHeap,
3680 0,
3681 Data.Buffer);
3682 }
3683
3684 return ErrorCode;
3685 }
3686
3687
3688 /************************************************************************
3689 * RegSetValueExW
3690 *
3691 * @implemented
3692 */
3693 LONG STDCALL
3694 RegSetValueExW (HKEY hKey,
3695 LPCWSTR lpValueName,
3696 DWORD Reserved,
3697 DWORD dwType,
3698 CONST BYTE* lpData,
3699 DWORD cbData)
3700 {
3701 UNICODE_STRING ValueName;
3702 PUNICODE_STRING pValueName;
3703 HANDLE KeyHandle;
3704 NTSTATUS Status;
3705
3706 Status = MapDefaultKey (&KeyHandle,
3707 hKey);
3708 if (!NT_SUCCESS(Status))
3709 {
3710 return RtlNtStatusToDosError (Status);
3711 }
3712
3713 if (lpValueName != NULL)
3714 {
3715 RtlInitUnicodeString (&ValueName,
3716 lpValueName);
3717 }
3718 else
3719 {
3720 RtlInitUnicodeString (&ValueName, L"");
3721 }
3722 pValueName = &ValueName;
3723
3724 if (((dwType == REG_SZ) ||
3725 (dwType == REG_MULTI_SZ) ||
3726 (dwType == REG_EXPAND_SZ)) &&
3727 (cbData != 0) && (*(((PWCHAR)lpData) + (cbData / sizeof(WCHAR)) - 1) != L'\0'))
3728 {
3729 /* NT adds one if the caller forgot the NULL-termination character */
3730 cbData += sizeof(WCHAR);
3731 }
3732
3733 Status = NtSetValueKey (KeyHandle,
3734 pValueName,
3735 0,
3736 dwType,
3737 (PVOID)lpData,
3738 (ULONG)cbData);
3739
3740 CloseDefaultKey(KeyHandle);
3741
3742 if (!NT_SUCCESS(Status))
3743 {
3744 return RtlNtStatusToDosError (Status);
3745 }
3746
3747 return ERROR_SUCCESS;
3748 }
3749
3750
3751 /************************************************************************
3752 * RegSetValueA
3753 *
3754 * @implemented
3755 */
3756 LONG STDCALL
3757 RegSetValueA (HKEY hKey,
3758 LPCSTR lpSubKey,
3759 DWORD dwType,
3760 LPCSTR lpData,
3761 DWORD cbData)
3762 {
3763 LONG ret;
3764 HKEY hSubKey;
3765
3766 if (dwType != REG_SZ)
3767 {
3768 return ERROR_INVALID_PARAMETER;
3769 }
3770
3771 if (lpSubKey != NULL && lpSubKey[0] != '\0')
3772 {
3773 ret = RegCreateKeyA(hKey,
3774 lpSubKey,
3775 &hSubKey);
3776
3777 if (ret != ERROR_SUCCESS)
3778 {
3779 return ret;
3780 }
3781 }
3782 else
3783 hSubKey = hKey;
3784
3785 ret = RegSetValueExA(hSubKey,
3786 NULL,
3787 0,
3788 REG_SZ,
3789 (CONST BYTE*)lpData,
3790 strlen(lpData) + 1);
3791
3792 if (hSubKey != hKey)
3793 {
3794 RegCloseKey(hSubKey);
3795 }
3796
3797 return ret;
3798 }
3799
3800
3801 /************************************************************************
3802 * RegSetValueW
3803 *
3804 * @implemented
3805 */
3806 LONG STDCALL
3807 RegSetValueW (HKEY hKey,
3808 LPCWSTR lpSubKey,
3809 DWORD dwType,
3810 LPCWSTR lpData,
3811 DWORD cbData)
3812 {
3813 OBJECT_ATTRIBUTES ObjectAttributes;
3814 UNICODE_STRING SubKeyString;
3815 HANDLE KeyHandle;
3816 HANDLE RealKey;
3817 BOOL CloseRealKey;
3818 NTSTATUS Status;
3819 LONG ErrorCode;
3820
3821 Status = MapDefaultKey (&KeyHandle,
3822 hKey);
3823 if (!NT_SUCCESS(Status))
3824 {
3825 return RtlNtStatusToDosError (Status);
3826 }
3827
3828 if ((lpSubKey) && (wcslen(lpSubKey) != 0))
3829 {
3830 RtlInitUnicodeString (&SubKeyString,
3831 (LPWSTR)lpSubKey);
3832 InitializeObjectAttributes (&ObjectAttributes,
3833 &SubKeyString,
3834 OBJ_CASE_INSENSITIVE,
3835 KeyHandle,
3836 NULL);
3837 Status = NtOpenKey (&RealKey,
3838 KEY_SET_VALUE,
3839 &ObjectAttributes);
3840 if (!NT_SUCCESS(Status))
3841 {
3842 ErrorCode = RtlNtStatusToDosError (Status);
3843 goto Cleanup;
3844 }
3845 CloseRealKey = TRUE;
3846 }
3847 else
3848 {
3849 RealKey = hKey;
3850 CloseRealKey = FALSE;
3851 }
3852
3853 ErrorCode = RegSetValueExW (RealKey,
3854 NULL,
3855 0,
3856 dwType,
3857 (LPBYTE)lpData,
3858 cbData);
3859 if (CloseRealKey == TRUE)
3860 {
3861 NtClose (RealKey);
3862 }
3863
3864 Cleanup:
3865 CloseDefaultKey(KeyHandle);
3866
3867 return ErrorCode;
3868 }
3869
3870
3871 /************************************************************************
3872 * RegUnLoadKeyA
3873 *
3874 * @implemented
3875 */
3876 LONG STDCALL
3877 RegUnLoadKeyA (HKEY hKey,
3878 LPCSTR lpSubKey)
3879 {
3880 UNICODE_STRING KeyName;
3881 DWORD ErrorCode;
3882
3883 RtlCreateUnicodeStringFromAsciiz (&KeyName,
3884 (LPSTR)lpSubKey);
3885
3886 ErrorCode = RegUnLoadKeyW (hKey,
3887 KeyName.Buffer);
3888
3889 RtlFreeUnicodeString (&KeyName);
3890
3891 return ErrorCode;
3892 }
3893
3894
3895 /************************************************************************
3896 * RegUnLoadKeyW
3897 *
3898 * @implemented
3899 */
3900 LONG STDCALL
3901 RegUnLoadKeyW (HKEY hKey,
3902 LPCWSTR lpSubKey)
3903 {
3904 OBJECT_ATTRIBUTES ObjectAttributes;
3905 UNICODE_STRING KeyName;
3906 HANDLE KeyHandle;
3907 NTSTATUS Status;
3908
3909 if (hKey == HKEY_PERFORMANCE_DATA)
3910 {
3911 return ERROR_INVALID_HANDLE;
3912 }
3913
3914 Status = MapDefaultKey (&KeyHandle, hKey);
3915 if (!NT_SUCCESS(Status))
3916 {
3917 return RtlNtStatusToDosError (Status);
3918 }
3919
3920 RtlInitUnicodeString (&KeyName,
3921 (LPWSTR)lpSubKey);
3922
3923 InitializeObjectAttributes (&ObjectAttributes,
3924 &KeyName,
3925 OBJ_CASE_INSENSITIVE,
3926 KeyHandle,
3927 NULL);
3928
3929 Status = NtUnloadKey (&ObjectAttributes);
3930
3931 CloseDefaultKey(KeyHandle);
3932
3933 if (!NT_SUCCESS(Status))
3934 {
3935 return RtlNtStatusToDosError (Status);
3936 }
3937
3938 return ERROR_SUCCESS;
3939 }
3940
3941
3942 /************************************************************************
3943 * RegLoadMUIStringW
3944 *
3945 * @unimplemented
3946 */
3947 LONG STDCALL
3948 RegLoadMUIStringW(IN HKEY hKey,
3949 IN LPCWSTR pszValue OPTIONAL,
3950 OUT LPWSTR pszOutBuf,
3951 IN ULONG cbOutBuf,
3952 IN ULONG Reserved,
3953 IN LPCWSTR pszDirectory OPTIONAL)
3954 {
3955 DPRINT1("RegLoadMUIStringW(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
3956 hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
3957 return ERROR_CALL_NOT_IMPLEMENTED;
3958 }
3959
3960
3961 /************************************************************************
3962 * RegLoadMUIStringA
3963 *
3964 * @unimplemented
3965 */
3966 LONG STDCALL
3967 RegLoadMUIStringA(IN HKEY hKey,
3968 IN LPCSTR pszValue OPTIONAL,
3969 OUT LPSTR pszOutBuf,
3970 IN ULONG cbOutBuf,
3971 IN ULONG Reserved,
3972 IN LPCSTR pszDirectory OPTIONAL)
3973 {
3974 DPRINT1("RegLoadMUIStringA(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
3975 hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
3976 return ERROR_CALL_NOT_IMPLEMENTED;
3977 }
3978
3979
3980 /* EOF */