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