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