ntdll: Fix typo in RTL_ReportRegistryValue which caused a counted string to be passed...
[wine] / dlls / ntdll / reg.c
1 /*
2  * Registry functions
3  *
4  * Copyright (C) 1999 Juergen Schmied
5  * Copyright (C) 2000 Alexandre Julliard
6  * Copyright 2005 Ivan Leo Puoti, Laurent Pinchart
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  * NOTES:
23  *      HKEY_LOCAL_MACHINE      \\REGISTRY\\MACHINE
24  *      HKEY_USERS              \\REGISTRY\\USER
25  *      HKEY_CURRENT_CONFIG     \\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT
26   *     HKEY_CLASSES            \\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES
27  */
28
29 #include "config.h"
30 #include "wine/port.h"
31
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #include "ntstatus.h"
37 #define WIN32_NO_STATUS
38 #include "wine/library.h"
39 #include "ntdll_misc.h"
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(reg);
44
45 /* maximum length of a key/value name in bytes (without terminating null) */
46 #define MAX_NAME_LENGTH ((MAX_PATH-1) * sizeof(WCHAR))
47
48 /******************************************************************************
49  * NtCreateKey [NTDLL.@]
50  * ZwCreateKey [NTDLL.@]
51  */
52 NTSTATUS WINAPI NtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
53                              ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
54                              PULONG dispos )
55 {
56     NTSTATUS ret;
57
58     if (!retkey || !attr) return STATUS_ACCESS_VIOLATION;
59     if (attr->Length > sizeof(OBJECT_ATTRIBUTES)) return STATUS_INVALID_PARAMETER;
60     if (attr->ObjectName->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
61
62     TRACE( "(%p,%s,%s,%x,%x,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
63            debugstr_us(class), options, access, retkey );
64
65     SERVER_START_REQ( create_key )
66     {
67         req->parent     = wine_server_obj_handle( attr->RootDirectory );
68         req->access     = access;
69         req->attributes = attr->Attributes;
70         req->options    = options;
71         req->namelen    = attr->ObjectName->Length;
72         wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
73         if (class) wine_server_add_data( req, class->Buffer, class->Length );
74         if (!(ret = wine_server_call( req )))
75         {
76             *retkey = wine_server_ptr_handle( reply->hkey );
77             if (dispos) *dispos = reply->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
78         }
79     }
80     SERVER_END_REQ;
81     TRACE("<- %p\n", *retkey);
82     return ret;
83 }
84
85 /******************************************************************************
86  *  RtlpNtCreateKey [NTDLL.@]
87  *
88  *  See NtCreateKey.
89  */
90 NTSTATUS WINAPI RtlpNtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
91                                  ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
92                                  PULONG dispos )
93 {
94     OBJECT_ATTRIBUTES oa;
95
96     if (attr)
97     {
98         oa = *attr;
99         oa.Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
100         attr = &oa;
101     }
102
103     return NtCreateKey(retkey, access, attr, 0, NULL, 0, dispos);
104 }
105
106 /******************************************************************************
107  * NtOpenKey [NTDLL.@]
108  * ZwOpenKey [NTDLL.@]
109  *
110  *   OUT        HANDLE                  retkey (returns 0 when failure)
111  *   IN         ACCESS_MASK             access
112  *   IN         POBJECT_ATTRIBUTES      attr
113  */
114 NTSTATUS WINAPI NtOpenKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
115 {
116     NTSTATUS ret;
117     DWORD len;
118
119     if (!attr) return STATUS_ACCESS_VIOLATION;
120     len = attr->ObjectName->Length;
121     TRACE( "(%p,%s,%x,%p)\n", attr->RootDirectory,
122            debugstr_us(attr->ObjectName), access, retkey );
123
124     if (len > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
125     if (!retkey) return STATUS_INVALID_PARAMETER;
126
127     SERVER_START_REQ( open_key )
128     {
129         req->parent     = wine_server_obj_handle( attr->RootDirectory );
130         req->access     = access;
131         req->attributes = attr->Attributes;
132         wine_server_add_data( req, attr->ObjectName->Buffer, len );
133         ret = wine_server_call( req );
134         *retkey = wine_server_ptr_handle( reply->hkey );
135     }
136     SERVER_END_REQ;
137     TRACE("<- %p\n", *retkey);
138     return ret;
139 }
140
141 /******************************************************************************
142  * RtlpNtOpenKey [NTDLL.@]
143  *
144  * See NtOpenKey.
145  */
146 NTSTATUS WINAPI RtlpNtOpenKey( PHANDLE retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
147 {
148     if (attr)
149         attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
150     return NtOpenKey(retkey, access, attr);
151 }
152
153 /******************************************************************************
154  * NtDeleteKey [NTDLL.@]
155  * ZwDeleteKey [NTDLL.@]
156  */
157 NTSTATUS WINAPI NtDeleteKey( HANDLE hkey )
158 {
159     NTSTATUS ret;
160
161     TRACE( "(%p)\n", hkey );
162
163     SERVER_START_REQ( delete_key )
164     {
165         req->hkey = wine_server_obj_handle( hkey );
166         ret = wine_server_call( req );
167     }
168     SERVER_END_REQ;
169     return ret;
170 }
171
172 /******************************************************************************
173  * RtlpNtMakeTemporaryKey [NTDLL.@]
174  *
175  *  See NtDeleteKey.
176  */
177 NTSTATUS WINAPI RtlpNtMakeTemporaryKey( HANDLE hkey )
178 {
179     return NtDeleteKey(hkey);
180 }
181
182 /******************************************************************************
183  * NtDeleteValueKey [NTDLL.@]
184  * ZwDeleteValueKey [NTDLL.@]
185  */
186 NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name )
187 {
188     NTSTATUS ret;
189
190     TRACE( "(%p,%s)\n", hkey, debugstr_us(name) );
191     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
192
193     SERVER_START_REQ( delete_key_value )
194     {
195         req->hkey = wine_server_obj_handle( hkey );
196         wine_server_add_data( req, name->Buffer, name->Length );
197         ret = wine_server_call( req );
198     }
199     SERVER_END_REQ;
200     return ret;
201 }
202
203
204 /******************************************************************************
205  *     enumerate_key
206  *
207  * Implementation of NtQueryKey and NtEnumerateKey
208  */
209 static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS info_class,
210                                void *info, DWORD length, DWORD *result_len )
211
212 {
213     NTSTATUS ret;
214     void *data_ptr;
215     size_t fixed_size;
216
217     switch(info_class)
218     {
219     case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break;
220     case KeyFullInformation:  data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
221     case KeyNodeInformation:  data_ptr = ((KEY_NODE_INFORMATION *)info)->Name;  break;
222     case KeyNameInformation:  data_ptr = ((KEY_NAME_INFORMATION *)info)->Name;  break;
223     default:
224         FIXME( "Information class %d not implemented\n", info_class );
225         return STATUS_INVALID_PARAMETER;
226     }
227     fixed_size = (char *)data_ptr - (char *)info;
228
229     SERVER_START_REQ( enum_key )
230     {
231         req->hkey       = wine_server_obj_handle( handle );
232         req->index      = index;
233         req->info_class = info_class;
234         if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
235         if (!(ret = wine_server_call( req )))
236         {
237             switch(info_class)
238             {
239             case KeyBasicInformation:
240                 {
241                     KEY_BASIC_INFORMATION keyinfo;
242                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
243                     keyinfo.LastWriteTime.QuadPart = reply->modif;
244                     keyinfo.TitleIndex = 0;
245                     keyinfo.NameLength = reply->namelen;
246                     memcpy( info, &keyinfo, min( length, fixed_size ) );
247                 }
248                 break;
249             case KeyFullInformation:
250                 {
251                     KEY_FULL_INFORMATION keyinfo;
252                     fixed_size = (char *)keyinfo.Class - (char *)&keyinfo;
253                     keyinfo.LastWriteTime.QuadPart = reply->modif;
254                     keyinfo.TitleIndex = 0;
255                     keyinfo.ClassLength = wine_server_reply_size(reply);
256                     keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
257                     keyinfo.SubKeys = reply->subkeys;
258                     keyinfo.MaxNameLen = reply->max_subkey;
259                     keyinfo.MaxClassLen = reply->max_class;
260                     keyinfo.Values = reply->values;
261                     keyinfo.MaxValueNameLen = reply->max_value;
262                     keyinfo.MaxValueDataLen = reply->max_data;
263                     memcpy( info, &keyinfo, min( length, fixed_size ) );
264                 }
265                 break;
266             case KeyNodeInformation:
267                 {
268                     KEY_NODE_INFORMATION keyinfo;
269                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
270                     keyinfo.LastWriteTime.QuadPart = reply->modif;
271                     keyinfo.TitleIndex = 0;
272                     if (reply->namelen < wine_server_reply_size(reply))
273                     {
274                         keyinfo.ClassLength = wine_server_reply_size(reply) - reply->namelen;
275                         keyinfo.ClassOffset = fixed_size + reply->namelen;
276                     }
277                     else
278                     {
279                         keyinfo.ClassLength = 0;
280                         keyinfo.ClassOffset = -1;
281                     }
282                     keyinfo.NameLength = reply->namelen;
283                     memcpy( info, &keyinfo, min( length, fixed_size ) );
284                 }
285                 break;
286             case KeyNameInformation:
287                 {
288                     KEY_NAME_INFORMATION keyinfo;
289                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
290                     keyinfo.NameLength = reply->namelen;
291                     memcpy( info, &keyinfo, min( length, fixed_size ) );
292                 }
293                 break;
294             }
295             *result_len = fixed_size + reply->total;
296             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
297         }
298     }
299     SERVER_END_REQ;
300     return ret;
301 }
302
303
304
305 /******************************************************************************
306  * NtEnumerateKey [NTDLL.@]
307  * ZwEnumerateKey [NTDLL.@]
308  *
309  * NOTES
310  *  the name copied into the buffer is NOT 0-terminated
311  */
312 NTSTATUS WINAPI NtEnumerateKey( HANDLE handle, ULONG index, KEY_INFORMATION_CLASS info_class,
313                                 void *info, DWORD length, DWORD *result_len )
314 {
315     /* -1 means query key, so avoid it here */
316     if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
317     return enumerate_key( handle, index, info_class, info, length, result_len );
318 }
319
320
321 /******************************************************************************
322  * RtlpNtEnumerateSubKey [NTDLL.@]
323  *
324  */
325 NTSTATUS WINAPI RtlpNtEnumerateSubKey( HANDLE handle, UNICODE_STRING *out, ULONG index )
326 {
327   KEY_BASIC_INFORMATION *info;
328   DWORD dwLen, dwResultLen;
329   NTSTATUS ret;
330
331   if (out->Length)
332   {
333     dwLen = out->Length + sizeof(KEY_BASIC_INFORMATION);
334     info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
335     if (!info)
336       return STATUS_NO_MEMORY;
337   }
338   else
339   {
340     dwLen = 0;
341     info = NULL;
342   }
343
344   ret = NtEnumerateKey( handle, index, KeyBasicInformation, info, dwLen, &dwResultLen );
345   dwResultLen -= sizeof(KEY_BASIC_INFORMATION);
346
347   if (ret == STATUS_BUFFER_OVERFLOW)
348     out->Length = dwResultLen;
349   else if (!ret)
350   {
351     if (out->Length < info->NameLength)
352     {
353       out->Length = dwResultLen;
354       ret = STATUS_BUFFER_OVERFLOW;
355     }
356     else
357     {
358       out->Length = info->NameLength;
359       memcpy(out->Buffer, info->Name, info->NameLength);
360     }
361   }
362
363   RtlFreeHeap( GetProcessHeap(), 0, info );
364   return ret;
365 }
366
367 /******************************************************************************
368  * NtQueryKey [NTDLL.@]
369  * ZwQueryKey [NTDLL.@]
370  */
371 NTSTATUS WINAPI NtQueryKey( HANDLE handle, KEY_INFORMATION_CLASS info_class,
372                             void *info, DWORD length, DWORD *result_len )
373 {
374     return enumerate_key( handle, -1, info_class, info, length, result_len );
375 }
376
377
378 /* fill the key value info structure for a specific info class */
379 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info,
380                                  DWORD length, int type, int name_len, int data_len )
381 {
382     switch(info_class)
383     {
384     case KeyValueBasicInformation:
385         {
386             KEY_VALUE_BASIC_INFORMATION keyinfo;
387             keyinfo.TitleIndex = 0;
388             keyinfo.Type       = type;
389             keyinfo.NameLength = name_len;
390             length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
391             memcpy( info, &keyinfo, length );
392             break;
393         }
394     case KeyValueFullInformation:
395         {
396             KEY_VALUE_FULL_INFORMATION keyinfo;
397             keyinfo.TitleIndex = 0;
398             keyinfo.Type       = type;
399             keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len;
400             keyinfo.DataLength = data_len;
401             keyinfo.NameLength = name_len;
402             length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
403             memcpy( info, &keyinfo, length );
404             break;
405         }
406     case KeyValuePartialInformation:
407         {
408             KEY_VALUE_PARTIAL_INFORMATION keyinfo;
409             keyinfo.TitleIndex = 0;
410             keyinfo.Type       = type;
411             keyinfo.DataLength = data_len;
412             length = min( length, (char *)keyinfo.Data - (char *)&keyinfo );
413             memcpy( info, &keyinfo, length );
414             break;
415         }
416     default:
417         break;
418     }
419 }
420
421
422 /******************************************************************************
423  *  NtEnumerateValueKey [NTDLL.@]
424  *  ZwEnumerateValueKey [NTDLL.@]
425  */
426 NTSTATUS WINAPI NtEnumerateValueKey( HANDLE handle, ULONG index,
427                                      KEY_VALUE_INFORMATION_CLASS info_class,
428                                      void *info, DWORD length, DWORD *result_len )
429 {
430     NTSTATUS ret;
431     void *ptr;
432     size_t fixed_size;
433
434     TRACE( "(%p,%u,%d,%p,%d)\n", handle, index, info_class, info, length );
435
436     /* compute the length we want to retrieve */
437     switch(info_class)
438     {
439     case KeyValueBasicInformation:   ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break;
440     case KeyValueFullInformation:    ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break;
441     case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break;
442     default:
443         FIXME( "Information class %d not implemented\n", info_class );
444         return STATUS_INVALID_PARAMETER;
445     }
446     fixed_size = (char *)ptr - (char *)info;
447
448     SERVER_START_REQ( enum_key_value )
449     {
450         req->hkey       = wine_server_obj_handle( handle );
451         req->index      = index;
452         req->info_class = info_class;
453         if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size );
454         if (!(ret = wine_server_call( req )))
455         {
456             copy_key_value_info( info_class, info, length, reply->type, reply->namelen,
457                                  wine_server_reply_size(reply) - reply->namelen );
458             *result_len = fixed_size + reply->total;
459             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
460         }
461     }
462     SERVER_END_REQ;
463     return ret;
464 }
465
466
467 /******************************************************************************
468  * NtQueryValueKey [NTDLL.@]
469  * ZwQueryValueKey [NTDLL.@]
470  *
471  * NOTES
472  *  the name in the KeyValueInformation is never set
473  */
474 NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name,
475                                  KEY_VALUE_INFORMATION_CLASS info_class,
476                                  void *info, DWORD length, DWORD *result_len )
477 {
478     NTSTATUS ret;
479     UCHAR *data_ptr;
480     unsigned int fixed_size = 0;
481
482     TRACE( "(%p,%s,%d,%p,%d)\n", handle, debugstr_us(name), info_class, info, length );
483
484     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
485
486     /* compute the length we want to retrieve */
487     switch(info_class)
488     {
489     case KeyValueBasicInformation:
490     {
491         KEY_VALUE_BASIC_INFORMATION *basic_info = info;
492         if (FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) < length)
493         {
494             memcpy(basic_info->Name, name->Buffer,
495                    min(length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name), name->Length));
496         }
497         fixed_size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) + name->Length;
498         data_ptr = NULL;
499         break;
500     }
501     case KeyValueFullInformation:
502     {
503         KEY_VALUE_FULL_INFORMATION *full_info = info;
504         if (FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) < length)
505         {
506             memcpy(full_info->Name, name->Buffer,
507                    min(length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name), name->Length));
508         }
509         data_ptr = (UCHAR *)full_info->Name + name->Length;
510         fixed_size = (char *)data_ptr - (char *)info;
511         break;
512     }
513     case KeyValuePartialInformation:
514         data_ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data;
515         fixed_size = (char *)data_ptr - (char *)info;
516         break;
517     default:
518         FIXME( "Information class %d not implemented\n", info_class );
519         return STATUS_INVALID_PARAMETER;
520     }
521
522     SERVER_START_REQ( get_key_value )
523     {
524         req->hkey = wine_server_obj_handle( handle );
525         wine_server_add_data( req, name->Buffer, name->Length );
526         if (length > fixed_size && data_ptr) wine_server_set_reply( req, data_ptr, length - fixed_size );
527         if (!(ret = wine_server_call( req )))
528         {
529             copy_key_value_info( info_class, info, length, reply->type,
530                                  name->Length, reply->total );
531             *result_len = fixed_size + (info_class == KeyValueBasicInformation ? 0 : reply->total);
532             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
533         }
534     }
535     SERVER_END_REQ;
536     return ret;
537 }
538
539 /******************************************************************************
540  * RtlpNtQueryValueKey [NTDLL.@]
541  *
542  */
543 NTSTATUS WINAPI RtlpNtQueryValueKey( HANDLE handle, ULONG *result_type, PBYTE dest,
544                                      DWORD *result_len, void *unknown )
545 {
546     KEY_VALUE_PARTIAL_INFORMATION *info;
547     UNICODE_STRING name;
548     NTSTATUS ret;
549     DWORD dwResultLen;
550     DWORD dwLen = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + (result_len ? *result_len : 0);
551
552     info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
553     if (!info)
554       return STATUS_NO_MEMORY;
555
556     name.Length = 0;
557     ret = NtQueryValueKey( handle, &name, KeyValuePartialInformation, info, dwLen, &dwResultLen );
558
559     if (!ret || ret == STATUS_BUFFER_OVERFLOW)
560     {
561         if (result_len)
562             *result_len = info->DataLength;
563
564         if (result_type)
565             *result_type = info->Type;
566
567         if (ret != STATUS_BUFFER_OVERFLOW)
568             memcpy( dest, info->Data, info->DataLength );
569     }
570
571     RtlFreeHeap( GetProcessHeap(), 0, info );
572     return ret;
573 }
574
575 /******************************************************************************
576  *  NtFlushKey  [NTDLL.@]
577  *  ZwFlushKey  [NTDLL.@]
578  */
579 NTSTATUS WINAPI NtFlushKey(HANDLE key)
580 {
581     NTSTATUS ret;
582
583     TRACE("key=%p\n", key);
584
585     SERVER_START_REQ( flush_key )
586     {
587         req->hkey = wine_server_obj_handle( key );
588         ret = wine_server_call( req );
589     }
590     SERVER_END_REQ;
591     
592     return ret;
593 }
594
595 /******************************************************************************
596  *  NtLoadKey   [NTDLL.@]
597  *  ZwLoadKey   [NTDLL.@]
598  */
599 NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file )
600 {
601     NTSTATUS ret;
602     HANDLE hive;
603     IO_STATUS_BLOCK io;
604
605     TRACE("(%p,%p)\n", attr, file);
606
607     ret = NtCreateFile(&hive, GENERIC_READ, file, &io, NULL, FILE_ATTRIBUTE_NORMAL, 0,
608                        FILE_OPEN, 0, NULL, 0);
609     if (ret) return ret;
610
611     SERVER_START_REQ( load_registry )
612     {
613         req->hkey = wine_server_obj_handle( attr->RootDirectory );
614         req->file = wine_server_obj_handle( hive );
615         wine_server_add_data(req, attr->ObjectName->Buffer, attr->ObjectName->Length);
616         ret = wine_server_call( req );
617     }
618     SERVER_END_REQ;
619
620     NtClose(hive);
621    
622     return ret;
623 }
624
625 /******************************************************************************
626  *  NtNotifyChangeKey   [NTDLL.@]
627  *  ZwNotifyChangeKey   [NTDLL.@]
628  */
629 NTSTATUS WINAPI NtNotifyChangeKey(
630         IN HANDLE KeyHandle,
631         IN HANDLE Event,
632         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
633         IN PVOID ApcContext OPTIONAL,
634         OUT PIO_STATUS_BLOCK IoStatusBlock,
635         IN ULONG CompletionFilter,
636         IN BOOLEAN Asynchronous,
637         OUT PVOID ChangeBuffer,
638         IN ULONG Length,
639         IN BOOLEAN WatchSubtree)
640 {
641     NTSTATUS ret;
642
643     TRACE("(%p,%p,%p,%p,%p,0x%08x, 0x%08x,%p,0x%08x,0x%08x)\n",
644         KeyHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
645         Asynchronous, ChangeBuffer, Length, WatchSubtree);
646
647     if (ApcRoutine || ApcContext || ChangeBuffer || Length)
648         FIXME("Unimplemented optional parameter\n");
649
650     if (!Asynchronous)
651     {
652         OBJECT_ATTRIBUTES attr;
653         InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
654         ret = NtCreateEvent( &Event, EVENT_ALL_ACCESS, &attr, FALSE, FALSE );
655         if (ret != STATUS_SUCCESS)
656             return ret;
657     }
658
659     SERVER_START_REQ( set_registry_notification )
660     {
661         req->hkey    = wine_server_obj_handle( KeyHandle );
662         req->event   = wine_server_obj_handle( Event );
663         req->subtree = WatchSubtree;
664         req->filter  = CompletionFilter;
665         ret = wine_server_call( req );
666     }
667     SERVER_END_REQ;
668  
669     if (!Asynchronous)
670     {
671         if (ret == STATUS_SUCCESS)
672             NtWaitForSingleObject( Event, FALSE, NULL );
673         NtClose( Event );
674     }
675
676     return STATUS_SUCCESS;
677 }
678
679 /******************************************************************************
680  * NtQueryMultipleValueKey [NTDLL]
681  * ZwQueryMultipleValueKey
682  */
683
684 NTSTATUS WINAPI NtQueryMultipleValueKey(
685         HANDLE KeyHandle,
686         PKEY_MULTIPLE_VALUE_INFORMATION ListOfValuesToQuery,
687         ULONG NumberOfItems,
688         PVOID MultipleValueInformation,
689         ULONG Length,
690         PULONG  ReturnLength)
691 {
692         FIXME("(%p,%p,0x%08x,%p,0x%08x,%p) stub!\n",
693         KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
694         Length,ReturnLength);
695         return STATUS_SUCCESS;
696 }
697
698 /******************************************************************************
699  * NtReplaceKey [NTDLL.@]
700  * ZwReplaceKey [NTDLL.@]
701  */
702 NTSTATUS WINAPI NtReplaceKey(
703         IN POBJECT_ATTRIBUTES ObjectAttributes,
704         IN HANDLE Key,
705         IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
706 {
707     FIXME("(%s,%p,%s),stub!\n", debugstr_ObjectAttributes(ObjectAttributes), Key,
708           debugstr_ObjectAttributes(ReplacedObjectAttributes) );
709     return STATUS_SUCCESS;
710 }
711 /******************************************************************************
712  * NtRestoreKey [NTDLL.@]
713  * ZwRestoreKey [NTDLL.@]
714  */
715 NTSTATUS WINAPI NtRestoreKey(
716         HANDLE KeyHandle,
717         HANDLE FileHandle,
718         ULONG RestoreFlags)
719 {
720         FIXME("(%p,%p,0x%08x) stub\n",
721         KeyHandle, FileHandle, RestoreFlags);
722         return STATUS_SUCCESS;
723 }
724 /******************************************************************************
725  * NtSaveKey [NTDLL.@]
726  * ZwSaveKey [NTDLL.@]
727  */
728 NTSTATUS WINAPI NtSaveKey(IN HANDLE KeyHandle, IN HANDLE FileHandle)
729 {
730     NTSTATUS ret;
731
732     TRACE("(%p,%p)\n", KeyHandle, FileHandle);
733
734     SERVER_START_REQ( save_registry )
735     {
736         req->hkey = wine_server_obj_handle( KeyHandle );
737         req->file = wine_server_obj_handle( FileHandle );
738         ret = wine_server_call( req );
739     }
740     SERVER_END_REQ;
741
742     return ret;
743 }
744 /******************************************************************************
745  * NtSetInformationKey [NTDLL.@]
746  * ZwSetInformationKey [NTDLL.@]
747  */
748 NTSTATUS WINAPI NtSetInformationKey(
749         IN HANDLE KeyHandle,
750         IN const int KeyInformationClass,
751         IN PVOID KeyInformation,
752         IN ULONG KeyInformationLength)
753 {
754         FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
755         KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
756         return STATUS_SUCCESS;
757 }
758
759
760 /******************************************************************************
761  * NtSetValueKey [NTDLL.@]
762  * ZwSetValueKey [NTDLL.@]
763  *
764  * NOTES
765  *   win95 does not care about count for REG_SZ and finds out the len by itself (js)
766  *   NT does definitely care (aj)
767  */
768 NTSTATUS WINAPI NtSetValueKey( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
769                                ULONG type, const void *data, ULONG count )
770 {
771     NTSTATUS ret;
772
773     TRACE( "(%p,%s,%d,%p,%d)\n", hkey, debugstr_us(name), type, data, count );
774
775     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
776
777     SERVER_START_REQ( set_key_value )
778     {
779         req->hkey    = wine_server_obj_handle( hkey );
780         req->type    = type;
781         req->namelen = name->Length;
782         wine_server_add_data( req, name->Buffer, name->Length );
783         wine_server_add_data( req, data, count );
784         ret = wine_server_call( req );
785     }
786     SERVER_END_REQ;
787     return ret;
788 }
789
790 /******************************************************************************
791  * RtlpNtSetValueKey [NTDLL.@]
792  *
793  */
794 NTSTATUS WINAPI RtlpNtSetValueKey( HANDLE hkey, ULONG type, const void *data,
795                                    ULONG count )
796 {
797     UNICODE_STRING name;
798
799     name.Length = 0;
800     return NtSetValueKey( hkey, &name, 0, type, data, count );
801 }
802
803 /******************************************************************************
804  * NtUnloadKey [NTDLL.@]
805  * ZwUnloadKey [NTDLL.@]
806  */
807 NTSTATUS WINAPI NtUnloadKey(IN POBJECT_ATTRIBUTES attr)
808 {
809     NTSTATUS ret;
810
811     TRACE("(%p)\n", attr);
812
813     SERVER_START_REQ( unload_registry )
814     {
815         req->hkey = wine_server_obj_handle( attr->RootDirectory );
816         ret = wine_server_call(req);
817     }
818     SERVER_END_REQ;
819
820     return ret;
821 }
822
823 /******************************************************************************
824  *  RtlFormatCurrentUserKeyPath         [NTDLL.@]
825  *
826  */
827 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
828 {
829     static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
830     HANDLE token;
831     NTSTATUS status;
832
833     status = NtOpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &token);
834     if (status == STATUS_NO_TOKEN)
835         status = NtOpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token);
836     if (status == STATUS_SUCCESS)
837     {
838         char buffer[sizeof(TOKEN_USER) + sizeof(SID) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES];
839         DWORD len = sizeof(buffer);
840
841         status = NtQueryInformationToken(token, TokenUser, buffer, len, &len);
842         if (status == STATUS_SUCCESS)
843         {
844             KeyPath->MaximumLength = 0;
845             status = RtlConvertSidToUnicodeString(KeyPath, ((TOKEN_USER *)buffer)->User.Sid, FALSE);
846             if (status == STATUS_BUFFER_OVERFLOW)
847             {
848                 PWCHAR buf = RtlAllocateHeap(GetProcessHeap(), 0,
849                                              sizeof(pathW) + KeyPath->Length + sizeof(WCHAR));
850                 if (buf)
851                 {
852                     memcpy(buf, pathW, sizeof(pathW));
853                     KeyPath->MaximumLength = KeyPath->Length + sizeof(WCHAR);
854                     KeyPath->Buffer = (PWCHAR)((LPBYTE)buf + sizeof(pathW));
855                     status = RtlConvertSidToUnicodeString(KeyPath,
856                                                           ((TOKEN_USER *)buffer)->User.Sid, FALSE);
857                     KeyPath->Buffer = buf;
858                     KeyPath->Length += sizeof(pathW);
859                     KeyPath->MaximumLength += sizeof(pathW);
860                 }
861                 else
862                     status = STATUS_NO_MEMORY;
863             }
864         }
865         NtClose(token);
866     }
867     return status;
868 }
869
870 /******************************************************************************
871  *  RtlOpenCurrentUser          [NTDLL.@]
872  *
873  * NOTES
874  *  If we return just HKEY_CURRENT_USER the advapi tries to find a remote
875  *  registry (odd handle) and fails.
876  */
877 NTSTATUS WINAPI RtlOpenCurrentUser(
878         IN ACCESS_MASK DesiredAccess, /* [in] */
879         OUT PHANDLE KeyHandle)        /* [out] handle of HKEY_CURRENT_USER */
880 {
881         OBJECT_ATTRIBUTES ObjectAttributes;
882         UNICODE_STRING ObjectName;
883         NTSTATUS ret;
884
885         TRACE("(0x%08x, %p)\n",DesiredAccess, KeyHandle);
886
887         if ((ret = RtlFormatCurrentUserKeyPath(&ObjectName))) return ret;
888         InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
889         ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
890         RtlFreeUnicodeString(&ObjectName);
891         return ret;
892 }
893
894
895 static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
896                                         PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
897 {
898     PUNICODE_STRING str;
899     UNICODE_STRING src, dst;
900     LONG *bin;
901     ULONG offset;
902     PWSTR wstr;
903     DWORD res;
904     NTSTATUS status = STATUS_SUCCESS;
905     ULONG len;
906     LPWSTR String;
907     ULONG count = 0;
908
909     if (pInfo == NULL)
910     {
911         if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
912             return STATUS_INVALID_PARAMETER;
913         else
914         {
915             status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
916                                           pQuery->DefaultLength, pContext, pQuery->EntryContext);
917         }
918         return status;
919     }
920     len = pInfo->DataLength;
921
922     if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
923     {
924         str = pQuery->EntryContext;
925
926         switch(pInfo->Type)
927         {
928         case REG_EXPAND_SZ:
929             if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
930             {
931                 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
932                 res = 0;
933                 dst.MaximumLength = 0;
934                 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
935                 dst.Length = 0;
936                 dst.MaximumLength = res;
937                 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
938                 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
939                 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
940                                      dst.Length, pContext, pQuery->EntryContext);
941                 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
942             }
943
944         case REG_SZ:
945         case REG_LINK:
946             if (str->Buffer == NULL)
947                 RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
948             else
949                 RtlAppendUnicodeToString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
950             break;
951
952         case REG_MULTI_SZ:
953             if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
954                 return STATUS_INVALID_PARAMETER;
955
956             if (str->Buffer == NULL)
957             {
958                 str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
959                 str->MaximumLength = len;
960             }
961             len = min(len, str->MaximumLength);
962             memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
963             str->Length = len;
964             break;
965
966         default:
967             bin = pQuery->EntryContext;
968             if (pInfo->DataLength <= sizeof(ULONG))
969                 memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
970                     pInfo->DataLength);
971             else
972             {
973                 if (bin[0] <= sizeof(ULONG))
974                 {
975                     memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
976                     min(-bin[0], pInfo->DataLength));
977                 }
978                 else
979                 {
980                    len = min(bin[0], pInfo->DataLength);
981                     bin[1] = len;
982                     bin[2] = pInfo->Type;
983                     memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
984                 }
985            }
986            break;
987         }
988     }
989     else
990     {
991         if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
992            (pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
993         {
994             status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type,
995                 ((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
996                 pContext, pQuery->EntryContext);
997         }
998         else if (pInfo->Type == REG_EXPAND_SZ)
999         {
1000             RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1001             res = 0;
1002             dst.MaximumLength = 0;
1003             RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1004             dst.Length = 0;
1005             dst.MaximumLength = res;
1006             dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1007             RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1008             status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1009                                           dst.Length, pContext, pQuery->EntryContext);
1010             RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1011         }
1012         else /* REG_MULTI_SZ */
1013         {
1014             if(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
1015             {
1016                 for (offset = 0; offset <= pInfo->DataLength; offset += len + sizeof(WCHAR))
1017                     {
1018                     wstr = (WCHAR*)(((CHAR*)pInfo) + offset);
1019                     len = strlenW(wstr) * sizeof(WCHAR);
1020                     status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, wstr, len,
1021                         pContext, pQuery->EntryContext);
1022                     if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1023                         return status;
1024                     }
1025             }
1026             else
1027             {
1028                 while(count<=pInfo->DataLength)
1029                 {
1030                     String = (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset)+count;
1031                     count+=strlenW(String)+1;
1032                     RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1033                     res = 0;
1034                     dst.MaximumLength = 0;
1035                     RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1036                     dst.Length = 0;
1037                     dst.MaximumLength = res;
1038                     dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1039                     RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1040                     status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1041                                                   dst.Length, pContext, pQuery->EntryContext);
1042                     RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1043                     if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1044                         return status;
1045                 }
1046             }
1047         }
1048     }
1049     return status;
1050 }
1051
1052
1053 static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
1054 {
1055     UNICODE_STRING KeyString;
1056     OBJECT_ATTRIBUTES regkey;
1057     PCWSTR base;
1058     INT len;
1059     NTSTATUS status;
1060
1061     static const WCHAR empty[] = {0};
1062     static const WCHAR control[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1063     '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1064     'C','o','n','t','r','o','l','\\',0};
1065
1066     static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1067     'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1068
1069     static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1070     'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1071     'S','e','r','v','i','c','e','s','\\',0};
1072
1073     static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1074     'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1075
1076     static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1077     'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1078     'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1079
1080     switch (RelativeTo & 0xff)
1081     {
1082     case RTL_REGISTRY_ABSOLUTE:
1083         base = empty;
1084         break;
1085
1086     case RTL_REGISTRY_CONTROL:
1087         base = control;
1088         break;
1089
1090     case RTL_REGISTRY_DEVICEMAP:
1091         base = devicemap;
1092         break;
1093
1094     case RTL_REGISTRY_SERVICES:
1095         base = services;
1096         break;
1097
1098     case RTL_REGISTRY_USER:
1099         base = user;
1100         break;
1101
1102     case RTL_REGISTRY_WINDOWS_NT:
1103         base = windows_nt;
1104         break;
1105
1106     default:
1107         return STATUS_INVALID_PARAMETER;
1108     }
1109
1110     len = (strlenW(base) + strlenW(Path) + 1) * sizeof(WCHAR);
1111     KeyString.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1112     if (KeyString.Buffer == NULL)
1113         return STATUS_NO_MEMORY;
1114
1115     strcpyW(KeyString.Buffer, base);
1116     strcatW(KeyString.Buffer, Path);
1117     KeyString.Length = len - sizeof(WCHAR);
1118     KeyString.MaximumLength = len;
1119     InitializeObjectAttributes(&regkey, &KeyString, OBJ_CASE_INSENSITIVE, NULL, NULL);
1120     status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
1121     RtlFreeHeap(GetProcessHeap(), 0, KeyString.Buffer);
1122     return status;
1123 }
1124
1125 /*************************************************************************
1126  * RtlQueryRegistryValues   [NTDLL.@]
1127  *
1128  * Query multiple registry values with a signle call.
1129  *
1130  * PARAMS
1131  *  RelativeTo  [I] Registry path that Path refers to
1132  *  Path        [I] Path to key
1133  *  QueryTable  [I] Table of key values to query
1134  *  Context     [I] Parameter to pass to the application defined QueryRoutine function
1135  *  Environment [I] Optional parameter to use when performing expansion
1136  *
1137  * RETURNS
1138  *  STATUS_SUCCESS or an appropriate NTSTATUS error code.
1139  */
1140 NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
1141                                        IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
1142                                        IN PVOID Environment OPTIONAL)
1143 {
1144     UNICODE_STRING Value;
1145     HANDLE handle, topkey;
1146     PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
1147     ULONG len, buflen = 0;
1148     NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
1149     INT i;
1150
1151     TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
1152
1153     if(Path == NULL)
1154         return STATUS_INVALID_PARAMETER;
1155
1156     /* get a valid handle */
1157     if (RelativeTo & RTL_REGISTRY_HANDLE)
1158         topkey = handle = (HANDLE)Path;
1159     else
1160     {
1161         status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
1162         handle = topkey;
1163     }
1164     if(status != STATUS_SUCCESS)
1165         return status;
1166
1167     /* Process query table entries */
1168     for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
1169     {
1170         if (QueryTable->Flags &
1171             (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
1172         {
1173             /* topkey must be kept open just in case we will reuse it later */
1174             if (handle != topkey)
1175                 NtClose(handle);
1176
1177             if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
1178             {
1179                 handle = 0;
1180                 status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
1181                 if(status != STATUS_SUCCESS)
1182                 {
1183                     ret = status;
1184                     goto out;
1185                 }
1186             }
1187             else
1188                 handle = topkey;
1189         }
1190
1191         if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
1192         {
1193             QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
1194                 Context, QueryTable->EntryContext);
1195             continue;
1196         }
1197
1198         if (!handle)
1199         {
1200             if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1201             {
1202                 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1203                 goto out;
1204             }
1205             continue;
1206         }
1207
1208         if (QueryTable->Name == NULL)
1209         {
1210             if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
1211             {
1212                 ret = STATUS_INVALID_PARAMETER;
1213                 goto out;
1214             }
1215
1216             /* Report all subkeys */
1217             for (i = 0;; ++i)
1218             {
1219                 status = NtEnumerateValueKey(handle, i,
1220                     KeyValueFullInformation, pInfo, buflen, &len);
1221                 if (status == STATUS_NO_MORE_ENTRIES)
1222                     break;
1223                 if (status == STATUS_BUFFER_OVERFLOW ||
1224                     status == STATUS_BUFFER_TOO_SMALL)
1225                 {
1226                     buflen = len;
1227                     RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1228                     pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1229                     NtEnumerateValueKey(handle, i, KeyValueFullInformation,
1230                         pInfo, buflen, &len);
1231                 }
1232
1233                 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1234                 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1235                 {
1236                     ret = status;
1237                     goto out;
1238                 }
1239                 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1240                 {
1241                     RtlInitUnicodeString(&Value, pInfo->Name);
1242                     NtDeleteValueKey(handle, &Value);
1243                 }
1244             }
1245
1246             if (i == 0  && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
1247             {
1248                 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1249                 goto out;
1250             }
1251         }
1252         else
1253         {
1254             RtlInitUnicodeString(&Value, QueryTable->Name);
1255             status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
1256                 pInfo, buflen, &len);
1257             if (status == STATUS_BUFFER_OVERFLOW ||
1258                 status == STATUS_BUFFER_TOO_SMALL)
1259             {
1260                 buflen = len;
1261                 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1262                 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1263                 status = NtQueryValueKey(handle, &Value,
1264                     KeyValueFullInformation, pInfo, buflen, &len);
1265             }
1266             if (status != STATUS_SUCCESS)
1267             {
1268                 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1269                 {
1270                     ret = STATUS_OBJECT_NAME_NOT_FOUND;
1271                     goto out;
1272                 }
1273                 status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
1274                 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1275                 {
1276                     ret = status;
1277                     goto out;
1278                 }
1279             }
1280             else
1281             {
1282                 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1283                 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1284                 {
1285                     ret = status;
1286                     goto out;
1287                 }
1288                 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1289                     NtDeleteValueKey(handle, &Value);
1290             }
1291         }
1292     }
1293
1294 out:
1295     RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1296     if (handle != topkey)
1297         NtClose(handle);
1298     NtClose(topkey);
1299     return ret;
1300 }
1301
1302 /*************************************************************************
1303  * RtlCheckRegistryKey   [NTDLL.@]
1304  *
1305  * Query multiple registry values with a signle call.
1306  *
1307  * PARAMS
1308  *  RelativeTo [I] Registry path that Path refers to
1309  *  Path       [I] Path to key
1310  *
1311  * RETURNS
1312  *  STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1313  */
1314 NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
1315 {
1316     HANDLE handle;
1317     NTSTATUS status;
1318
1319     TRACE("(%d, %s)\n", RelativeTo, debugstr_w(Path));
1320
1321     if((!RelativeTo) && Path == NULL)
1322         return STATUS_OBJECT_PATH_SYNTAX_BAD;
1323     if(RelativeTo & RTL_REGISTRY_HANDLE)
1324         return STATUS_SUCCESS;
1325
1326     status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1327     if (handle) NtClose(handle);
1328     if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
1329     return status;
1330 }
1331
1332 /*************************************************************************
1333  * RtlDeleteRegistryValue   [NTDLL.@]
1334  *
1335  * Query multiple registry values with a signle call.
1336  *
1337  * PARAMS
1338  *  RelativeTo [I] Registry path that Path refers to
1339  *  Path       [I] Path to key
1340  *  ValueName  [I] Name of the value to delete
1341  *
1342  * RETURNS
1343  *  STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1344  */
1345 NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
1346 {
1347     NTSTATUS status;
1348     HANDLE handle;
1349     UNICODE_STRING Value;
1350
1351     TRACE("(%d, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
1352
1353     RtlInitUnicodeString(&Value, ValueName);
1354     if(RelativeTo == RTL_REGISTRY_HANDLE)
1355     {
1356         return NtDeleteValueKey((HANDLE)Path, &Value);
1357     }
1358     status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1359     if (status) return status;
1360     status = NtDeleteValueKey(handle, &Value);
1361     NtClose(handle);
1362     return status;
1363 }
1364
1365 /*************************************************************************
1366  * RtlWriteRegistryValue   [NTDLL.@]
1367  *
1368  * Sets the registry value with provided data.
1369  *
1370  * PARAMS
1371  *  RelativeTo [I] Registry path that path parameter refers to
1372  *  path       [I] Path to the key (or handle - see RTL_GetKeyHandle)
1373  *  name       [I] Name of the registry value to set
1374  *  type       [I] Type of the registry key to set
1375  *  data       [I] Pointer to the user data to be set
1376  *  length     [I] Length of the user data pointed by data
1377  *
1378  * RETURNS
1379  *  STATUS_SUCCESS if the specified key is successfully set,
1380  *  or an NTSTATUS error code.
1381  */
1382 NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
1383                                        ULONG type, PVOID data, ULONG length )
1384 {
1385     HANDLE hkey;
1386     NTSTATUS status;
1387     UNICODE_STRING str;
1388
1389     TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
1390            type, data, length );
1391
1392     RtlInitUnicodeString( &str, name );
1393
1394     if (RelativeTo == RTL_REGISTRY_HANDLE)
1395         return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
1396
1397     status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
1398     if (status != STATUS_SUCCESS) return status;
1399
1400     status = NtSetValueKey( hkey, &str, 0, type, data, length );
1401     NtClose( hkey );
1402
1403     return status;
1404 }