OpenPrinter should fail if pPrinterName is "".
[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     FILETIME modif;
165
166     RtlSecondsSince1970ToTime( req->modif, &modif );
167
168     switch(info_class)
169     {
170     case KeyBasicInformation:
171         {
172             KEY_BASIC_INFORMATION keyinfo;
173             fixed_size = sizeof(keyinfo) - sizeof(keyinfo.Name);
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 = sizeof(keyinfo) - sizeof(keyinfo.Class);
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 = sizeof(keyinfo) - sizeof(keyinfo.Name);
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, sizeof(keyinfo) - sizeof(keyinfo.Name) );
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 = sizeof(keyinfo) - sizeof(keyinfo.Name) + name_len;
316             keyinfo.DataLength = data_len;
317             keyinfo.NameLength = name_len;
318             length = min( length, sizeof(keyinfo) - sizeof(keyinfo.Name) );
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, sizeof(keyinfo) - sizeof(keyinfo.Data) );
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     char *data_ptr, *name_ptr;
348     int fixed_size = 0, name_len = 0, data_len = 0, offset = 0, type = 0, total_len = 0;
349
350     TRACE( "(0x%x,%lu,%d,%p,%ld)\n", handle, index, info_class, info, length );
351
352     /* compute the length we want to retrieve */
353     switch(info_class)
354     {
355     case KeyValueBasicInformation:
356         fixed_size = sizeof(KEY_VALUE_BASIC_INFORMATION) - sizeof(WCHAR);
357         name_ptr = (char *)info + fixed_size;
358         data_ptr = NULL;
359         break;
360     case KeyValueFullInformation:
361         fixed_size = sizeof(KEY_VALUE_FULL_INFORMATION) - sizeof(WCHAR);
362         name_ptr = data_ptr = (char *)info + fixed_size;
363         break;
364     case KeyValuePartialInformation:
365         fixed_size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) - sizeof(UCHAR);
366         name_ptr = NULL;
367         data_ptr = (char *)info + fixed_size;
368         break;
369     default:
370         FIXME( "Information class %d not implemented\n", info_class );
371         return STATUS_INVALID_PARAMETER;
372     }
373     if (length > fixed_size) data_len = length - fixed_size;
374
375     do
376     {
377         size_t reqlen = data_len + sizeof(WCHAR);
378         if (name_ptr && !offset) reqlen += MAX_PATH*sizeof(WCHAR);
379         reqlen = min( reqlen, REQUEST_MAX_VAR_SIZE );
380
381         SERVER_START_VAR_REQ( enum_key_value, reqlen )
382         {
383             req->hkey = handle;
384             req->index = index;
385             req->offset = offset;
386
387             if (!(ret = SERVER_CALL()))
388             {
389                 size_t size = server_data_size(req) - sizeof(WCHAR);
390                 WCHAR *name = server_data_ptr(req);
391                 if (!offset)  /* name is only present on the first request */
392                 {
393                     name_len = *name++;
394                     size -= name_len;
395                     if (name_ptr)
396                     {
397                         if (name_len > data_len)  /* overflow */
398                         {
399                             memcpy( name_ptr, name, data_len );
400                             data_len = 0;
401                             ret = STATUS_BUFFER_OVERFLOW;
402                         }
403                         else
404                         {
405                             memcpy( name_ptr, name, name_len );
406                             data_len -= name_len;
407                             if (data_ptr) data_ptr += name_len;
408                         }
409                     }
410                     name += name_len / sizeof(WCHAR);
411                 }
412                 else name++;  /* skip 0 length */
413
414                 if (data_ptr)
415                 {
416                     size = min( size, data_len );
417                     memcpy( data_ptr + offset, name, size );
418                     offset += size;
419                     data_len -= size;
420                 }
421                 type = req->type;
422                 total_len = req->len;
423             }
424         }
425         SERVER_END_VAR_REQ;
426         if (ret) return ret;
427     } while (data_len && data_ptr && offset < total_len);
428
429     *result_len = total_len + fixed_size + (name_ptr ? name_len : 0);
430
431     if (data_ptr && offset < total_len) ret = STATUS_BUFFER_OVERFLOW;
432     if (length < fixed_size) ret = STATUS_BUFFER_OVERFLOW;
433
434     copy_key_value_info( info_class, info, length, type, name_len, total_len );
435     return ret;
436
437 }
438
439
440 /******************************************************************************
441  * NtQueryValueKey [NTDLL.@]
442  * ZwQueryValueKey [NTDLL.@]
443  *
444  * NOTES
445  *  the name in the KeyValueInformation is never set
446  */
447 NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name,
448                                  KEY_VALUE_INFORMATION_CLASS info_class,
449                                  void *info, DWORD length, DWORD *result_len )
450 {
451     NTSTATUS ret;
452     char *data_ptr;
453     int fixed_size = 0, data_len = 0, offset = 0, type = 0, total_len = 0;
454
455     TRACE( "(0x%x,%s,%d,%p,%ld)\n", handle, debugstr_us(name), info_class, info, length );
456
457     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
458
459     /* compute the length we want to retrieve */
460     switch(info_class)
461     {
462     case KeyValueBasicInformation:
463         fixed_size = sizeof(KEY_VALUE_BASIC_INFORMATION) - sizeof(WCHAR);
464         data_ptr = NULL;
465         break;
466     case KeyValueFullInformation:
467         fixed_size = sizeof(KEY_VALUE_FULL_INFORMATION) - sizeof(WCHAR);
468         data_ptr = (char *)info + fixed_size;
469         break;
470     case KeyValuePartialInformation:
471         fixed_size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) - sizeof(UCHAR);
472         data_ptr = (char *)info + fixed_size;
473         break;
474     default:
475         FIXME( "Information class %d not implemented\n", info_class );
476         return STATUS_INVALID_PARAMETER;
477     }
478     if (data_ptr && length > fixed_size) data_len = length - fixed_size;
479
480     do
481     {
482         size_t reqlen = min( data_len, REQUEST_MAX_VAR_SIZE );
483         reqlen = max( reqlen, name->Length + sizeof(WCHAR) );
484
485         SERVER_START_VAR_REQ( get_key_value, reqlen )
486         {
487             WCHAR *nameptr = server_data_ptr(req);
488
489             req->hkey = handle;
490             req->offset = offset;
491             *nameptr++ = name->Length;
492             memcpy( nameptr, name->Buffer, name->Length );
493
494             if (!(ret = SERVER_CALL()))
495             {
496                 size_t size = min( server_data_size(req), data_len );
497                 type = req->type;
498                 total_len = req->len;
499                 if (size)
500                 {
501                     memcpy( data_ptr + offset, server_data_ptr(req), size );
502                     offset += size;
503                     data_len -= size;
504                 }
505             }
506         }
507         SERVER_END_VAR_REQ;
508         if (ret) return ret;
509     } while (data_len && offset < total_len);
510
511     *result_len = total_len + fixed_size;
512
513     if (offset < total_len) ret = STATUS_BUFFER_OVERFLOW;
514     if (length < fixed_size) ret = STATUS_BUFFER_OVERFLOW;
515
516     copy_key_value_info( info_class, info, length, type, 0, total_len );
517     return ret;
518 }
519
520
521 /******************************************************************************
522  *  NtFlushKey  [NTDLL.@]
523  *  ZwFlushKey  [NTDLL.@]
524  */
525 NTSTATUS WINAPI NtFlushKey(HANDLE KeyHandle)
526 {
527         FIXME("(0x%08x) stub!\n",
528         KeyHandle);
529         return 1;
530 }
531
532 /******************************************************************************
533  *  NtLoadKey   [NTDLL.@]
534  *  ZwLoadKey   [NTDLL.@]
535  */
536 NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, const OBJECT_ATTRIBUTES *file )
537 {
538     FIXME("stub!\n");
539     dump_ObjectAttributes(attr);
540     dump_ObjectAttributes(file);
541     return STATUS_SUCCESS;
542 }
543
544 /******************************************************************************
545  *  NtNotifyChangeKey   [NTDLL.@]
546  *  ZwNotifyChangeKey   [NTDLL.@]
547  */
548 NTSTATUS WINAPI NtNotifyChangeKey(
549         IN HANDLE KeyHandle,
550         IN HANDLE Event,
551         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
552         IN PVOID ApcContext OPTIONAL,
553         OUT PIO_STATUS_BLOCK IoStatusBlock,
554         IN ULONG CompletionFilter,
555         IN BOOLEAN Asynchroneous,
556         OUT PVOID ChangeBuffer,
557         IN ULONG Length,
558         IN BOOLEAN WatchSubtree)
559 {
560         FIXME("(0x%08x,0x%08x,%p,%p,%p,0x%08lx, 0x%08x,%p,0x%08lx,0x%08x) stub!\n",
561         KeyHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
562         Asynchroneous, ChangeBuffer, Length, WatchSubtree);
563         return STATUS_SUCCESS;
564 }
565
566 /******************************************************************************
567  * NtQueryMultipleValueKey [NTDLL]
568  * ZwQueryMultipleValueKey
569  */
570
571 NTSTATUS WINAPI NtQueryMultipleValueKey(
572         HANDLE KeyHandle,
573         PVALENTW ListOfValuesToQuery,
574         ULONG NumberOfItems,
575         PVOID MultipleValueInformation,
576         ULONG Length,
577         PULONG  ReturnLength)
578 {
579         FIXME("(0x%08x,%p,0x%08lx,%p,0x%08lx,%p) stub!\n",
580         KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
581         Length,ReturnLength);
582         return STATUS_SUCCESS;
583 }
584
585 /******************************************************************************
586  * NtReplaceKey [NTDLL.@]
587  * ZwReplaceKey [NTDLL.@]
588  */
589 NTSTATUS WINAPI NtReplaceKey(
590         IN POBJECT_ATTRIBUTES ObjectAttributes,
591         IN HANDLE Key,
592         IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
593 {
594         FIXME("(0x%08x),stub!\n", Key);
595         dump_ObjectAttributes(ObjectAttributes);
596         dump_ObjectAttributes(ReplacedObjectAttributes);
597         return STATUS_SUCCESS;
598 }
599 /******************************************************************************
600  * NtRestoreKey [NTDLL.@]
601  * ZwRestoreKey [NTDLL.@]
602  */
603 NTSTATUS WINAPI NtRestoreKey(
604         HANDLE KeyHandle,
605         HANDLE FileHandle,
606         ULONG RestoreFlags)
607 {
608         FIXME("(0x%08x,0x%08x,0x%08lx) stub\n",
609         KeyHandle, FileHandle, RestoreFlags);
610         return STATUS_SUCCESS;
611 }
612 /******************************************************************************
613  * NtSaveKey [NTDLL.@]
614  * ZwSaveKey [NTDLL.@]
615  */
616 NTSTATUS WINAPI NtSaveKey(
617         IN HANDLE KeyHandle,
618         IN HANDLE FileHandle)
619 {
620         FIXME("(0x%08x,0x%08x) stub\n",
621         KeyHandle, FileHandle);
622         return STATUS_SUCCESS;
623 }
624 /******************************************************************************
625  * NtSetInformationKey [NTDLL.@]
626  * ZwSetInformationKey [NTDLL.@]
627  */
628 NTSTATUS WINAPI NtSetInformationKey(
629         IN HANDLE KeyHandle,
630         IN const int KeyInformationClass,
631         IN PVOID KeyInformation,
632         IN ULONG KeyInformationLength)
633 {
634         FIXME("(0x%08x,0x%08x,%p,0x%08lx) stub\n",
635         KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
636         return STATUS_SUCCESS;
637 }
638
639
640 /******************************************************************************
641  * NtSetValueKey [NTDLL.@]
642  * ZwSetValueKey [NTDLL.@]
643  *
644  * NOTES
645  *   win95 does not care about count for REG_SZ and finds out the len by itself (js) 
646  *   NT does definitely care (aj)
647  */
648 NTSTATUS WINAPI NtSetValueKey( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
649                                ULONG type, const void *data, ULONG count )
650 {
651     NTSTATUS ret;
652     ULONG namelen, pos;
653
654     TRACE( "(0x%x,%s,%ld,%p,%ld)\n", hkey, debugstr_us(name), type, data, count );
655
656     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
657
658     namelen = name->Length + sizeof(WCHAR);  /* for storing length */
659     pos = 0;
660
661     do
662     {
663         ULONG len = count - pos;
664         if (len > REQUEST_MAX_VAR_SIZE - namelen) len = REQUEST_MAX_VAR_SIZE - namelen;
665
666         SERVER_START_VAR_REQ( set_key_value, namelen + len )
667         {
668             WCHAR *name_ptr = server_data_ptr(req);
669
670             req->hkey   = hkey;
671             req->type   = type;
672             req->total  = count;
673             req->offset = pos;
674             *name_ptr++ = name->Length;
675             memcpy( name_ptr, name->Buffer, name->Length );
676             memcpy( (char *)name_ptr + name->Length, (char *)data + pos, len );
677             pos += len;
678             ret = SERVER_CALL();
679         }
680         SERVER_END_VAR_REQ;
681     } while (!ret && pos < count);
682     return ret;
683 }
684
685 /******************************************************************************
686  * NtUnloadKey [NTDLL.@]
687  * ZwUnloadKey [NTDLL.@]
688  */
689 NTSTATUS WINAPI NtUnloadKey(
690         IN HANDLE KeyHandle)
691 {
692         FIXME("(0x%08x) stub\n",
693         KeyHandle);
694         return STATUS_SUCCESS;
695 }
696
697 /******************************************************************************
698  *  RtlFormatCurrentUserKeyPath         [NTDLL.@]
699  */
700 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath(
701         IN OUT PUNICODE_STRING KeyPath)
702 {
703 /*      LPSTR Path = "\\REGISTRY\\USER\\S-1-5-21-0000000000-000000000-0000000000-500";*/
704         LPSTR Path = "\\REGISTRY\\USER\\.DEFAULT";
705         ANSI_STRING AnsiPath;
706
707         FIXME("(%p) stub\n",KeyPath);
708         RtlInitAnsiString(&AnsiPath, Path);
709         return RtlAnsiStringToUnicodeString(KeyPath, &AnsiPath, TRUE);
710 }
711
712 /******************************************************************************
713  *  RtlOpenCurrentUser          [NTDLL.@]
714  *
715  * if we return just HKEY_CURRENT_USER the advapi try's to find a remote
716  * registry (odd handle) and fails
717  *
718  */
719 DWORD WINAPI RtlOpenCurrentUser(
720         IN ACCESS_MASK DesiredAccess, /* [in] */
721         OUT PHANDLE KeyHandle)        /* [out] handle of HKEY_CURRENT_USER */
722 {
723         OBJECT_ATTRIBUTES ObjectAttributes;
724         UNICODE_STRING ObjectName;
725         NTSTATUS ret;
726
727         TRACE("(0x%08lx, %p) stub\n",DesiredAccess, KeyHandle);
728
729         RtlFormatCurrentUserKeyPath(&ObjectName);
730         InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
731         ret = NtOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
732         RtlFreeUnicodeString(&ObjectName);
733         return ret;
734 }