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