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