comctl32/tests: Destroy the window after the tests.
[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("(%p),stub!\n", Key);
697         dump_ObjectAttributes(ObjectAttributes);
698         dump_ObjectAttributes(ReplacedObjectAttributes);
699         return STATUS_SUCCESS;
700 }
701 /******************************************************************************
702  * NtRestoreKey [NTDLL.@]
703  * ZwRestoreKey [NTDLL.@]
704  */
705 NTSTATUS WINAPI NtRestoreKey(
706         HANDLE KeyHandle,
707         HANDLE FileHandle,
708         ULONG RestoreFlags)
709 {
710         FIXME("(%p,%p,0x%08x) stub\n",
711         KeyHandle, FileHandle, RestoreFlags);
712         return STATUS_SUCCESS;
713 }
714 /******************************************************************************
715  * NtSaveKey [NTDLL.@]
716  * ZwSaveKey [NTDLL.@]
717  */
718 NTSTATUS WINAPI NtSaveKey(IN HANDLE KeyHandle, IN HANDLE FileHandle)
719 {
720     NTSTATUS ret;
721
722     TRACE("(%p,%p)\n", KeyHandle, FileHandle);
723
724     SERVER_START_REQ( save_registry )
725     {
726         req->hkey = wine_server_obj_handle( KeyHandle );
727         req->file = wine_server_obj_handle( FileHandle );
728         ret = wine_server_call( req );
729     }
730     SERVER_END_REQ;
731
732     return ret;
733 }
734 /******************************************************************************
735  * NtSetInformationKey [NTDLL.@]
736  * ZwSetInformationKey [NTDLL.@]
737  */
738 NTSTATUS WINAPI NtSetInformationKey(
739         IN HANDLE KeyHandle,
740         IN const int KeyInformationClass,
741         IN PVOID KeyInformation,
742         IN ULONG KeyInformationLength)
743 {
744         FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
745         KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
746         return STATUS_SUCCESS;
747 }
748
749
750 /******************************************************************************
751  * NtSetValueKey [NTDLL.@]
752  * ZwSetValueKey [NTDLL.@]
753  *
754  * NOTES
755  *   win95 does not care about count for REG_SZ and finds out the len by itself (js)
756  *   NT does definitely care (aj)
757  */
758 NTSTATUS WINAPI NtSetValueKey( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
759                                ULONG type, const void *data, ULONG count )
760 {
761     NTSTATUS ret;
762
763     TRACE( "(%p,%s,%d,%p,%d)\n", hkey, debugstr_us(name), type, data, count );
764
765     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
766
767     SERVER_START_REQ( set_key_value )
768     {
769         req->hkey    = wine_server_obj_handle( hkey );
770         req->type    = type;
771         req->namelen = name->Length;
772         wine_server_add_data( req, name->Buffer, name->Length );
773         wine_server_add_data( req, data, count );
774         ret = wine_server_call( req );
775     }
776     SERVER_END_REQ;
777     return ret;
778 }
779
780 /******************************************************************************
781  * RtlpNtSetValueKey [NTDLL.@]
782  *
783  */
784 NTSTATUS WINAPI RtlpNtSetValueKey( HANDLE hkey, ULONG type, const void *data,
785                                    ULONG count )
786 {
787     UNICODE_STRING name;
788
789     name.Length = 0;
790     return NtSetValueKey( hkey, &name, 0, type, data, count );
791 }
792
793 /******************************************************************************
794  * NtUnloadKey [NTDLL.@]
795  * ZwUnloadKey [NTDLL.@]
796  */
797 NTSTATUS WINAPI NtUnloadKey(IN POBJECT_ATTRIBUTES attr)
798 {
799     NTSTATUS ret;
800
801     TRACE("(%p)\n", attr);
802
803     SERVER_START_REQ( unload_registry )
804     {
805         req->hkey = wine_server_obj_handle( attr->RootDirectory );
806         ret = wine_server_call(req);
807     }
808     SERVER_END_REQ;
809
810     return ret;
811 }
812
813 /******************************************************************************
814  *  RtlFormatCurrentUserKeyPath         [NTDLL.@]
815  *
816  */
817 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
818 {
819     static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
820     HANDLE token;
821     NTSTATUS status;
822
823     status = NtOpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &token);
824     if (status == STATUS_NO_TOKEN)
825         status = NtOpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token);
826     if (status == STATUS_SUCCESS)
827     {
828         char buffer[sizeof(TOKEN_USER) + sizeof(SID) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES];
829         DWORD len = sizeof(buffer);
830
831         status = NtQueryInformationToken(token, TokenUser, buffer, len, &len);
832         if (status == STATUS_SUCCESS)
833         {
834             KeyPath->MaximumLength = 0;
835             status = RtlConvertSidToUnicodeString(KeyPath, ((TOKEN_USER *)buffer)->User.Sid, FALSE);
836             if (status == STATUS_BUFFER_OVERFLOW)
837             {
838                 PWCHAR buf = RtlAllocateHeap(GetProcessHeap(), 0,
839                                              sizeof(pathW) + KeyPath->Length + sizeof(WCHAR));
840                 if (buf)
841                 {
842                     memcpy(buf, pathW, sizeof(pathW));
843                     KeyPath->MaximumLength = KeyPath->Length + sizeof(WCHAR);
844                     KeyPath->Buffer = (PWCHAR)((LPBYTE)buf + sizeof(pathW));
845                     status = RtlConvertSidToUnicodeString(KeyPath,
846                                                           ((TOKEN_USER *)buffer)->User.Sid, FALSE);
847                     KeyPath->Buffer = buf;
848                     KeyPath->Length += sizeof(pathW);
849                     KeyPath->MaximumLength += sizeof(pathW);
850                 }
851                 else
852                     status = STATUS_NO_MEMORY;
853             }
854         }
855         NtClose(token);
856     }
857     return status;
858 }
859
860 /******************************************************************************
861  *  RtlOpenCurrentUser          [NTDLL.@]
862  *
863  * NOTES
864  *  If we return just HKEY_CURRENT_USER the advapi tries to find a remote
865  *  registry (odd handle) and fails.
866  */
867 NTSTATUS WINAPI RtlOpenCurrentUser(
868         IN ACCESS_MASK DesiredAccess, /* [in] */
869         OUT PHANDLE KeyHandle)        /* [out] handle of HKEY_CURRENT_USER */
870 {
871         OBJECT_ATTRIBUTES ObjectAttributes;
872         UNICODE_STRING ObjectName;
873         NTSTATUS ret;
874
875         TRACE("(0x%08x, %p)\n",DesiredAccess, KeyHandle);
876
877         if ((ret = RtlFormatCurrentUserKeyPath(&ObjectName))) return ret;
878         InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
879         ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
880         RtlFreeUnicodeString(&ObjectName);
881         return ret;
882 }
883
884
885 static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
886                                         PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
887 {
888     PUNICODE_STRING str;
889     UNICODE_STRING src, dst;
890     LONG *bin;
891     ULONG offset;
892     PWSTR wstr;
893     DWORD res;
894     NTSTATUS status = STATUS_SUCCESS;
895     ULONG len;
896     LPWSTR String;
897     ULONG count = 0;
898
899     if (pInfo == NULL)
900     {
901         if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
902             return STATUS_INVALID_PARAMETER;
903         else
904         {
905             status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
906                                           pQuery->DefaultLength, pContext, pQuery->EntryContext);
907         }
908         return status;
909     }
910     len = pInfo->DataLength;
911
912     if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
913     {
914         str = (PUNICODE_STRING)pQuery->EntryContext;
915  
916         switch(pInfo->Type)
917         {
918         case REG_EXPAND_SZ:
919             if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
920             {
921                 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
922                 res = 0;
923                 dst.MaximumLength = 0;
924                 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
925                 dst.Length = 0;
926                 dst.MaximumLength = res;
927                 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
928                 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
929                 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
930                                      dst.Length, pContext, pQuery->EntryContext);
931                 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
932             }
933
934         case REG_SZ:
935         case REG_LINK:
936             if (str->Buffer == NULL)
937                 RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
938             else
939                 RtlAppendUnicodeToString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
940             break;
941
942         case REG_MULTI_SZ:
943             if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
944                 return STATUS_INVALID_PARAMETER;
945
946             if (str->Buffer == NULL)
947             {
948                 str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
949                 str->MaximumLength = len;
950             }
951             len = min(len, str->MaximumLength);
952             memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
953             str->Length = len;
954             break;
955
956         default:
957             bin = (LONG*)pQuery->EntryContext;
958             if (pInfo->DataLength <= sizeof(ULONG))
959                 memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
960                     pInfo->DataLength);
961             else
962             {
963                 if (bin[0] <= sizeof(ULONG))
964                 {
965                     memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
966                     min(-bin[0], pInfo->DataLength));
967                 }
968                 else
969                 {
970                    len = min(bin[0], pInfo->DataLength);
971                     bin[1] = len;
972                     bin[2] = pInfo->Type;
973                     memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
974                 }
975            }
976            break;
977         }
978     }
979     else
980     {
981         if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
982            (pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
983         {
984             status = pQuery->QueryRoutine(pInfo->Name, pInfo->Type,
985                 ((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
986                 pContext, pQuery->EntryContext);
987         }
988         else if (pInfo->Type == REG_EXPAND_SZ)
989         {
990             RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
991             res = 0;
992             dst.MaximumLength = 0;
993             RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
994             dst.Length = 0;
995             dst.MaximumLength = res;
996             dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
997             RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
998             status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
999                                           dst.Length, pContext, pQuery->EntryContext);
1000             RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1001         }
1002         else /* REG_MULTI_SZ */
1003         {
1004             if(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
1005             {
1006                 for (offset = 0; offset <= pInfo->DataLength; offset += len + sizeof(WCHAR))
1007                     {
1008                     wstr = (WCHAR*)(((CHAR*)pInfo) + offset);
1009                     len = strlenW(wstr) * sizeof(WCHAR);
1010                     status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, wstr, len,
1011                         pContext, pQuery->EntryContext);
1012                     if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1013                         return status;
1014                     }
1015             }
1016             else
1017             {
1018                 while(count<=pInfo->DataLength)
1019                 {
1020                     String = (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset)+count;
1021                     count+=strlenW(String)+1;
1022                     RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1023                     res = 0;
1024                     dst.MaximumLength = 0;
1025                     RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1026                     dst.Length = 0;
1027                     dst.MaximumLength = res;
1028                     dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1029                     RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1030                     status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1031                                                   dst.Length, pContext, pQuery->EntryContext);
1032                     RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1033                     if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1034                         return status;
1035                 }
1036             }
1037         }
1038     }
1039     return status;
1040 }
1041
1042
1043 static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
1044 {
1045     UNICODE_STRING KeyString;
1046     OBJECT_ATTRIBUTES regkey;
1047     PCWSTR base;
1048     INT len;
1049     NTSTATUS status;
1050
1051     static const WCHAR empty[] = {0};
1052     static const WCHAR control[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1053     '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1054     'C','o','n','t','r','o','l','\\',0};
1055
1056     static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1057     'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1058
1059     static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1060     'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1061     'S','e','r','v','i','c','e','s','\\',0};
1062
1063     static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1064     'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1065
1066     static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1067     'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1068     'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1069
1070     switch (RelativeTo & 0xff)
1071     {
1072     case RTL_REGISTRY_ABSOLUTE:
1073         base = empty;
1074         break;
1075
1076     case RTL_REGISTRY_CONTROL:
1077         base = control;
1078         break;
1079
1080     case RTL_REGISTRY_DEVICEMAP:
1081         base = devicemap;
1082         break;
1083
1084     case RTL_REGISTRY_SERVICES:
1085         base = services;
1086         break;
1087
1088     case RTL_REGISTRY_USER:
1089         base = user;
1090         break;
1091
1092     case RTL_REGISTRY_WINDOWS_NT:
1093         base = windows_nt;
1094         break;
1095
1096     default:
1097         return STATUS_INVALID_PARAMETER;
1098     }
1099
1100     len = (strlenW(base) + strlenW(Path) + 1) * sizeof(WCHAR);
1101     KeyString.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1102     if (KeyString.Buffer == NULL)
1103         return STATUS_NO_MEMORY;
1104
1105     strcpyW(KeyString.Buffer, base);
1106     strcatW(KeyString.Buffer, Path);
1107     KeyString.Length = len - sizeof(WCHAR);
1108     KeyString.MaximumLength = len;
1109     InitializeObjectAttributes(&regkey, &KeyString, OBJ_CASE_INSENSITIVE, NULL, NULL);
1110     status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
1111     RtlFreeHeap(GetProcessHeap(), 0, KeyString.Buffer);
1112     return status;
1113 }
1114
1115 /*************************************************************************
1116  * RtlQueryRegistryValues   [NTDLL.@]
1117  *
1118  * Query multiple registry values with a signle call.
1119  *
1120  * PARAMS
1121  *  RelativeTo  [I] Registry path that Path refers to
1122  *  Path        [I] Path to key
1123  *  QueryTable  [I] Table of key values to query
1124  *  Context     [I] Parameter to pass to the application defined QueryRoutine function
1125  *  Environment [I] Optional parameter to use when performing expansion
1126  *
1127  * RETURNS
1128  *  STATUS_SUCCESS or an appropriate NTSTATUS error code.
1129  */
1130 NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
1131                                        IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
1132                                        IN PVOID Environment OPTIONAL)
1133 {
1134     UNICODE_STRING Value;
1135     HANDLE handle, topkey;
1136     PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
1137     ULONG len, buflen = 0;
1138     NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
1139     INT i;
1140
1141     TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
1142
1143     if(Path == NULL)
1144         return STATUS_INVALID_PARAMETER;
1145
1146     /* get a valid handle */
1147     if (RelativeTo & RTL_REGISTRY_HANDLE)
1148         topkey = handle = (HANDLE)Path;
1149     else
1150     {
1151         status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
1152         handle = topkey;
1153     }
1154     if(status != STATUS_SUCCESS)
1155         return status;
1156
1157     /* Process query table entries */
1158     for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
1159     {
1160         if (QueryTable->Flags &
1161             (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
1162         {
1163             /* topkey must be kept open just in case we will reuse it later */
1164             if (handle != topkey)
1165                 NtClose(handle);
1166
1167             if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
1168             {
1169                 handle = 0;
1170                 status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
1171                 if(status != STATUS_SUCCESS)
1172                 {
1173                     ret = status;
1174                     goto out;
1175                 }
1176             }
1177             else
1178                 handle = topkey;
1179         }
1180
1181         if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
1182         {
1183             QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
1184                 Context, QueryTable->EntryContext);
1185             continue;
1186         }
1187
1188         if (!handle)
1189         {
1190             if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1191             {
1192                 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1193                 goto out;
1194             }
1195             continue;
1196         }
1197
1198         if (QueryTable->Name == NULL)
1199         {
1200             if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
1201             {
1202                 ret = STATUS_INVALID_PARAMETER;
1203                 goto out;
1204             }
1205
1206             /* Report all subkeys */
1207             for (i = 0;; ++i)
1208             {
1209                 status = NtEnumerateValueKey(handle, i,
1210                     KeyValueFullInformation, pInfo, buflen, &len);
1211                 if (status == STATUS_NO_MORE_ENTRIES)
1212                     break;
1213                 if (status == STATUS_BUFFER_OVERFLOW ||
1214                     status == STATUS_BUFFER_TOO_SMALL)
1215                 {
1216                     buflen = len;
1217                     RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1218                     pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1219                     NtEnumerateValueKey(handle, i, KeyValueFullInformation,
1220                         pInfo, buflen, &len);
1221                 }
1222
1223                 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1224                 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1225                 {
1226                     ret = status;
1227                     goto out;
1228                 }
1229                 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1230                 {
1231                     RtlInitUnicodeString(&Value, pInfo->Name);
1232                     NtDeleteValueKey(handle, &Value);
1233                 }
1234             }
1235
1236             if (i == 0  && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
1237             {
1238                 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1239                 goto out;
1240             }
1241         }
1242         else
1243         {
1244             RtlInitUnicodeString(&Value, QueryTable->Name);
1245             status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
1246                 pInfo, buflen, &len);
1247             if (status == STATUS_BUFFER_OVERFLOW ||
1248                 status == STATUS_BUFFER_TOO_SMALL)
1249             {
1250                 buflen = len;
1251                 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1252                 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1253                 status = NtQueryValueKey(handle, &Value,
1254                     KeyValueFullInformation, pInfo, buflen, &len);
1255             }
1256             if (status != STATUS_SUCCESS)
1257             {
1258                 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1259                 {
1260                     ret = STATUS_OBJECT_NAME_NOT_FOUND;
1261                     goto out;
1262                 }
1263                 status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
1264                 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1265                 {
1266                     ret = status;
1267                     goto out;
1268                 }
1269             }
1270             else
1271             {
1272                 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1273                 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1274                 {
1275                     ret = status;
1276                     goto out;
1277                 }
1278                 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1279                     NtDeleteValueKey(handle, &Value);
1280             }
1281         }
1282     }
1283
1284 out:
1285     RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1286     if (handle != topkey)
1287         NtClose(handle);
1288     NtClose(topkey);
1289     return ret;
1290 }
1291
1292 /*************************************************************************
1293  * RtlCheckRegistryKey   [NTDLL.@]
1294  *
1295  * Query multiple registry values with a signle call.
1296  *
1297  * PARAMS
1298  *  RelativeTo [I] Registry path that Path refers to
1299  *  Path       [I] Path to key
1300  *
1301  * RETURNS
1302  *  STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1303  */
1304 NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
1305 {
1306     HANDLE handle;
1307     NTSTATUS status;
1308
1309     TRACE("(%d, %s)\n", RelativeTo, debugstr_w(Path));
1310
1311     if((!RelativeTo) && Path == NULL)
1312         return STATUS_OBJECT_PATH_SYNTAX_BAD;
1313     if(RelativeTo & RTL_REGISTRY_HANDLE)
1314         return STATUS_SUCCESS;
1315
1316     status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1317     if (handle) NtClose(handle);
1318     if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
1319     return status;
1320 }
1321
1322 /*************************************************************************
1323  * RtlDeleteRegistryValue   [NTDLL.@]
1324  *
1325  * Query multiple registry values with a signle call.
1326  *
1327  * PARAMS
1328  *  RelativeTo [I] Registry path that Path refers to
1329  *  Path       [I] Path to key
1330  *  ValueName  [I] Name of the value to delete
1331  *
1332  * RETURNS
1333  *  STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1334  */
1335 NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
1336 {
1337     NTSTATUS status;
1338     HANDLE handle;
1339     UNICODE_STRING Value;
1340
1341     TRACE("(%d, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
1342
1343     RtlInitUnicodeString(&Value, ValueName);
1344     if(RelativeTo == RTL_REGISTRY_HANDLE)
1345     {
1346         return NtDeleteValueKey((HANDLE)Path, &Value);
1347     }
1348     status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1349     if (status) return status;
1350     status = NtDeleteValueKey(handle, &Value);
1351     NtClose(handle);
1352     return status;
1353 }
1354
1355 /*************************************************************************
1356  * RtlWriteRegistryValue   [NTDLL.@]
1357  *
1358  * Sets the registry value with provided data.
1359  *
1360  * PARAMS
1361  *  RelativeTo [I] Registry path that path parameter refers to
1362  *  path       [I] Path to the key (or handle - see RTL_GetKeyHandle)
1363  *  name       [I] Name of the registry value to set
1364  *  type       [I] Type of the registry key to set
1365  *  data       [I] Pointer to the user data to be set
1366  *  length     [I] Length of the user data pointed by data
1367  *
1368  * RETURNS
1369  *  STATUS_SUCCESS if the specified key is successfully set,
1370  *  or an NTSTATUS error code.
1371  */
1372 NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
1373                                        ULONG type, PVOID data, ULONG length )
1374 {
1375     HANDLE hkey;
1376     NTSTATUS status;
1377     UNICODE_STRING str;
1378
1379     TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
1380            type, data, length );
1381
1382     RtlInitUnicodeString( &str, name );
1383
1384     if (RelativeTo == RTL_REGISTRY_HANDLE)
1385         return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
1386
1387     status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
1388     if (status != STATUS_SUCCESS) return status;
1389
1390     status = NtSetValueKey( hkey, &str, 0, type, data, length );
1391     NtClose( hkey );
1392
1393     return status;
1394 }