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