If using the default values, also set dwType to REG_SZ as our default
[wine] / dlls / ntdll / reg.c
1 /*
2  * Registry functions
3  *
4  * Copyright (C) 1999 Juergen Schmied
5  * Copyright (C) 2000 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * NOTES:
22  *      HKEY_LOCAL_MACHINE      \\REGISTRY\\MACHINE
23  *      HKEY_USERS              \\REGISTRY\\USER
24  *      HKEY_CURRENT_CONFIG     \\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT
25   *     HKEY_CLASSES            \\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include "winerror.h"
36 #include "wine/unicode.h"
37 #include "wine/library.h"
38 #include "wine/server.h"
39 #include "windef.h"
40 #include "winbase.h"
41 #include "winreg.h"
42 #include "winternl.h"
43 #include "ntdll_misc.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(reg);
47
48 /* maximum length of a key/value name in bytes (without terminating null) */
49 #define MAX_NAME_LENGTH ((MAX_PATH-1) * sizeof(WCHAR))
50
51
52 /******************************************************************************
53  * NtCreateKey [NTDLL.@]
54  * ZwCreateKey [NTDLL.@]
55  */
56 NTSTATUS WINAPI NtCreateKey( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
57                              ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
58                              PULONG dispos )
59 {
60     NTSTATUS ret;
61
62     TRACE( "(%p,%s,%s,%lx,%lx,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
63            debugstr_us(class), options, access, retkey );
64
65     if (attr->ObjectName->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
66     if (!retkey) return STATUS_INVALID_PARAMETER;
67
68     SERVER_START_REQ( create_key )
69     {
70         req->parent  = attr->RootDirectory;
71         req->access  = access;
72         req->options = options;
73         req->modif   = 0;
74         req->namelen = attr->ObjectName->Length;
75         wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
76         if (class) wine_server_add_data( req, class->Buffer, class->Length );
77         if (!(ret = wine_server_call( req )))
78         {
79             *retkey = reply->hkey;
80             if (dispos) *dispos = reply->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
81         }
82     }
83     SERVER_END_REQ;
84     TRACE("<- %p\n", *retkey);
85     return ret;
86 }
87
88
89 /******************************************************************************
90  * NtOpenKey [NTDLL.@]
91  * ZwOpenKey [NTDLL.@]
92  *
93  *   OUT        PHKEY                   retkey (returns 0 when failure)
94  *   IN         ACCESS_MASK             access
95  *   IN         POBJECT_ATTRIBUTES      attr
96  */
97 NTSTATUS WINAPI NtOpenKey( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
98 {
99     NTSTATUS ret;
100     DWORD len = attr->ObjectName->Length;
101
102     TRACE( "(%p,%s,%lx,%p)\n", attr->RootDirectory,
103            debugstr_us(attr->ObjectName), access, retkey );
104
105     if (len > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
106     if (!retkey) return STATUS_INVALID_PARAMETER;
107
108     SERVER_START_REQ( open_key )
109     {
110         req->parent = attr->RootDirectory;
111         req->access = access;
112         wine_server_add_data( req, attr->ObjectName->Buffer, len );
113         ret = wine_server_call( req );
114         *retkey = reply->hkey;
115     }
116     SERVER_END_REQ;
117     TRACE("<- %p\n", *retkey);
118     return ret;
119 }
120
121
122 /******************************************************************************
123  * NtDeleteKey [NTDLL.@]
124  * ZwDeleteKey [NTDLL.@]
125  */
126 NTSTATUS WINAPI NtDeleteKey( HKEY hkey )
127 {
128     NTSTATUS ret;
129
130     TRACE( "(%p)\n", hkey );
131
132     SERVER_START_REQ( delete_key )
133     {
134         req->hkey = hkey;
135         ret = wine_server_call( req );
136     }
137     SERVER_END_REQ;
138     return ret;
139 }
140
141
142 /******************************************************************************
143  * NtDeleteValueKey [NTDLL.@]
144  * ZwDeleteValueKey [NTDLL.@]
145  */
146 NTSTATUS WINAPI NtDeleteValueKey( HKEY hkey, const UNICODE_STRING *name )
147 {
148     NTSTATUS ret;
149
150     TRACE( "(%p,%s)\n", hkey, debugstr_us(name) );
151     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
152
153     SERVER_START_REQ( delete_key_value )
154     {
155         req->hkey = hkey;
156         wine_server_add_data( req, name->Buffer, name->Length );
157         ret = wine_server_call( req );
158     }
159     SERVER_END_REQ;
160     return ret;
161 }
162
163
164 /******************************************************************************
165  *     enumerate_key
166  *
167  * Implementation of NtQueryKey and NtEnumerateKey
168  */
169 static NTSTATUS enumerate_key( HKEY handle, int index, KEY_INFORMATION_CLASS info_class,
170                                void *info, DWORD length, DWORD *result_len )
171
172 {
173     NTSTATUS ret;
174     void *data_ptr;
175     size_t fixed_size;
176
177     switch(info_class)
178     {
179     case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break;
180     case KeyFullInformation:  data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
181     case KeyNodeInformation:  data_ptr = ((KEY_NODE_INFORMATION *)info)->Name;  break;
182     default:
183         FIXME( "Information class %d not implemented\n", info_class );
184         return STATUS_INVALID_PARAMETER;
185     }
186     fixed_size = (char *)data_ptr - (char *)info;
187
188     SERVER_START_REQ( enum_key )
189     {
190         req->hkey       = handle;
191         req->index      = index;
192         req->info_class = info_class;
193         if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
194         if (!(ret = wine_server_call( req )))
195         {
196             LARGE_INTEGER modif;
197
198             RtlSecondsSince1970ToTime( reply->modif, &modif );
199
200             switch(info_class)
201             {
202             case KeyBasicInformation:
203                 {
204                     KEY_BASIC_INFORMATION keyinfo;
205                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
206                     keyinfo.LastWriteTime = modif;
207                     keyinfo.TitleIndex = 0;
208                     keyinfo.NameLength = reply->namelen;
209                     memcpy( info, &keyinfo, min( length, fixed_size ) );
210                 }
211                 break;
212             case KeyFullInformation:
213                 {
214                     KEY_FULL_INFORMATION keyinfo;
215                     fixed_size = (char *)keyinfo.Class - (char *)&keyinfo;
216                     keyinfo.LastWriteTime = modif;
217                     keyinfo.TitleIndex = 0;
218                     keyinfo.ClassLength = wine_server_reply_size(reply);
219                     keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
220                     keyinfo.SubKeys = reply->subkeys;
221                     keyinfo.MaxNameLen = reply->max_subkey;
222                     keyinfo.MaxClassLen = reply->max_class;
223                     keyinfo.Values = reply->values;
224                     keyinfo.MaxValueNameLen = reply->max_value;
225                     keyinfo.MaxValueDataLen = reply->max_data;
226                     memcpy( info, &keyinfo, min( length, fixed_size ) );
227                 }
228                 break;
229             case KeyNodeInformation:
230                 {
231                     KEY_NODE_INFORMATION keyinfo;
232                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
233                     keyinfo.LastWriteTime = modif;
234                     keyinfo.TitleIndex = 0;
235                     keyinfo.ClassLength = max( 0, wine_server_reply_size(reply) - reply->namelen );
236                     keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size + reply->namelen : -1;
237                     keyinfo.NameLength = reply->namelen;
238                     memcpy( info, &keyinfo, min( length, fixed_size ) );
239                 }
240                 break;
241             }
242             *result_len = fixed_size + reply->total;
243             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
244         }
245     }
246     SERVER_END_REQ;
247     return ret;
248 }
249
250
251
252 /******************************************************************************
253  * NtEnumerateKey [NTDLL.@]
254  * ZwEnumerateKey [NTDLL.@]
255  *
256  * NOTES
257  *  the name copied into the buffer is NOT 0-terminated
258  */
259 NTSTATUS WINAPI NtEnumerateKey( HKEY handle, ULONG index, KEY_INFORMATION_CLASS info_class,
260                                 void *info, DWORD length, DWORD *result_len )
261 {
262     /* -1 means query key, so avoid it here */
263     if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
264     return enumerate_key( handle, index, info_class, info, length, result_len );
265 }
266
267
268 /******************************************************************************
269  * NtQueryKey [NTDLL.@]
270  * ZwQueryKey [NTDLL.@]
271  */
272 NTSTATUS WINAPI NtQueryKey( HKEY handle, KEY_INFORMATION_CLASS info_class,
273                             void *info, DWORD length, DWORD *result_len )
274 {
275     return enumerate_key( handle, -1, info_class, info, length, result_len );
276 }
277
278
279 /* fill the key value info structure for a specific info class */
280 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info,
281                                  DWORD length, int type, int name_len, int data_len )
282 {
283     switch(info_class)
284     {
285     case KeyValueBasicInformation:
286         {
287             KEY_VALUE_BASIC_INFORMATION keyinfo;
288             keyinfo.TitleIndex = 0;
289             keyinfo.Type       = type;
290             keyinfo.NameLength = name_len;
291             length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
292             memcpy( info, &keyinfo, length );
293             break;
294         }
295     case KeyValueFullInformation:
296         {
297             KEY_VALUE_FULL_INFORMATION keyinfo;
298             keyinfo.TitleIndex = 0;
299             keyinfo.Type       = type;
300             keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len;
301             keyinfo.DataLength = data_len;
302             keyinfo.NameLength = name_len;
303             length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
304             memcpy( info, &keyinfo, length );
305             break;
306         }
307     case KeyValuePartialInformation:
308         {
309             KEY_VALUE_PARTIAL_INFORMATION keyinfo;
310             keyinfo.TitleIndex = 0;
311             keyinfo.Type       = type;
312             keyinfo.DataLength = data_len;
313             length = min( length, (char *)keyinfo.Data - (char *)&keyinfo );
314             memcpy( info, &keyinfo, length );
315             break;
316         }
317     default:
318         break;
319     }
320 }
321
322
323 /******************************************************************************
324  *  NtEnumerateValueKey [NTDLL.@]
325  *  ZwEnumerateValueKey [NTDLL.@]
326  */
327 NTSTATUS WINAPI NtEnumerateValueKey( HKEY handle, ULONG index,
328                                      KEY_VALUE_INFORMATION_CLASS info_class,
329                                      void *info, DWORD length, DWORD *result_len )
330 {
331     NTSTATUS ret;
332     void *ptr;
333     size_t fixed_size;
334
335     TRACE( "(%p,%lu,%d,%p,%ld)\n", handle, index, info_class, info, length );
336
337     /* compute the length we want to retrieve */
338     switch(info_class)
339     {
340     case KeyValueBasicInformation:   ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break;
341     case KeyValueFullInformation:    ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break;
342     case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break;
343     default:
344         FIXME( "Information class %d not implemented\n", info_class );
345         return STATUS_INVALID_PARAMETER;
346     }
347     fixed_size = (char *)ptr - (char *)info;
348
349     SERVER_START_REQ( enum_key_value )
350     {
351         req->hkey       = handle;
352         req->index      = index;
353         req->info_class = info_class;
354         if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size );
355         if (!(ret = wine_server_call( req )))
356         {
357             copy_key_value_info( info_class, info, length, reply->type, reply->namelen,
358                                  wine_server_reply_size(reply) - reply->namelen );
359             *result_len = fixed_size + reply->total;
360             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
361         }
362     }
363     SERVER_END_REQ;
364     return ret;
365 }
366
367
368 /******************************************************************************
369  * NtQueryValueKey [NTDLL.@]
370  * ZwQueryValueKey [NTDLL.@]
371  *
372  * NOTES
373  *  the name in the KeyValueInformation is never set
374  */
375 NTSTATUS WINAPI NtQueryValueKey( HKEY handle, const UNICODE_STRING *name,
376                                  KEY_VALUE_INFORMATION_CLASS info_class,
377                                  void *info, DWORD length, DWORD *result_len )
378 {
379     NTSTATUS ret;
380     UCHAR *data_ptr;
381     int fixed_size = 0;
382
383     TRACE( "(%p,%s,%d,%p,%ld)\n", handle, debugstr_us(name), info_class, info, length );
384
385     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
386
387     /* compute the length we want to retrieve */
388     switch(info_class)
389     {
390     case KeyValueBasicInformation:
391         fixed_size = (char *)((KEY_VALUE_BASIC_INFORMATION *)info)->Name - (char *)info;
392         data_ptr = NULL;
393         break;
394     case KeyValueFullInformation:
395         data_ptr = (UCHAR *)((KEY_VALUE_FULL_INFORMATION *)info)->Name;
396         fixed_size = (char *)data_ptr - (char *)info;
397         break;
398     case KeyValuePartialInformation:
399         data_ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data;
400         fixed_size = (char *)data_ptr - (char *)info;
401         break;
402     default:
403         FIXME( "Information class %d not implemented\n", info_class );
404         return STATUS_INVALID_PARAMETER;
405     }
406
407     SERVER_START_REQ( get_key_value )
408     {
409         req->hkey = handle;
410         wine_server_add_data( req, name->Buffer, name->Length );
411         if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
412         if (!(ret = wine_server_call( req )))
413         {
414             copy_key_value_info( info_class, info, length, reply->type,
415                                  0, wine_server_reply_size(reply) );
416             *result_len = fixed_size + reply->total;
417             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
418         }
419     }
420     SERVER_END_REQ;
421     return ret;
422 }
423
424
425 /******************************************************************************
426  *  NtFlushKey  [NTDLL.@]
427  *  ZwFlushKey  [NTDLL.@]
428  */
429 NTSTATUS WINAPI NtFlushKey(HKEY KeyHandle)
430 {
431         FIXME("(%p) stub!\n",
432         KeyHandle);
433         return 1;
434 }
435
436 /******************************************************************************
437  *  NtLoadKey   [NTDLL.@]
438  *  ZwLoadKey   [NTDLL.@]
439  */
440 NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, const OBJECT_ATTRIBUTES *file )
441 {
442     FIXME("stub!\n");
443     dump_ObjectAttributes(attr);
444     dump_ObjectAttributes(file);
445     return STATUS_SUCCESS;
446 }
447
448 /******************************************************************************
449  *  NtNotifyChangeKey   [NTDLL.@]
450  *  ZwNotifyChangeKey   [NTDLL.@]
451  */
452 NTSTATUS WINAPI NtNotifyChangeKey(
453         IN HKEY KeyHandle,
454         IN HANDLE Event,
455         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
456         IN PVOID ApcContext OPTIONAL,
457         OUT PIO_STATUS_BLOCK IoStatusBlock,
458         IN ULONG CompletionFilter,
459         IN BOOLEAN Asynchroneous,
460         OUT PVOID ChangeBuffer,
461         IN ULONG Length,
462         IN BOOLEAN WatchSubtree)
463 {
464         FIXME("(%p,%p,%p,%p,%p,0x%08lx, 0x%08x,%p,0x%08lx,0x%08x) stub!\n",
465         KeyHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
466         Asynchroneous, ChangeBuffer, Length, WatchSubtree);
467         return STATUS_SUCCESS;
468 }
469
470 /******************************************************************************
471  * NtQueryMultipleValueKey [NTDLL]
472  * ZwQueryMultipleValueKey
473  */
474
475 NTSTATUS WINAPI NtQueryMultipleValueKey(
476         HKEY KeyHandle,
477         PVALENTW ListOfValuesToQuery,
478         ULONG NumberOfItems,
479         PVOID MultipleValueInformation,
480         ULONG Length,
481         PULONG  ReturnLength)
482 {
483         FIXME("(%p,%p,0x%08lx,%p,0x%08lx,%p) stub!\n",
484         KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
485         Length,ReturnLength);
486         return STATUS_SUCCESS;
487 }
488
489 /******************************************************************************
490  * NtReplaceKey [NTDLL.@]
491  * ZwReplaceKey [NTDLL.@]
492  */
493 NTSTATUS WINAPI NtReplaceKey(
494         IN POBJECT_ATTRIBUTES ObjectAttributes,
495         IN HKEY Key,
496         IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
497 {
498         FIXME("(%p),stub!\n", Key);
499         dump_ObjectAttributes(ObjectAttributes);
500         dump_ObjectAttributes(ReplacedObjectAttributes);
501         return STATUS_SUCCESS;
502 }
503 /******************************************************************************
504  * NtRestoreKey [NTDLL.@]
505  * ZwRestoreKey [NTDLL.@]
506  */
507 NTSTATUS WINAPI NtRestoreKey(
508         HKEY KeyHandle,
509         HANDLE FileHandle,
510         ULONG RestoreFlags)
511 {
512         FIXME("(%p,%p,0x%08lx) stub\n",
513         KeyHandle, FileHandle, RestoreFlags);
514         return STATUS_SUCCESS;
515 }
516 /******************************************************************************
517  * NtSaveKey [NTDLL.@]
518  * ZwSaveKey [NTDLL.@]
519  */
520 NTSTATUS WINAPI NtSaveKey(
521         IN HKEY KeyHandle,
522         IN HANDLE FileHandle)
523 {
524         FIXME("(%p,%p) stub\n",
525         KeyHandle, FileHandle);
526         return STATUS_SUCCESS;
527 }
528 /******************************************************************************
529  * NtSetInformationKey [NTDLL.@]
530  * ZwSetInformationKey [NTDLL.@]
531  */
532 NTSTATUS WINAPI NtSetInformationKey(
533         IN HKEY KeyHandle,
534         IN const int KeyInformationClass,
535         IN PVOID KeyInformation,
536         IN ULONG KeyInformationLength)
537 {
538         FIXME("(%p,0x%08x,%p,0x%08lx) stub\n",
539         KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
540         return STATUS_SUCCESS;
541 }
542
543
544 /******************************************************************************
545  * NtSetValueKey [NTDLL.@]
546  * ZwSetValueKey [NTDLL.@]
547  *
548  * NOTES
549  *   win95 does not care about count for REG_SZ and finds out the len by itself (js)
550  *   NT does definitely care (aj)
551  */
552 NTSTATUS WINAPI NtSetValueKey( HKEY hkey, const UNICODE_STRING *name, ULONG TitleIndex,
553                                ULONG type, const void *data, ULONG count )
554 {
555     NTSTATUS ret;
556
557     TRACE( "(%p,%s,%ld,%p,%ld)\n", hkey, debugstr_us(name), type, data, count );
558
559     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
560
561     SERVER_START_REQ( set_key_value )
562     {
563         req->hkey    = hkey;
564         req->type    = type;
565         req->namelen = name->Length;
566         wine_server_add_data( req, name->Buffer, name->Length );
567         wine_server_add_data( req, data, count );
568         ret = wine_server_call( req );
569     }
570     SERVER_END_REQ;
571     return ret;
572 }
573
574 /******************************************************************************
575  * NtUnloadKey [NTDLL.@]
576  * ZwUnloadKey [NTDLL.@]
577  */
578 NTSTATUS WINAPI NtUnloadKey(
579         IN HKEY KeyHandle)
580 {
581         FIXME("(%p) stub\n",
582         KeyHandle);
583         return STATUS_SUCCESS;
584 }
585
586 /******************************************************************************
587  *  RtlFormatCurrentUserKeyPath         [NTDLL.@]
588  *
589  * NOTE: under NT the user name part of the path is an SID.
590  */
591 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
592 {
593     const char *user = wine_get_user_name();
594     char *buffer;
595     ANSI_STRING AnsiPath;
596     NTSTATUS ret;
597
598     if (!(buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, strlen(user)+16 )))
599         return STATUS_NO_MEMORY;
600
601     strcpy( buffer, "\\Registry\\User\\" );
602     strcat( buffer, user );
603     RtlInitAnsiString( &AnsiPath, buffer );
604     ret = RtlAnsiStringToUnicodeString(KeyPath, &AnsiPath, TRUE);
605     RtlFreeAnsiString( &AnsiPath );
606     return ret;
607 }
608
609 /******************************************************************************
610  *  RtlOpenCurrentUser          [NTDLL.@]
611  *
612  * if we return just HKEY_CURRENT_USER the advapi tries to find a remote
613  * registry (odd handle) and fails
614  *
615  */
616 DWORD WINAPI RtlOpenCurrentUser(
617         IN ACCESS_MASK DesiredAccess, /* [in] */
618         OUT PHKEY KeyHandle)          /* [out] handle of HKEY_CURRENT_USER */
619 {
620         OBJECT_ATTRIBUTES ObjectAttributes;
621         UNICODE_STRING ObjectName;
622         NTSTATUS ret;
623
624         TRACE("(0x%08lx, %p) stub\n",DesiredAccess, KeyHandle);
625
626         RtlFormatCurrentUserKeyPath(&ObjectName);
627         InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
628         ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
629         RtlFreeUnicodeString(&ObjectName);
630         return ret;
631 }