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