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