Remove unneeded headers to reduce unneeded rebuilds.
[wine] / dlls / ntdll / reg.c
1 /*
2  * Registry functions
3  *
4  * Copyright (C) 1999 Juergen Schmied
5  * Copyright (C) 2000 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * NOTES:
22  *      HKEY_LOCAL_MACHINE      \\REGISTRY\\MACHINE
23  *      HKEY_USERS              \\REGISTRY\\USER
24  *      HKEY_CURRENT_CONFIG     \\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT
25   *     HKEY_CLASSES            \\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include "winerror.h"
36 #include "wine/library.h"
37 #include "winreg.h"
38 #include "ntdll_misc.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(reg);
42
43 /* maximum length of a key/value name in bytes (without terminating null) */
44 #define MAX_NAME_LENGTH ((MAX_PATH-1) * sizeof(WCHAR))
45
46
47 /******************************************************************************
48  * NtCreateKey [NTDLL.@]
49  * ZwCreateKey [NTDLL.@]
50  */
51 NTSTATUS WINAPI NtCreateKey( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
52                              ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
53                              PULONG dispos )
54 {
55     NTSTATUS ret;
56
57     TRACE( "(%p,%s,%s,%lx,%lx,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
58            debugstr_us(class), options, access, retkey );
59
60     if (attr->ObjectName->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
61     if (!retkey) return STATUS_INVALID_PARAMETER;
62
63     SERVER_START_REQ( create_key )
64     {
65         req->parent  = attr->RootDirectory;
66         req->access  = access;
67         req->options = options;
68         req->modif   = 0;
69         req->namelen = attr->ObjectName->Length;
70         wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
71         if (class) wine_server_add_data( req, class->Buffer, class->Length );
72         if (!(ret = wine_server_call( req )))
73         {
74             *retkey = reply->hkey;
75             if (dispos) *dispos = reply->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
76         }
77     }
78     SERVER_END_REQ;
79     TRACE("<- %p\n", *retkey);
80     return ret;
81 }
82
83 /******************************************************************************
84  *  RtlpNtCreateKey [NTDLL.@]
85  *
86  *  See NtCreateKey.
87  */
88 NTSTATUS WINAPI RtlpNtCreateKey( PHKEY retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
89                                  ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
90                                  PULONG dispos )
91 {
92     if (attr)
93         attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
94
95     return NtCreateKey(retkey, access, attr, 0, NULL, 0, dispos);
96 }
97
98 /******************************************************************************
99  * NtOpenKey [NTDLL.@]
100  * ZwOpenKey [NTDLL.@]
101  *
102  *   OUT        PHKEY                   retkey (returns 0 when failure)
103  *   IN         ACCESS_MASK             access
104  *   IN         POBJECT_ATTRIBUTES      attr
105  */
106 NTSTATUS WINAPI NtOpenKey( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
107 {
108     NTSTATUS ret;
109     DWORD len = attr->ObjectName->Length;
110
111     TRACE( "(%p,%s,%lx,%p)\n", attr->RootDirectory,
112            debugstr_us(attr->ObjectName), access, retkey );
113
114     if (len > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
115     if (!retkey) return STATUS_INVALID_PARAMETER;
116
117     SERVER_START_REQ( open_key )
118     {
119         req->parent = attr->RootDirectory;
120         req->access = access;
121         wine_server_add_data( req, attr->ObjectName->Buffer, len );
122         ret = wine_server_call( req );
123         *retkey = reply->hkey;
124     }
125     SERVER_END_REQ;
126     TRACE("<- %p\n", *retkey);
127     return ret;
128 }
129
130 /******************************************************************************
131  * RtlpNtOpenKey [NTDLL.@]
132  *
133  * See NtOpenKey.
134  */
135 NTSTATUS WINAPI RtlpNtOpenKey( PHKEY retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
136 {
137     if (attr)
138         attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
139     return NtOpenKey(retkey, access, attr);
140 }
141
142 /******************************************************************************
143  * NtDeleteKey [NTDLL.@]
144  * ZwDeleteKey [NTDLL.@]
145  */
146 NTSTATUS WINAPI NtDeleteKey( HKEY hkey )
147 {
148     NTSTATUS ret;
149
150     TRACE( "(%p)\n", hkey );
151
152     SERVER_START_REQ( delete_key )
153     {
154         req->hkey = hkey;
155         ret = wine_server_call( req );
156     }
157     SERVER_END_REQ;
158     return ret;
159 }
160
161 /******************************************************************************
162  * RtlpNtMakeTemporaryKey [NTDLL.@]
163  *
164  *  See NtDeleteKey.
165  */
166 NTSTATUS WINAPI RtlpNtMakeTemporaryKey( HKEY hkey )
167 {
168     return NtDeleteKey(hkey);
169 }
170
171 /******************************************************************************
172  * NtDeleteValueKey [NTDLL.@]
173  * ZwDeleteValueKey [NTDLL.@]
174  */
175 NTSTATUS WINAPI NtDeleteValueKey( HKEY hkey, const UNICODE_STRING *name )
176 {
177     NTSTATUS ret;
178
179     TRACE( "(%p,%s)\n", hkey, debugstr_us(name) );
180     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
181
182     SERVER_START_REQ( delete_key_value )
183     {
184         req->hkey = hkey;
185         wine_server_add_data( req, name->Buffer, name->Length );
186         ret = wine_server_call( req );
187     }
188     SERVER_END_REQ;
189     return ret;
190 }
191
192
193 /******************************************************************************
194  *     enumerate_key
195  *
196  * Implementation of NtQueryKey and NtEnumerateKey
197  */
198 static NTSTATUS enumerate_key( HKEY handle, int index, KEY_INFORMATION_CLASS info_class,
199                                void *info, DWORD length, DWORD *result_len )
200
201 {
202     NTSTATUS ret;
203     void *data_ptr;
204     size_t fixed_size;
205
206     switch(info_class)
207     {
208     case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break;
209     case KeyFullInformation:  data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
210     case KeyNodeInformation:  data_ptr = ((KEY_NODE_INFORMATION *)info)->Name;  break;
211     default:
212         FIXME( "Information class %d not implemented\n", info_class );
213         return STATUS_INVALID_PARAMETER;
214     }
215     fixed_size = (char *)data_ptr - (char *)info;
216
217     SERVER_START_REQ( enum_key )
218     {
219         req->hkey       = handle;
220         req->index      = index;
221         req->info_class = info_class;
222         if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
223         if (!(ret = wine_server_call( req )))
224         {
225             LARGE_INTEGER modif;
226
227             RtlSecondsSince1970ToTime( reply->modif, &modif );
228
229             switch(info_class)
230             {
231             case KeyBasicInformation:
232                 {
233                     KEY_BASIC_INFORMATION keyinfo;
234                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
235                     keyinfo.LastWriteTime = modif;
236                     keyinfo.TitleIndex = 0;
237                     keyinfo.NameLength = reply->namelen;
238                     memcpy( info, &keyinfo, min( length, fixed_size ) );
239                 }
240                 break;
241             case KeyFullInformation:
242                 {
243                     KEY_FULL_INFORMATION keyinfo;
244                     fixed_size = (char *)keyinfo.Class - (char *)&keyinfo;
245                     keyinfo.LastWriteTime = modif;
246                     keyinfo.TitleIndex = 0;
247                     keyinfo.ClassLength = wine_server_reply_size(reply);
248                     keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
249                     keyinfo.SubKeys = reply->subkeys;
250                     keyinfo.MaxNameLen = reply->max_subkey;
251                     keyinfo.MaxClassLen = reply->max_class;
252                     keyinfo.Values = reply->values;
253                     keyinfo.MaxValueNameLen = reply->max_value;
254                     keyinfo.MaxValueDataLen = reply->max_data;
255                     memcpy( info, &keyinfo, min( length, fixed_size ) );
256                 }
257                 break;
258             case KeyNodeInformation:
259                 {
260                     KEY_NODE_INFORMATION keyinfo;
261                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
262                     keyinfo.LastWriteTime = modif;
263                     keyinfo.TitleIndex = 0;
264                     keyinfo.ClassLength = max( 0, wine_server_reply_size(reply) - reply->namelen );
265                     keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size + reply->namelen : -1;
266                     keyinfo.NameLength = reply->namelen;
267                     memcpy( info, &keyinfo, min( length, fixed_size ) );
268                 }
269                 break;
270             }
271             *result_len = fixed_size + reply->total;
272             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
273         }
274     }
275     SERVER_END_REQ;
276     return ret;
277 }
278
279
280
281 /******************************************************************************
282  * NtEnumerateKey [NTDLL.@]
283  * ZwEnumerateKey [NTDLL.@]
284  *
285  * NOTES
286  *  the name copied into the buffer is NOT 0-terminated
287  */
288 NTSTATUS WINAPI NtEnumerateKey( HKEY handle, ULONG index, KEY_INFORMATION_CLASS info_class,
289                                 void *info, DWORD length, DWORD *result_len )
290 {
291     /* -1 means query key, so avoid it here */
292     if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
293     return enumerate_key( handle, index, info_class, info, length, result_len );
294 }
295
296
297 /******************************************************************************
298  * RtlpNtEnumerateSubKey [NTDLL.@]
299  *
300  */
301 NTSTATUS WINAPI RtlpNtEnumerateSubKey( HKEY handle, UNICODE_STRING *out, ULONG index )
302 {
303   KEY_BASIC_INFORMATION *info;
304   DWORD dwLen, dwResultLen;
305   NTSTATUS ret;
306
307   if (out->Length)
308   {
309     dwLen = out->Length + sizeof(KEY_BASIC_INFORMATION);
310     info = (KEY_BASIC_INFORMATION*)RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
311     if (!info)
312       return STATUS_NO_MEMORY;
313   }
314   else
315   {
316     dwLen = 0;
317     info = NULL;
318   }
319
320   ret = NtEnumerateKey( handle, index, KeyBasicInformation, info, dwLen, &dwResultLen );
321   dwResultLen -= sizeof(KEY_BASIC_INFORMATION);
322
323   if (ret == STATUS_BUFFER_OVERFLOW)
324     out->Length = dwResultLen;
325   else if (!ret)
326   {
327     if (out->Length < info->NameLength)
328     {
329       out->Length = dwResultLen;
330       ret = STATUS_BUFFER_OVERFLOW;
331     }
332     else
333     {
334       out->Length = info->NameLength;
335       memcpy(out->Buffer, info->Name, info->NameLength);
336     }
337   }
338
339   if (info)
340     RtlFreeHeap( GetProcessHeap(), 0, info );
341   return ret;
342 }
343
344 /******************************************************************************
345  * NtQueryKey [NTDLL.@]
346  * ZwQueryKey [NTDLL.@]
347  */
348 NTSTATUS WINAPI NtQueryKey( HKEY handle, KEY_INFORMATION_CLASS info_class,
349                             void *info, DWORD length, DWORD *result_len )
350 {
351     return enumerate_key( handle, -1, info_class, info, length, result_len );
352 }
353
354
355 /* fill the key value info structure for a specific info class */
356 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info,
357                                  DWORD length, int type, int name_len, int data_len )
358 {
359     switch(info_class)
360     {
361     case KeyValueBasicInformation:
362         {
363             KEY_VALUE_BASIC_INFORMATION keyinfo;
364             keyinfo.TitleIndex = 0;
365             keyinfo.Type       = type;
366             keyinfo.NameLength = name_len;
367             length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
368             memcpy( info, &keyinfo, length );
369             break;
370         }
371     case KeyValueFullInformation:
372         {
373             KEY_VALUE_FULL_INFORMATION keyinfo;
374             keyinfo.TitleIndex = 0;
375             keyinfo.Type       = type;
376             keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len;
377             keyinfo.DataLength = data_len;
378             keyinfo.NameLength = name_len;
379             length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
380             memcpy( info, &keyinfo, length );
381             break;
382         }
383     case KeyValuePartialInformation:
384         {
385             KEY_VALUE_PARTIAL_INFORMATION keyinfo;
386             keyinfo.TitleIndex = 0;
387             keyinfo.Type       = type;
388             keyinfo.DataLength = data_len;
389             length = min( length, (char *)keyinfo.Data - (char *)&keyinfo );
390             memcpy( info, &keyinfo, length );
391             break;
392         }
393     default:
394         break;
395     }
396 }
397
398
399 /******************************************************************************
400  *  NtEnumerateValueKey [NTDLL.@]
401  *  ZwEnumerateValueKey [NTDLL.@]
402  */
403 NTSTATUS WINAPI NtEnumerateValueKey( HKEY handle, ULONG index,
404                                      KEY_VALUE_INFORMATION_CLASS info_class,
405                                      void *info, DWORD length, DWORD *result_len )
406 {
407     NTSTATUS ret;
408     void *ptr;
409     size_t fixed_size;
410
411     TRACE( "(%p,%lu,%d,%p,%ld)\n", handle, index, info_class, info, length );
412
413     /* compute the length we want to retrieve */
414     switch(info_class)
415     {
416     case KeyValueBasicInformation:   ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break;
417     case KeyValueFullInformation:    ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break;
418     case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break;
419     default:
420         FIXME( "Information class %d not implemented\n", info_class );
421         return STATUS_INVALID_PARAMETER;
422     }
423     fixed_size = (char *)ptr - (char *)info;
424
425     SERVER_START_REQ( enum_key_value )
426     {
427         req->hkey       = handle;
428         req->index      = index;
429         req->info_class = info_class;
430         if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size );
431         if (!(ret = wine_server_call( req )))
432         {
433             copy_key_value_info( info_class, info, length, reply->type, reply->namelen,
434                                  wine_server_reply_size(reply) - reply->namelen );
435             *result_len = fixed_size + reply->total;
436             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
437         }
438     }
439     SERVER_END_REQ;
440     return ret;
441 }
442
443
444 /******************************************************************************
445  * NtQueryValueKey [NTDLL.@]
446  * ZwQueryValueKey [NTDLL.@]
447  *
448  * NOTES
449  *  the name in the KeyValueInformation is never set
450  */
451 NTSTATUS WINAPI NtQueryValueKey( HKEY handle, const UNICODE_STRING *name,
452                                  KEY_VALUE_INFORMATION_CLASS info_class,
453                                  void *info, DWORD length, DWORD *result_len )
454 {
455     NTSTATUS ret;
456     UCHAR *data_ptr;
457     unsigned int fixed_size = 0;
458
459     TRACE( "(%p,%s,%d,%p,%ld)\n", handle, debugstr_us(name), info_class, info, length );
460
461     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
462
463     /* compute the length we want to retrieve */
464     switch(info_class)
465     {
466     case KeyValueBasicInformation:
467         fixed_size = (char *)((KEY_VALUE_BASIC_INFORMATION *)info)->Name - (char *)info;
468         data_ptr = NULL;
469         break;
470     case KeyValueFullInformation:
471         data_ptr = (UCHAR *)((KEY_VALUE_FULL_INFORMATION *)info)->Name;
472         fixed_size = (char *)data_ptr - (char *)info;
473         break;
474     case KeyValuePartialInformation:
475         data_ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data;
476         fixed_size = (char *)data_ptr - (char *)info;
477         break;
478     default:
479         FIXME( "Information class %d not implemented\n", info_class );
480         return STATUS_INVALID_PARAMETER;
481     }
482
483     SERVER_START_REQ( get_key_value )
484     {
485         req->hkey = handle;
486         wine_server_add_data( req, name->Buffer, name->Length );
487         if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
488         if (!(ret = wine_server_call( req )))
489         {
490             copy_key_value_info( info_class, info, length, reply->type,
491                                  0, wine_server_reply_size(reply) );
492             *result_len = fixed_size + reply->total;
493             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
494         }
495     }
496     SERVER_END_REQ;
497     return ret;
498 }
499
500 /******************************************************************************
501  * RtlpNtQueryValueKey [NTDLL.@]
502  *
503  */
504 NTSTATUS WINAPI RtlpNtQueryValueKey( HKEY handle, ULONG *result_type, PBYTE dest,
505                                      DWORD *result_len )
506 {
507     KEY_VALUE_PARTIAL_INFORMATION *info;
508     UNICODE_STRING name;
509     NTSTATUS ret;
510     DWORD dwResultLen;
511     DWORD dwLen = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + result_len ? *result_len : 0;
512
513     info = (KEY_VALUE_PARTIAL_INFORMATION*)RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
514     if (!info)
515       return STATUS_NO_MEMORY;
516
517     name.Length = 0;
518     ret = NtQueryValueKey( handle, &name, KeyValuePartialInformation, info, dwLen, &dwResultLen );
519
520     if (!ret || ret == STATUS_BUFFER_OVERFLOW)
521     {
522         if (result_len)
523             *result_len = info->DataLength;
524
525         if (result_type)
526             *result_type = info->Type;
527
528         if (ret != STATUS_BUFFER_OVERFLOW)
529             memcpy( dest, info->Data, info->DataLength );
530     }
531
532     RtlFreeHeap( GetProcessHeap(), 0, info );
533     return ret;
534 }
535
536 /******************************************************************************
537  *  NtFlushKey  [NTDLL.@]
538  *  ZwFlushKey  [NTDLL.@]
539  */
540 NTSTATUS WINAPI NtFlushKey(HKEY key)
541 {
542     NTSTATUS ret;
543
544     TRACE("key=%p\n", key);
545
546     SERVER_START_REQ( flush_key )
547     {
548         req->hkey = key;
549         ret = wine_server_call( req );
550     }
551     SERVER_END_REQ;
552     
553     return ret;
554 }
555
556 /******************************************************************************
557  *  NtLoadKey   [NTDLL.@]
558  *  ZwLoadKey   [NTDLL.@]
559  */
560 NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, const OBJECT_ATTRIBUTES *file )
561 {
562     FIXME("stub!\n");
563     dump_ObjectAttributes(attr);
564     dump_ObjectAttributes(file);
565     return STATUS_SUCCESS;
566 }
567
568 /******************************************************************************
569  *  NtNotifyChangeKey   [NTDLL.@]
570  *  ZwNotifyChangeKey   [NTDLL.@]
571  */
572 NTSTATUS WINAPI NtNotifyChangeKey(
573         IN HKEY KeyHandle,
574         IN HANDLE Event,
575         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
576         IN PVOID ApcContext OPTIONAL,
577         OUT PIO_STATUS_BLOCK IoStatusBlock,
578         IN ULONG CompletionFilter,
579         IN BOOLEAN Asynchroneous,
580         OUT PVOID ChangeBuffer,
581         IN ULONG Length,
582         IN BOOLEAN WatchSubtree)
583 {
584         FIXME("(%p,%p,%p,%p,%p,0x%08lx, 0x%08x,%p,0x%08lx,0x%08x) stub!\n",
585         KeyHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
586         Asynchroneous, ChangeBuffer, Length, WatchSubtree);
587         return STATUS_SUCCESS;
588 }
589
590 /******************************************************************************
591  * NtQueryMultipleValueKey [NTDLL]
592  * ZwQueryMultipleValueKey
593  */
594
595 NTSTATUS WINAPI NtQueryMultipleValueKey(
596         HKEY KeyHandle,
597         PVALENTW ListOfValuesToQuery,
598         ULONG NumberOfItems,
599         PVOID MultipleValueInformation,
600         ULONG Length,
601         PULONG  ReturnLength)
602 {
603         FIXME("(%p,%p,0x%08lx,%p,0x%08lx,%p) stub!\n",
604         KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
605         Length,ReturnLength);
606         return STATUS_SUCCESS;
607 }
608
609 /******************************************************************************
610  * NtReplaceKey [NTDLL.@]
611  * ZwReplaceKey [NTDLL.@]
612  */
613 NTSTATUS WINAPI NtReplaceKey(
614         IN POBJECT_ATTRIBUTES ObjectAttributes,
615         IN HKEY Key,
616         IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
617 {
618         FIXME("(%p),stub!\n", Key);
619         dump_ObjectAttributes(ObjectAttributes);
620         dump_ObjectAttributes(ReplacedObjectAttributes);
621         return STATUS_SUCCESS;
622 }
623 /******************************************************************************
624  * NtRestoreKey [NTDLL.@]
625  * ZwRestoreKey [NTDLL.@]
626  */
627 NTSTATUS WINAPI NtRestoreKey(
628         HKEY KeyHandle,
629         HANDLE FileHandle,
630         ULONG RestoreFlags)
631 {
632         FIXME("(%p,%p,0x%08lx) stub\n",
633         KeyHandle, FileHandle, RestoreFlags);
634         return STATUS_SUCCESS;
635 }
636 /******************************************************************************
637  * NtSaveKey [NTDLL.@]
638  * ZwSaveKey [NTDLL.@]
639  */
640 NTSTATUS WINAPI NtSaveKey(
641         IN HKEY KeyHandle,
642         IN HANDLE FileHandle)
643 {
644         FIXME("(%p,%p) stub\n",
645         KeyHandle, FileHandle);
646         return STATUS_SUCCESS;
647 }
648 /******************************************************************************
649  * NtSetInformationKey [NTDLL.@]
650  * ZwSetInformationKey [NTDLL.@]
651  */
652 NTSTATUS WINAPI NtSetInformationKey(
653         IN HKEY KeyHandle,
654         IN const int KeyInformationClass,
655         IN PVOID KeyInformation,
656         IN ULONG KeyInformationLength)
657 {
658         FIXME("(%p,0x%08x,%p,0x%08lx) stub\n",
659         KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
660         return STATUS_SUCCESS;
661 }
662
663
664 /******************************************************************************
665  * NtSetValueKey [NTDLL.@]
666  * ZwSetValueKey [NTDLL.@]
667  *
668  * NOTES
669  *   win95 does not care about count for REG_SZ and finds out the len by itself (js)
670  *   NT does definitely care (aj)
671  */
672 NTSTATUS WINAPI NtSetValueKey( HKEY hkey, const UNICODE_STRING *name, ULONG TitleIndex,
673                                ULONG type, const void *data, ULONG count )
674 {
675     NTSTATUS ret;
676
677     TRACE( "(%p,%s,%ld,%p,%ld)\n", hkey, debugstr_us(name), type, data, count );
678
679     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
680
681     SERVER_START_REQ( set_key_value )
682     {
683         req->hkey    = hkey;
684         req->type    = type;
685         req->namelen = name->Length;
686         wine_server_add_data( req, name->Buffer, name->Length );
687         wine_server_add_data( req, data, count );
688         ret = wine_server_call( req );
689     }
690     SERVER_END_REQ;
691     return ret;
692 }
693
694 /******************************************************************************
695  * RtlpNtSetValueKey [NTDLL.@]
696  *
697  */
698 NTSTATUS WINAPI RtlpNtSetValueKey( HKEY hkey, ULONG type, const void *data,
699                                    ULONG count )
700 {
701     UNICODE_STRING name;
702
703     name.Length = 0;
704     return NtSetValueKey( hkey, &name, 0, type, data, count );
705 }
706
707 /******************************************************************************
708  * NtUnloadKey [NTDLL.@]
709  * ZwUnloadKey [NTDLL.@]
710  */
711 NTSTATUS WINAPI NtUnloadKey(
712         IN HKEY KeyHandle)
713 {
714         FIXME("(%p) stub\n",
715         KeyHandle);
716         return STATUS_SUCCESS;
717 }
718
719 /******************************************************************************
720  *  RtlFormatCurrentUserKeyPath         [NTDLL.@]
721  *
722  * NOTE: under NT the user name part of the path is an SID.
723  */
724 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
725 {
726     static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
727     const char *user = wine_get_user_name();
728     int len = ntdll_umbstowcs( 0, user, strlen(user)+1, NULL, 0 );
729
730     KeyPath->MaximumLength = sizeof(pathW) + len * sizeof(WCHAR);
731     KeyPath->Length = KeyPath->MaximumLength - sizeof(WCHAR);
732     if (!(KeyPath->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, KeyPath->MaximumLength )))
733         return STATUS_NO_MEMORY;
734     memcpy( KeyPath->Buffer, pathW, sizeof(pathW) );
735     ntdll_umbstowcs( 0, user, strlen(user)+1, KeyPath->Buffer + sizeof(pathW)/sizeof(WCHAR), len );
736     return STATUS_SUCCESS;
737 }
738
739 /******************************************************************************
740  *  RtlOpenCurrentUser          [NTDLL.@]
741  *
742  * if we return just HKEY_CURRENT_USER the advapi tries to find a remote
743  * registry (odd handle) and fails
744  *
745  */
746 DWORD WINAPI RtlOpenCurrentUser(
747         IN ACCESS_MASK DesiredAccess, /* [in] */
748         OUT PHKEY KeyHandle)          /* [out] handle of HKEY_CURRENT_USER */
749 {
750         OBJECT_ATTRIBUTES ObjectAttributes;
751         UNICODE_STRING ObjectName;
752         NTSTATUS ret;
753
754         TRACE("(0x%08lx, %p) stub\n",DesiredAccess, KeyHandle);
755
756         RtlFormatCurrentUserKeyPath(&ObjectName);
757         InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
758         ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
759         RtlFreeUnicodeString(&ObjectName);
760         return ret;
761 }