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