update for HEAD-2003091401
[reactos.git] / lib / ntdll / rtl / registry.c
1 /* $Id$
2  *
3  * COPYRIGHT:         See COPYING in the top level directory
4  * PROJECT:           ReactOS kernel
5  * PURPOSE:           Rtl registry functions
6  * FILE:              lib/ntdll/rtl/registry.c
7  * PROGRAMER:         Eric Kohl
8  * REVISION HISTORY:
9  *                    2000/08/11: Created
10  */
11
12 /*
13  * TODO:
14  *   - finish RtlQueryRegistryValues()
15  *      - support RTL_QUERY_REGISTRY_DELETE
16  *
17  *   - finish RtlFormatCurrentUserKeyPath()
18  */
19
20 /* INCLUDES ****************************************************************/
21
22 #include <ddk/ntddk.h>
23 #include <ntdll/rtl.h>
24 #include <ntdll/registry.h>
25 #include <ntos/minmax.h>
26
27 #define NDEBUG
28 #include <ntdll/ntdll.h>
29
30
31 /* FUNCTIONS ***************************************************************/
32
33 /*
34  * @implemented
35  */
36 NTSTATUS STDCALL
37 RtlCheckRegistryKey(IN ULONG RelativeTo,
38                     IN PWSTR Path)
39 {
40   HANDLE KeyHandle;
41   NTSTATUS Status;
42
43   Status = RtlpGetRegistryHandle(RelativeTo,
44                                  Path,
45                                  FALSE,
46                                  &KeyHandle);
47   if (!NT_SUCCESS(Status))
48     return(Status);
49
50   NtClose(KeyHandle);
51
52   return(STATUS_SUCCESS);
53 }
54
55
56 /*
57  * @implemented
58  */
59 NTSTATUS STDCALL
60 RtlCreateRegistryKey(IN ULONG RelativeTo,
61                      IN PWSTR Path)
62 {
63   HANDLE KeyHandle;
64   NTSTATUS Status;
65
66   Status = RtlpGetRegistryHandle(RelativeTo,
67                                  Path,
68                                  TRUE,
69                                  &KeyHandle);
70   if (!NT_SUCCESS(Status))
71     return(Status);
72
73   NtClose(KeyHandle);
74
75   return(STATUS_SUCCESS);
76 }
77
78
79 /*
80  * @implemented
81  */
82 NTSTATUS STDCALL
83 RtlDeleteRegistryValue(IN ULONG RelativeTo,
84                        IN PCWSTR Path,
85                        IN PCWSTR ValueName)
86 {
87   HANDLE KeyHandle;
88   NTSTATUS Status;
89   UNICODE_STRING Name;
90
91   Status = RtlpGetRegistryHandle(RelativeTo,
92                                  (PWSTR)Path,
93                                  FALSE,
94                                  &KeyHandle);
95   if (!NT_SUCCESS(Status))
96     return(Status);
97
98   RtlInitUnicodeString(&Name,
99                        ValueName);
100
101   Status = NtDeleteValueKey(KeyHandle,
102                             &Name);
103
104   NtClose(KeyHandle);
105
106   return(Status);
107 }
108
109
110 /*
111  * @unimplemented
112  */
113 NTSTATUS STDCALL
114 RtlFormatCurrentUserKeyPath(PUNICODE_STRING KeyPath)
115 {
116   /* FIXME: !!! */
117 #if 0
118     RtlCreateUnicodeString(KeyPath,
119                          L"\\Registry\\User\\.Default");
120 #endif
121   return(STATUS_SUCCESS);
122 }
123
124
125 /*
126  * @implemented
127  */
128 NTSTATUS STDCALL
129 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess,
130                    OUT PHANDLE KeyHandle)
131 {
132   OBJECT_ATTRIBUTES ObjectAttributes;
133   NTSTATUS Status;
134   UNICODE_STRING KeyPath = UNICODE_STRING_INITIALIZER(L"\\Registry\\User\\.Default");
135
136   Status = RtlFormatCurrentUserKeyPath(&KeyPath);
137   if (NT_SUCCESS(Status))
138     {
139       InitializeObjectAttributes(&ObjectAttributes,
140                                  &KeyPath,
141                                  OBJ_CASE_INSENSITIVE,
142                                  NULL,
143                                  NULL);
144       Status = NtOpenKey(KeyHandle,
145                          DesiredAccess,
146                          &ObjectAttributes);
147       if (NT_SUCCESS(Status)) {
148          RtlFreeUnicodeString(&KeyPath);
149              return(STATUS_SUCCESS);
150       }
151     }
152   InitializeObjectAttributes(&ObjectAttributes,
153                              &KeyPath,
154                              OBJ_CASE_INSENSITIVE,
155                              NULL,
156                              NULL);
157   Status = NtOpenKey(KeyHandle,
158                      DesiredAccess,
159                      &ObjectAttributes);
160   RtlFreeUnicodeString(&KeyPath);
161   return(Status);
162 }
163
164
165 /*
166  * @unimplemented
167  */
168 NTSTATUS STDCALL
169 RtlQueryRegistryValues(IN ULONG RelativeTo,
170                        IN PCWSTR Path,
171                        IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
172                        IN PVOID Context,
173                        IN PVOID Environment)
174 {
175   NTSTATUS Status;
176   HANDLE BaseKeyHandle;
177   HANDLE CurrentKeyHandle;
178   PRTL_QUERY_REGISTRY_TABLE QueryEntry;
179   OBJECT_ATTRIBUTES ObjectAttributes;
180   UNICODE_STRING KeyName;
181   PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
182   PKEY_VALUE_FULL_INFORMATION FullValueInfo;
183   ULONG BufferSize;
184   ULONG ResultSize;
185   ULONG Index;
186   ULONG StringLen;
187   ULONG ValueNameSize;
188   PWSTR StringPtr;
189   PWSTR ExpandBuffer;
190   PWSTR ValueName;
191   UNICODE_STRING EnvValue;
192   UNICODE_STRING EnvExpandedValue;
193
194   DPRINT("RtlQueryRegistryValues() called\n");
195
196   Status = RtlpGetRegistryHandle(RelativeTo,
197                                  (PWSTR)Path,
198                                  FALSE,
199                                  &BaseKeyHandle);
200   if (!NT_SUCCESS(Status))
201     {
202       DPRINT("RtlpGetRegistryHandle() failed (Status %lx)\n", Status);
203       return(Status);
204     }
205
206   CurrentKeyHandle = BaseKeyHandle;
207   QueryEntry = QueryTable;
208   while ((QueryEntry->QueryRoutine != NULL) ||
209          (QueryEntry->Name != NULL))
210     {
211       if (((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY)) != 0) &&
212           (BaseKeyHandle != CurrentKeyHandle))
213         {
214           NtClose(CurrentKeyHandle);
215           CurrentKeyHandle = BaseKeyHandle;
216         }
217
218       if (QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY)
219         {
220           DPRINT("Open new subkey: %S\n", QueryEntry->Name);
221
222           RtlInitUnicodeString(&KeyName,
223                                QueryEntry->Name);
224           InitializeObjectAttributes(&ObjectAttributes,
225                                      &KeyName,
226                                      OBJ_CASE_INSENSITIVE,
227                                      BaseKeyHandle,
228                                      NULL);
229           Status = NtOpenKey(&CurrentKeyHandle,
230                              KEY_ALL_ACCESS,
231                              &ObjectAttributes);
232           if (!NT_SUCCESS(Status))
233             break;
234         }
235       else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DIRECT)
236         {
237           DPRINT("Query value directly: %S\n", QueryEntry->Name);
238
239           RtlInitUnicodeString(&KeyName,
240                                QueryEntry->Name);
241
242           BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
243           ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
244                                       0,
245                                       BufferSize);
246           if (ValueInfo == NULL)
247             {
248               Status = STATUS_NO_MEMORY;
249               break;
250             }
251
252           Status = NtQueryValueKey(CurrentKeyHandle,
253                                    &KeyName,
254                                    KeyValuePartialInformation,
255                                    ValueInfo,
256                                    BufferSize,
257                                    &ResultSize);
258           if (!NT_SUCCESS(Status))
259             {
260               if (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED)
261                 {
262                   RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
263                   Status = STATUS_OBJECT_NAME_NOT_FOUND;
264                   break;
265                 }
266         
267               if (QueryEntry->DefaultType == REG_SZ)
268                 {
269                   PUNICODE_STRING ValueString;
270                   PUNICODE_STRING SourceString;
271
272                   SourceString = (PUNICODE_STRING)QueryEntry->DefaultData;
273                   ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
274                   if (ValueString->Buffer == NULL)
275                     {
276                       ValueString->Length = SourceString->Length;
277                       ValueString->MaximumLength = SourceString->MaximumLength;
278                       ValueString->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
279                                                             0,
280                                                             ValueString->MaximumLength);
281                       if (!ValueString->Buffer)
282                         break;
283                       ValueString->Buffer[0] = 0;
284                       memcpy(ValueString->Buffer,
285                              SourceString->Buffer,
286                              SourceString->MaximumLength);
287                     }
288                   else
289                     {
290                       ValueString->Length = min(SourceString->Length,
291                                                 ValueString->MaximumLength - sizeof(WCHAR));
292                       memcpy(ValueString->Buffer,
293                              SourceString->Buffer,
294                              ValueString->Length);
295                       ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
296                     }
297                 }
298               else
299                 {
300                   memcpy(QueryEntry->EntryContext,
301                          QueryEntry->DefaultData,
302                          QueryEntry->DefaultLength);
303                 }
304               Status = STATUS_SUCCESS;
305             }
306           else
307             {
308               if ((ValueInfo->Type == REG_SZ) ||
309                   (ValueInfo->Type == REG_MULTI_SZ) ||
310                   (ValueInfo->Type == REG_EXPAND_SZ && (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND)))
311                 {
312                   PUNICODE_STRING ValueString;
313
314                   ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
315                   if (ValueString->Buffer == NULL)
316                     {
317                       ValueString->MaximumLength = ValueInfo->DataLength;
318                       ValueString->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
319                                                             0,
320                                                             ValueString->MaximumLength);
321                       if (ValueString->Buffer == NULL)
322                         {
323                           Status = STATUS_INSUFFICIENT_RESOURCES;
324                           break;
325                         }
326                       ValueString->Buffer[0] = 0;
327                      }
328                   ValueString->Length = min(ValueInfo->DataLength,
329                                             ValueString->MaximumLength) - sizeof(WCHAR);
330                   memcpy(ValueString->Buffer,
331                          ValueInfo->Data,
332                          ValueString->Length);
333                   ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
334                 }
335               else if (ValueInfo->Type == REG_EXPAND_SZ)
336                 {
337                   PUNICODE_STRING ValueString;
338
339                   DPRINT("Expand REG_EXPAND_SZ type\n");
340
341                   ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
342
343                   ExpandBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
344                                                  0,
345                                                  ValueInfo->DataLength * 2);
346                   if (ExpandBuffer == NULL)
347                     {
348                       Status = STATUS_NO_MEMORY;
349                       break;
350                     }
351
352                   RtlInitUnicodeString(&EnvValue,
353                                        (PWSTR)ValueInfo->Data);
354                   EnvExpandedValue.Length = 0;
355                   EnvExpandedValue.MaximumLength = ValueInfo->DataLength * 2;
356                   EnvExpandedValue.Buffer = ExpandBuffer;
357                   *ExpandBuffer = 0;
358
359                   RtlExpandEnvironmentStrings_U(Environment,
360                                                 &EnvValue,
361                                                 &EnvExpandedValue,
362                                                 &StringLen);
363
364                   if (ValueString->Buffer == NULL)
365                     {
366                       ValueString->MaximumLength = EnvExpandedValue.Length + sizeof(WCHAR);
367                       ValueString->Length = EnvExpandedValue.Length;
368                       ValueString->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
369                                                             0,
370                                                             ValueString->MaximumLength);
371                       if (ValueString->Buffer == NULL)
372                         {
373                           Status = STATUS_INSUFFICIENT_RESOURCES;
374                           break;
375                         }
376                     }
377                   else
378                     {
379                       ValueString->Length = min(EnvExpandedValue.Length,
380                                                 ValueString->MaximumLength - sizeof(WCHAR));
381                     }
382
383                   memcpy(ValueString->Buffer,
384                          EnvExpandedValue.Buffer,
385                          ValueString->Length);
386                   ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
387
388                   RtlFreeHeap(RtlGetProcessHeap(),
389                               0,
390                               ExpandBuffer);
391                 }
392               else
393                 {
394                   memcpy(QueryEntry->EntryContext,
395                          ValueInfo->Data,
396                          ValueInfo->DataLength);
397                 }
398             }
399
400           if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
401             {
402               DPRINT1("FIXME: Delete value: %S\n", QueryEntry->Name);
403
404             }
405
406           RtlFreeHeap(RtlGetProcessHeap(),
407                       0,
408                       ValueInfo);
409         }
410       else
411         {
412           DPRINT("Query value via query routine: %S\n", QueryEntry->Name);
413           if (QueryEntry->Name != NULL)
414             {
415               RtlInitUnicodeString(&KeyName,
416                                    QueryEntry->Name);
417
418               BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
419               ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
420                                           0,
421                                           BufferSize);
422               if (ValueInfo == NULL)
423                 {
424                   Status = STATUS_NO_MEMORY;
425                   break;
426                 }
427
428               Status = NtQueryValueKey(CurrentKeyHandle,
429                                        &KeyName,
430                                        KeyValuePartialInformation,
431                                        ValueInfo,
432                                        BufferSize,
433                                        &ResultSize);
434               if (!NT_SUCCESS(Status))
435                 {
436                   Status = QueryEntry->QueryRoutine(QueryEntry->Name,
437                                                     QueryEntry->DefaultType,
438                                                     QueryEntry->DefaultData,
439                                                     QueryEntry->DefaultLength,
440                                                     Context,
441                                                     QueryEntry->EntryContext);
442                 }
443               else if ((ValueInfo->Type == REG_MULTI_SZ) &&
444                        !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
445                 {
446                   DPRINT("Expand REG_MULTI_SZ type\n");
447                   StringPtr = (PWSTR)ValueInfo->Data;
448                   while (*StringPtr != 0)
449                     {
450                       StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
451                       Status = QueryEntry->QueryRoutine(QueryEntry->Name,
452                                                         REG_SZ,
453                                                         (PVOID)StringPtr,
454                                                         StringLen,
455                                                         Context,
456                                                         QueryEntry->EntryContext);
457                       if(!NT_SUCCESS(Status))
458                         break;
459                       StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
460                     }
461                 }
462               else if ((ValueInfo->Type == REG_EXPAND_SZ) &&
463                        !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
464                 {
465                   DPRINT("Expand REG_EXPAND_SZ type\n");
466
467                   ExpandBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
468                                                  0,
469                                                  ValueInfo->DataLength * 2);
470                   if (ExpandBuffer == NULL)
471                     {
472                       Status = STATUS_NO_MEMORY;
473                       break;
474                     }
475
476                   RtlInitUnicodeString(&EnvValue,
477                                        (PWSTR)ValueInfo->Data);
478                   EnvExpandedValue.Length = 0;
479                   EnvExpandedValue.MaximumLength = ValueInfo->DataLength * 2 * sizeof(WCHAR);
480                   EnvExpandedValue.Buffer = ExpandBuffer;
481                   *ExpandBuffer = 0;
482
483                   RtlExpandEnvironmentStrings_U(Environment,
484                                                 &EnvValue,
485                                                 &EnvExpandedValue,
486                                                 &StringLen);
487
488                   StringLen = (wcslen(ExpandBuffer) + 1) * sizeof(WCHAR);
489                   Status = QueryEntry->QueryRoutine(QueryEntry->Name,
490                                                     REG_SZ,
491                                                     (PVOID)ExpandBuffer,
492                                                     StringLen,
493                                                     Context,
494                                                     QueryEntry->EntryContext);
495
496                   RtlFreeHeap(RtlGetProcessHeap(),
497                               0,
498                               ExpandBuffer);
499                 }
500               else
501                 {
502                   Status = QueryEntry->QueryRoutine(QueryEntry->Name,
503                                                     ValueInfo->Type,
504                                                     ValueInfo->Data,
505                                                     ValueInfo->DataLength,
506                                                     Context,
507                                                     QueryEntry->EntryContext);
508                 }
509
510               if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
511                 {
512                   DPRINT1("FIXME: Delete value: %S\n", QueryEntry->Name);
513
514                 }
515
516               RtlFreeHeap(RtlGetProcessHeap(),
517                           0,
518                           ValueInfo);
519               if (!NT_SUCCESS(Status))
520                 break;
521             }
522           else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOVALUE)
523             {
524               DPRINT("Simple callback\n");
525               Status = QueryEntry->QueryRoutine(NULL,
526                                                 REG_NONE,
527                                                 NULL,
528                                                 0,
529                                                 Context,
530                                                 QueryEntry->EntryContext);
531               if (!NT_SUCCESS(Status))
532                 break;
533             }
534           else
535             {
536               DPRINT("Enumerate values\n");
537
538               BufferSize = sizeof(KEY_VALUE_FULL_INFORMATION) + 4096;
539               FullValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
540                                               0,
541                                               BufferSize);
542               if (FullValueInfo == NULL)
543                 {
544                   Status = STATUS_NO_MEMORY;
545                   break;
546                 }
547               ValueNameSize = 256 * sizeof(WCHAR);
548               ValueName = RtlAllocateHeap(RtlGetProcessHeap(),
549                                           0,
550                                           ValueNameSize);
551               if (ValueName == NULL)
552                 {
553                   Status = STATUS_NO_MEMORY;
554                   break;
555                 }
556               Index = 0;
557               while (TRUE)
558                 {
559                   Status = NtEnumerateValueKey(CurrentKeyHandle,
560                                                Index,
561                                                KeyValueFullInformation,
562                                                FullValueInfo,
563                                                BufferSize,
564                                                &ResultSize);
565                   if (!NT_SUCCESS(Status))
566                     {
567                       if ((Status == STATUS_NO_MORE_ENTRIES) &&
568                           (Index == 0) &&
569                           (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED))
570                         {
571                           Status = STATUS_OBJECT_NAME_NOT_FOUND;
572                         }
573                       else if (Status == STATUS_NO_MORE_ENTRIES)
574                         {
575                           Status = STATUS_SUCCESS;
576                         }
577                       break;
578                     }
579
580                   if (FullValueInfo->NameLength > ValueNameSize - sizeof(WCHAR))
581                     {
582                       /* Should not happen, because the name length is limited to 255 characters */
583                       RtlFreeHeap(RtlGetProcessHeap(),
584                                   0,
585                                   ValueName);
586                       ValueNameSize = FullValueInfo->NameLength + sizeof(WCHAR);
587                       ValueName = RtlAllocateHeap(RtlGetProcessHeap(),
588                                                   0,
589                                                   ValueNameSize);
590                       if (ValueName == NULL)
591                         {
592                           Status = STATUS_NO_MEMORY;
593                           break;
594                         }
595                     }
596
597                   memcpy(ValueName,
598                          FullValueInfo->Name,
599                          FullValueInfo->NameLength);
600                   ValueName[FullValueInfo->NameLength / sizeof(WCHAR)] = 0;
601
602                   DPRINT("FullValueInfo->Type: %lu\n", FullValueInfo->Type);
603                   if ((FullValueInfo->Type == REG_MULTI_SZ) &&
604                       !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
605                     {
606                       DPRINT("Expand REG_MULTI_SZ type\n");
607                       StringPtr = (PWSTR)((PVOID)FullValueInfo + FullValueInfo->DataOffset);
608                       while (*StringPtr != 0)
609                         {
610                           StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
611                           Status = QueryEntry->QueryRoutine(ValueName,
612                                                             REG_SZ,
613                                                             (PVOID)StringPtr,
614                                                             StringLen,
615                                                             Context,
616                                                             QueryEntry->EntryContext);
617                           if(!NT_SUCCESS(Status))
618                             break;
619                           StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
620                         }
621                     }
622                   else if ((FullValueInfo->Type == REG_EXPAND_SZ) &&
623                            !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
624                     {
625                       DPRINT("Expand REG_EXPAND_SZ type\n");
626
627                       StringPtr = (PWSTR)((PVOID)FullValueInfo + FullValueInfo->DataOffset);
628                       ExpandBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
629                                                      0,
630                                                      FullValueInfo->DataLength * 2);
631                       if (ExpandBuffer == NULL)
632                         {
633                           Status = STATUS_NO_MEMORY;
634                           break;
635                         }
636
637                       RtlInitUnicodeString(&EnvValue,
638                                            StringPtr);
639                       EnvExpandedValue.Length = 0;
640                       EnvExpandedValue.MaximumLength = FullValueInfo->DataLength * 2;
641                       EnvExpandedValue.Buffer = ExpandBuffer;
642                       *ExpandBuffer = 0;
643
644                       RtlExpandEnvironmentStrings_U(Environment,
645                                                     &EnvValue,
646                                                     &EnvExpandedValue,
647                                                     &StringLen);
648
649                       StringLen = (wcslen(ExpandBuffer) + 1) * sizeof(WCHAR);
650                       Status = QueryEntry->QueryRoutine(ValueName,
651                                                         REG_SZ,
652                                                         (PVOID)ExpandBuffer,
653                                                         StringLen,
654                                                         Context,
655                                                         QueryEntry->EntryContext);
656
657                       RtlFreeHeap(RtlGetProcessHeap(),
658                                   0,
659                                   ExpandBuffer);
660                     }
661                   else
662                     {
663                       Status = QueryEntry->QueryRoutine(ValueName,
664                                                         FullValueInfo->Type,
665                                                         (PVOID)FullValueInfo + FullValueInfo->DataOffset,
666                                                         FullValueInfo->DataLength,
667                                                         Context,
668                                                         QueryEntry->EntryContext);
669                     }
670
671                   if (!NT_SUCCESS(Status))
672                     break;
673
674                   /* FIXME: How will these be deleted? */
675
676                   Index++;
677                 }
678
679               RtlFreeHeap(RtlGetProcessHeap(),
680                           0,
681                           FullValueInfo);
682               RtlFreeHeap(RtlGetProcessHeap(),
683                           0,
684                           ValueName);
685               if (!NT_SUCCESS(Status))
686                 break;
687             }
688         }
689
690       QueryEntry++;
691     }
692
693   if (CurrentKeyHandle != BaseKeyHandle)
694     NtClose(CurrentKeyHandle);
695
696   NtClose(BaseKeyHandle);
697
698   return(Status);
699 }
700
701
702 /*
703  * @implemented
704  */
705 NTSTATUS STDCALL
706 RtlWriteRegistryValue(IN ULONG RelativeTo,
707                       IN PCWSTR Path,
708                       IN PCWSTR ValueName,
709                       IN ULONG ValueType,
710                       IN PVOID ValueData,
711                       IN ULONG ValueLength)
712 {
713   HANDLE KeyHandle;
714   NTSTATUS Status;
715   UNICODE_STRING Name;
716
717   Status = RtlpGetRegistryHandle(RelativeTo,
718                                  (PWSTR)Path,
719                                  TRUE,
720                                  &KeyHandle);
721   if (!NT_SUCCESS(Status))
722     return(Status);
723
724   RtlInitUnicodeString(&Name,
725                        ValueName);
726
727   Status = NtSetValueKey(KeyHandle,
728                          &Name,
729                          0,
730                          ValueType,
731                          ValueData,
732                          ValueLength);
733   if (NT_SUCCESS(Status))
734     NtClose(KeyHandle);
735
736   return(Status);
737 }
738
739
740 /*
741  * @implemented
742  */
743 NTSTATUS STDCALL
744 RtlpNtCreateKey(OUT HANDLE KeyHandle,
745                 IN ACCESS_MASK DesiredAccess,
746                 IN POBJECT_ATTRIBUTES ObjectAttributes,
747                 IN ULONG Unused1,
748                 OUT PULONG Disposition,
749                 IN ULONG Unused2)
750 {
751   if (ObjectAttributes != NULL)
752     ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
753
754   return(NtCreateKey(KeyHandle,
755                      DesiredAccess,
756                      ObjectAttributes,
757                      0,
758                      NULL,
759                      0,
760                      Disposition));
761 }
762
763
764 /*
765  * @implemented
766  */
767 NTSTATUS STDCALL
768 RtlpNtEnumerateSubKey(IN HANDLE KeyHandle,
769                       OUT PUNICODE_STRING SubKeyName,
770                       IN ULONG Index,
771                       IN ULONG Unused)
772 {
773   PKEY_BASIC_INFORMATION KeyInfo = NULL;
774   ULONG BufferLength = 0;
775   ULONG ReturnedLength;
776   NTSTATUS Status;
777
778   if (SubKeyName->MaximumLength != 0)
779     {
780       BufferLength = SubKeyName->MaximumLength +
781                      sizeof(KEY_BASIC_INFORMATION);
782       KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(),
783                                 0,
784                                 BufferLength);
785       if (KeyInfo == NULL)
786         return(STATUS_NO_MEMORY);
787     }
788
789   Status = NtEnumerateKey(KeyHandle,
790                           Index,
791                           KeyBasicInformation,
792                           KeyInfo,
793                           BufferLength,
794                           &ReturnedLength);
795   if (NT_SUCCESS(Status))
796     {
797       if (KeyInfo->NameLength + sizeof(WCHAR) <= SubKeyName->MaximumLength)
798         {
799           memmove(SubKeyName->Buffer,
800                   KeyInfo->Name,
801                   KeyInfo->NameLength);
802           SubKeyName->Buffer[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
803           SubKeyName->Length = KeyInfo->NameLength;
804         }
805       else
806         {
807           Status = STATUS_BUFFER_OVERFLOW;
808         }
809     }
810
811   if (KeyInfo != NULL)
812     {
813       RtlFreeHeap(RtlGetProcessHeap(),
814                   0,
815                   KeyInfo);
816     }
817
818   return(Status);
819 }
820
821
822 /*
823  * @implemented
824  */
825 NTSTATUS STDCALL
826 RtlpNtMakeTemporaryKey(IN HANDLE KeyHandle)
827 {
828   return(NtDeleteKey(KeyHandle));
829 }
830
831
832 /*
833  * @implemented
834  */
835 NTSTATUS STDCALL
836 RtlpNtOpenKey(OUT HANDLE KeyHandle,
837               IN ACCESS_MASK DesiredAccess,
838               IN POBJECT_ATTRIBUTES ObjectAttributes,
839               IN ULONG Unused)
840 {
841   if (ObjectAttributes != NULL)
842     ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
843
844   return(NtOpenKey(KeyHandle,
845                    DesiredAccess,
846                    ObjectAttributes));
847 }
848
849
850 /*
851  * @implemented
852  */
853 NTSTATUS STDCALL
854 RtlpNtQueryValueKey(IN HANDLE KeyHandle,
855                     OUT PULONG Type OPTIONAL,
856                     OUT PVOID Data OPTIONAL,
857                     IN OUT PULONG DataLength OPTIONAL,
858                     IN ULONG Unused)
859 {
860   PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
861   UNICODE_STRING ValueName;
862   ULONG BufferLength;
863   ULONG ReturnedLength;
864   NTSTATUS Status;
865
866   RtlInitUnicodeString(&ValueName,
867                        NULL);
868
869   BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
870   if (DataLength != NULL)
871     BufferLength = *DataLength;
872
873   ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
874                               0,
875                               BufferLength);
876   if (ValueInfo == NULL)
877     return(STATUS_NO_MEMORY);
878
879   Status = NtQueryValueKey(KeyHandle,
880                            &ValueName,
881                            KeyValuePartialInformation,
882                            ValueInfo,
883                            BufferLength,
884                            &ReturnedLength);
885   if (NT_SUCCESS(Status))
886     {
887       if (DataLength != NULL)
888         *DataLength = ValueInfo->DataLength;
889
890       if (Type != NULL)
891         *Type = ValueInfo->Type;
892
893       if (Data != NULL)
894         {
895           memmove(Data,
896                   ValueInfo->Data,
897                   ValueInfo->DataLength);
898         }
899     }
900
901   RtlFreeHeap(RtlGetProcessHeap(),
902               0,
903               ValueInfo);
904
905   return(Status);
906 }
907
908
909 /*
910  * @implemented
911  */
912 NTSTATUS STDCALL
913 RtlpNtSetValueKey(IN HANDLE KeyHandle,
914                   IN ULONG Type,
915                   IN PVOID Data,
916                   IN ULONG DataLength)
917 {
918   UNICODE_STRING ValueName;
919
920   RtlInitUnicodeString(&ValueName,
921                        NULL);
922   return(NtSetValueKey(KeyHandle,
923                        &ValueName,
924                        0,
925                        Type,
926                        Data,
927                        DataLength));
928 }
929
930
931 /* INTERNAL FUNCTIONS ******************************************************/
932
933 NTSTATUS
934 RtlpGetRegistryHandle(ULONG RelativeTo,
935                       PWSTR Path,
936                       BOOLEAN Create,
937                       PHANDLE KeyHandle)
938 {
939   UNICODE_STRING KeyName;
940   WCHAR KeyBuffer[MAX_PATH];
941   OBJECT_ATTRIBUTES ObjectAttributes;
942   NTSTATUS Status;
943
944   DPRINT("RtlpGetRegistryHandle()\n");
945
946   if (RelativeTo & RTL_REGISTRY_HANDLE)
947     {
948       Status = NtDuplicateObject(NtCurrentProcess(),
949                                  (HANDLE)Path,
950                                  NtCurrentProcess(),
951                                  KeyHandle,
952                                  0,
953                                  FALSE,
954                                  DUPLICATE_SAME_ACCESS);
955       return(Status);
956     }
957
958   if (RelativeTo & RTL_REGISTRY_OPTIONAL)
959     RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
960
961   if (RelativeTo >= RTL_REGISTRY_MAXIMUM)
962     return(STATUS_INVALID_PARAMETER);
963
964   KeyName.Length = 0;
965   KeyName.MaximumLength = MAX_PATH;
966   KeyName.Buffer = KeyBuffer;
967   KeyBuffer[0] = 0;
968
969   switch (RelativeTo)
970     {
971       case RTL_REGISTRY_ABSOLUTE:
972         RtlAppendUnicodeToString(&KeyName,
973                                  L"\\");
974         break;
975
976       case RTL_REGISTRY_SERVICES:
977         RtlAppendUnicodeToString(&KeyName,
978                                  L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
979         break;
980
981       case RTL_REGISTRY_CONTROL:
982         RtlAppendUnicodeToString(&KeyName,
983                                  L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
984         break;
985
986       case RTL_REGISTRY_WINDOWS_NT:
987         RtlAppendUnicodeToString(&KeyName,
988                                  L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
989         break;
990
991       case RTL_REGISTRY_DEVICEMAP:
992         RtlAppendUnicodeToString(&KeyName,
993                                  L"\\Registry\\Machine\\Hardware\\DeviceMap\\");
994         break;
995
996       case RTL_REGISTRY_USER:
997         Status = RtlFormatCurrentUserKeyPath(&KeyName);
998         if (!NT_SUCCESS(Status))
999           return(Status);
1000         break;
1001
1002       /* ReactOS specific */
1003       case RTL_REGISTRY_ENUM:
1004         RtlAppendUnicodeToString(&KeyName,
1005                                  L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1006         break;
1007     }
1008
1009   DPRINT("KeyName %wZ\n", &KeyName);
1010
1011   if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE)
1012     {
1013       Path++;
1014     }
1015   RtlAppendUnicodeToString(&KeyName,
1016                            Path);
1017
1018   DPRINT("KeyName %wZ\n", &KeyName);
1019
1020   InitializeObjectAttributes(&ObjectAttributes,
1021                              &KeyName,
1022                              OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1023                              NULL,
1024                              NULL);
1025
1026   if (Create == TRUE)
1027     {
1028       Status = NtCreateKey(KeyHandle,
1029                            KEY_ALL_ACCESS,
1030                            &ObjectAttributes,
1031                            0,
1032                            NULL,
1033                            0,
1034                            NULL);
1035     }
1036   else
1037     {
1038       Status = NtOpenKey(KeyHandle,
1039                          KEY_ALL_ACCESS,
1040                          &ObjectAttributes);
1041     }
1042
1043   return(Status);
1044 }
1045
1046 /* EOF */