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