4 * Copyright (C) 1999 Juergen Schmied
5 * Copyright (C) 2000 Alexandre Julliard
6 * Copyright 2005 Ivan Leo Puoti, Laurent Pinchart
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * HKEY_LOCAL_MACHINE \\REGISTRY\\MACHINE
24 * HKEY_USERS \\REGISTRY\\USER
25 * HKEY_CURRENT_CONFIG \\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT
26 * HKEY_CLASSES \\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES
30 #include "wine/port.h"
37 #define WIN32_NO_STATUS
38 #include "wine/library.h"
39 #include "ntdll_misc.h"
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
45 /* maximum length of a key name in bytes (without terminating null) */
46 #define MAX_NAME_LENGTH (255 * sizeof(WCHAR))
47 /* maximum length of a value name in bytes (without terminating null) */
48 #define MAX_VALUE_LENGTH (16383 * sizeof(WCHAR))
50 /******************************************************************************
51 * NtCreateKey [NTDLL.@]
52 * ZwCreateKey [NTDLL.@]
54 NTSTATUS WINAPI
NtCreateKey( PHANDLE retkey
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
55 ULONG TitleIndex
, const UNICODE_STRING
*class, ULONG options
,
60 if (!retkey
|| !attr
) return STATUS_ACCESS_VIOLATION
;
61 if (attr
->Length
> sizeof(OBJECT_ATTRIBUTES
)) return STATUS_INVALID_PARAMETER
;
62 if (attr
->ObjectName
->Length
> MAX_NAME_LENGTH
) return STATUS_BUFFER_OVERFLOW
;
64 TRACE( "(%p,%s,%s,%x,%x,%p)\n", attr
->RootDirectory
, debugstr_us(attr
->ObjectName
),
65 debugstr_us(class), options
, access
, retkey
);
67 SERVER_START_REQ( create_key
)
69 req
->parent
= wine_server_obj_handle( attr
->RootDirectory
);
71 req
->attributes
= attr
->Attributes
;
72 req
->options
= options
;
73 req
->namelen
= attr
->ObjectName
->Length
;
74 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
75 if (class) wine_server_add_data( req
, class->Buffer
, class->Length
);
76 if (!(ret
= wine_server_call( req
)))
78 *retkey
= wine_server_ptr_handle( reply
->hkey
);
79 if (dispos
) *dispos
= reply
->created
? REG_CREATED_NEW_KEY
: REG_OPENED_EXISTING_KEY
;
83 TRACE("<- %p\n", *retkey
);
87 /******************************************************************************
88 * RtlpNtCreateKey [NTDLL.@]
92 NTSTATUS WINAPI
RtlpNtCreateKey( PHANDLE retkey
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
93 ULONG TitleIndex
, const UNICODE_STRING
*class, ULONG options
,
101 oa
.Attributes
&= ~(OBJ_PERMANENT
|OBJ_EXCLUSIVE
);
105 return NtCreateKey(retkey
, access
, attr
, 0, NULL
, 0, dispos
);
108 /******************************************************************************
109 * NtOpenKey [NTDLL.@]
110 * ZwOpenKey [NTDLL.@]
112 * OUT HANDLE retkey (returns 0 when failure)
113 * IN ACCESS_MASK access
114 * IN POBJECT_ATTRIBUTES attr
116 NTSTATUS WINAPI
NtOpenKey( PHANDLE retkey
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
121 if (!retkey
|| !attr
) return STATUS_ACCESS_VIOLATION
;
122 if (attr
->Length
> sizeof(OBJECT_ATTRIBUTES
)) return STATUS_INVALID_PARAMETER
;
123 len
= attr
->ObjectName
->Length
;
124 TRACE( "(%p,%s,%x,%p)\n", attr
->RootDirectory
,
125 debugstr_us(attr
->ObjectName
), access
, retkey
);
127 if (len
> MAX_NAME_LENGTH
) return STATUS_BUFFER_OVERFLOW
;
129 SERVER_START_REQ( open_key
)
131 req
->parent
= wine_server_obj_handle( attr
->RootDirectory
);
132 req
->access
= access
;
133 req
->attributes
= attr
->Attributes
;
134 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
135 ret
= wine_server_call( req
);
136 *retkey
= wine_server_ptr_handle( reply
->hkey
);
139 TRACE("<- %p\n", *retkey
);
143 /******************************************************************************
144 * RtlpNtOpenKey [NTDLL.@]
148 NTSTATUS WINAPI
RtlpNtOpenKey( PHANDLE retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
151 attr
->Attributes
&= ~(OBJ_PERMANENT
|OBJ_EXCLUSIVE
);
152 return NtOpenKey(retkey
, access
, attr
);
155 /******************************************************************************
156 * NtDeleteKey [NTDLL.@]
157 * ZwDeleteKey [NTDLL.@]
159 NTSTATUS WINAPI
NtDeleteKey( HANDLE hkey
)
163 TRACE( "(%p)\n", hkey
);
165 SERVER_START_REQ( delete_key
)
167 req
->hkey
= wine_server_obj_handle( hkey
);
168 ret
= wine_server_call( req
);
174 /******************************************************************************
175 * RtlpNtMakeTemporaryKey [NTDLL.@]
179 NTSTATUS WINAPI
RtlpNtMakeTemporaryKey( HANDLE hkey
)
181 return NtDeleteKey(hkey
);
184 /******************************************************************************
185 * NtDeleteValueKey [NTDLL.@]
186 * ZwDeleteValueKey [NTDLL.@]
188 NTSTATUS WINAPI
NtDeleteValueKey( HANDLE hkey
, const UNICODE_STRING
*name
)
192 TRACE( "(%p,%s)\n", hkey
, debugstr_us(name
) );
193 if (name
->Length
> MAX_VALUE_LENGTH
) return STATUS_BUFFER_OVERFLOW
;
195 SERVER_START_REQ( delete_key_value
)
197 req
->hkey
= wine_server_obj_handle( hkey
);
198 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
199 ret
= wine_server_call( req
);
206 /******************************************************************************
209 * Implementation of NtQueryKey and NtEnumerateKey
211 static NTSTATUS
enumerate_key( HANDLE handle
, int index
, KEY_INFORMATION_CLASS info_class
,
212 void *info
, DWORD length
, DWORD
*result_len
)
221 case KeyBasicInformation
: data_ptr
= ((KEY_BASIC_INFORMATION
*)info
)->Name
; break;
222 case KeyFullInformation
: data_ptr
= ((KEY_FULL_INFORMATION
*)info
)->Class
; break;
223 case KeyNodeInformation
: data_ptr
= ((KEY_NODE_INFORMATION
*)info
)->Name
; break;
224 case KeyNameInformation
: data_ptr
= ((KEY_NAME_INFORMATION
*)info
)->Name
; break;
226 FIXME( "Information class %d not implemented\n", info_class
);
227 return STATUS_INVALID_PARAMETER
;
229 fixed_size
= (char *)data_ptr
- (char *)info
;
231 SERVER_START_REQ( enum_key
)
233 req
->hkey
= wine_server_obj_handle( handle
);
235 req
->info_class
= info_class
;
236 if (length
> fixed_size
) wine_server_set_reply( req
, data_ptr
, length
- fixed_size
);
237 if (!(ret
= wine_server_call( req
)))
241 case KeyBasicInformation
:
243 KEY_BASIC_INFORMATION keyinfo
;
244 fixed_size
= (char *)keyinfo
.Name
- (char *)&keyinfo
;
245 keyinfo
.LastWriteTime
.QuadPart
= reply
->modif
;
246 keyinfo
.TitleIndex
= 0;
247 keyinfo
.NameLength
= reply
->namelen
;
248 memcpy( info
, &keyinfo
, min( length
, fixed_size
) );
251 case KeyFullInformation
:
253 KEY_FULL_INFORMATION keyinfo
;
254 fixed_size
= (char *)keyinfo
.Class
- (char *)&keyinfo
;
255 keyinfo
.LastWriteTime
.QuadPart
= reply
->modif
;
256 keyinfo
.TitleIndex
= 0;
257 keyinfo
.ClassLength
= wine_server_reply_size(reply
);
258 keyinfo
.ClassOffset
= keyinfo
.ClassLength
? fixed_size
: -1;
259 keyinfo
.SubKeys
= reply
->subkeys
;
260 keyinfo
.MaxNameLen
= reply
->max_subkey
;
261 keyinfo
.MaxClassLen
= reply
->max_class
;
262 keyinfo
.Values
= reply
->values
;
263 keyinfo
.MaxValueNameLen
= reply
->max_value
;
264 keyinfo
.MaxValueDataLen
= reply
->max_data
;
265 memcpy( info
, &keyinfo
, min( length
, fixed_size
) );
268 case KeyNodeInformation
:
270 KEY_NODE_INFORMATION keyinfo
;
271 fixed_size
= (char *)keyinfo
.Name
- (char *)&keyinfo
;
272 keyinfo
.LastWriteTime
.QuadPart
= reply
->modif
;
273 keyinfo
.TitleIndex
= 0;
274 if (reply
->namelen
< wine_server_reply_size(reply
))
276 keyinfo
.ClassLength
= wine_server_reply_size(reply
) - reply
->namelen
;
277 keyinfo
.ClassOffset
= fixed_size
+ reply
->namelen
;
281 keyinfo
.ClassLength
= 0;
282 keyinfo
.ClassOffset
= -1;
284 keyinfo
.NameLength
= reply
->namelen
;
285 memcpy( info
, &keyinfo
, min( length
, fixed_size
) );
288 case KeyNameInformation
:
290 KEY_NAME_INFORMATION keyinfo
;
291 fixed_size
= (char *)keyinfo
.Name
- (char *)&keyinfo
;
292 keyinfo
.NameLength
= reply
->namelen
;
293 memcpy( info
, &keyinfo
, min( length
, fixed_size
) );
297 *result_len
= fixed_size
+ reply
->total
;
298 if (length
< *result_len
) ret
= STATUS_BUFFER_OVERFLOW
;
307 /******************************************************************************
308 * NtEnumerateKey [NTDLL.@]
309 * ZwEnumerateKey [NTDLL.@]
312 * the name copied into the buffer is NOT 0-terminated
314 NTSTATUS WINAPI
NtEnumerateKey( HANDLE handle
, ULONG index
, KEY_INFORMATION_CLASS info_class
,
315 void *info
, DWORD length
, DWORD
*result_len
)
317 /* -1 means query key, so avoid it here */
318 if (index
== (ULONG
)-1) return STATUS_NO_MORE_ENTRIES
;
319 return enumerate_key( handle
, index
, info_class
, info
, length
, result_len
);
323 /******************************************************************************
324 * RtlpNtEnumerateSubKey [NTDLL.@]
327 NTSTATUS WINAPI
RtlpNtEnumerateSubKey( HANDLE handle
, UNICODE_STRING
*out
, ULONG index
)
329 KEY_BASIC_INFORMATION
*info
;
330 DWORD dwLen
, dwResultLen
;
335 dwLen
= out
->Length
+ sizeof(KEY_BASIC_INFORMATION
);
336 info
= RtlAllocateHeap( GetProcessHeap(), 0, dwLen
);
338 return STATUS_NO_MEMORY
;
346 ret
= NtEnumerateKey( handle
, index
, KeyBasicInformation
, info
, dwLen
, &dwResultLen
);
347 dwResultLen
-= sizeof(KEY_BASIC_INFORMATION
);
349 if (ret
== STATUS_BUFFER_OVERFLOW
)
350 out
->Length
= dwResultLen
;
353 if (out
->Length
< info
->NameLength
)
355 out
->Length
= dwResultLen
;
356 ret
= STATUS_BUFFER_OVERFLOW
;
360 out
->Length
= info
->NameLength
;
361 memcpy(out
->Buffer
, info
->Name
, info
->NameLength
);
365 RtlFreeHeap( GetProcessHeap(), 0, info
);
369 /******************************************************************************
370 * NtQueryKey [NTDLL.@]
371 * ZwQueryKey [NTDLL.@]
373 NTSTATUS WINAPI
NtQueryKey( HANDLE handle
, KEY_INFORMATION_CLASS info_class
,
374 void *info
, DWORD length
, DWORD
*result_len
)
376 return enumerate_key( handle
, -1, info_class
, info
, length
, result_len
);
380 /* fill the key value info structure for a specific info class */
381 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class
, void *info
,
382 DWORD length
, int type
, int name_len
, int data_len
)
386 case KeyValueBasicInformation
:
388 KEY_VALUE_BASIC_INFORMATION keyinfo
;
389 keyinfo
.TitleIndex
= 0;
391 keyinfo
.NameLength
= name_len
;
392 length
= min( length
, (char *)keyinfo
.Name
- (char *)&keyinfo
);
393 memcpy( info
, &keyinfo
, length
);
396 case KeyValueFullInformation
:
398 KEY_VALUE_FULL_INFORMATION keyinfo
;
399 keyinfo
.TitleIndex
= 0;
401 keyinfo
.DataOffset
= (char *)keyinfo
.Name
- (char *)&keyinfo
+ name_len
;
402 keyinfo
.DataLength
= data_len
;
403 keyinfo
.NameLength
= name_len
;
404 length
= min( length
, (char *)keyinfo
.Name
- (char *)&keyinfo
);
405 memcpy( info
, &keyinfo
, length
);
408 case KeyValuePartialInformation
:
410 KEY_VALUE_PARTIAL_INFORMATION keyinfo
;
411 keyinfo
.TitleIndex
= 0;
413 keyinfo
.DataLength
= data_len
;
414 length
= min( length
, (char *)keyinfo
.Data
- (char *)&keyinfo
);
415 memcpy( info
, &keyinfo
, length
);
424 /******************************************************************************
425 * NtEnumerateValueKey [NTDLL.@]
426 * ZwEnumerateValueKey [NTDLL.@]
428 NTSTATUS WINAPI
NtEnumerateValueKey( HANDLE handle
, ULONG index
,
429 KEY_VALUE_INFORMATION_CLASS info_class
,
430 void *info
, DWORD length
, DWORD
*result_len
)
436 TRACE( "(%p,%u,%d,%p,%d)\n", handle
, index
, info_class
, info
, length
);
438 /* compute the length we want to retrieve */
441 case KeyValueBasicInformation
: ptr
= ((KEY_VALUE_BASIC_INFORMATION
*)info
)->Name
; break;
442 case KeyValueFullInformation
: ptr
= ((KEY_VALUE_FULL_INFORMATION
*)info
)->Name
; break;
443 case KeyValuePartialInformation
: ptr
= ((KEY_VALUE_PARTIAL_INFORMATION
*)info
)->Data
; break;
445 FIXME( "Information class %d not implemented\n", info_class
);
446 return STATUS_INVALID_PARAMETER
;
448 fixed_size
= (char *)ptr
- (char *)info
;
450 SERVER_START_REQ( enum_key_value
)
452 req
->hkey
= wine_server_obj_handle( handle
);
454 req
->info_class
= info_class
;
455 if (length
> fixed_size
) wine_server_set_reply( req
, ptr
, length
- fixed_size
);
456 if (!(ret
= wine_server_call( req
)))
458 copy_key_value_info( info_class
, info
, length
, reply
->type
, reply
->namelen
,
459 wine_server_reply_size(reply
) - reply
->namelen
);
460 *result_len
= fixed_size
+ reply
->total
;
461 if (length
< *result_len
) ret
= STATUS_BUFFER_OVERFLOW
;
469 /******************************************************************************
470 * NtQueryValueKey [NTDLL.@]
471 * ZwQueryValueKey [NTDLL.@]
474 * the name in the KeyValueInformation is never set
476 NTSTATUS WINAPI
NtQueryValueKey( HANDLE handle
, const UNICODE_STRING
*name
,
477 KEY_VALUE_INFORMATION_CLASS info_class
,
478 void *info
, DWORD length
, DWORD
*result_len
)
482 unsigned int fixed_size
= 0, min_size
= 0;
484 TRACE( "(%p,%s,%d,%p,%d)\n", handle
, debugstr_us(name
), info_class
, info
, length
);
486 if (name
->Length
> MAX_VALUE_LENGTH
) return STATUS_BUFFER_OVERFLOW
;
488 /* compute the length we want to retrieve */
491 case KeyValueBasicInformation
:
493 KEY_VALUE_BASIC_INFORMATION
*basic_info
= info
;
494 min_size
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
);
495 fixed_size
= min_size
+ name
->Length
;
496 if (min_size
< length
)
497 memcpy(basic_info
->Name
, name
->Buffer
, min(length
- min_size
, name
->Length
));
501 case KeyValueFullInformation
:
503 KEY_VALUE_FULL_INFORMATION
*full_info
= info
;
504 min_size
= FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
);
505 fixed_size
= min_size
+ name
->Length
;
506 if (min_size
< length
)
507 memcpy(full_info
->Name
, name
->Buffer
, min(length
- min_size
, name
->Length
));
508 data_ptr
= (UCHAR
*)full_info
->Name
+ name
->Length
;
511 case KeyValuePartialInformation
:
512 min_size
= fixed_size
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
513 data_ptr
= ((KEY_VALUE_PARTIAL_INFORMATION
*)info
)->Data
;
516 FIXME( "Information class %d not implemented\n", info_class
);
517 return STATUS_INVALID_PARAMETER
;
520 SERVER_START_REQ( get_key_value
)
522 req
->hkey
= wine_server_obj_handle( handle
);
523 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
524 if (length
> fixed_size
&& data_ptr
) wine_server_set_reply( req
, data_ptr
, length
- fixed_size
);
525 if (!(ret
= wine_server_call( req
)))
527 copy_key_value_info( info_class
, info
, length
, reply
->type
,
528 name
->Length
, reply
->total
);
529 *result_len
= fixed_size
+ (info_class
== KeyValueBasicInformation
? 0 : reply
->total
);
530 if (length
< min_size
) ret
= STATUS_BUFFER_TOO_SMALL
;
531 else if (length
< *result_len
) ret
= STATUS_BUFFER_OVERFLOW
;
538 /******************************************************************************
539 * RtlpNtQueryValueKey [NTDLL.@]
542 NTSTATUS WINAPI
RtlpNtQueryValueKey( HANDLE handle
, ULONG
*result_type
, PBYTE dest
,
543 DWORD
*result_len
, void *unknown
)
545 KEY_VALUE_PARTIAL_INFORMATION
*info
;
549 DWORD dwLen
= sizeof (KEY_VALUE_PARTIAL_INFORMATION
) + (result_len
? *result_len
: 0);
551 info
= RtlAllocateHeap( GetProcessHeap(), 0, dwLen
);
553 return STATUS_NO_MEMORY
;
556 ret
= NtQueryValueKey( handle
, &name
, KeyValuePartialInformation
, info
, dwLen
, &dwResultLen
);
558 if (!ret
|| ret
== STATUS_BUFFER_OVERFLOW
)
561 *result_len
= info
->DataLength
;
564 *result_type
= info
->Type
;
566 if (ret
!= STATUS_BUFFER_OVERFLOW
)
567 memcpy( dest
, info
->Data
, info
->DataLength
);
570 RtlFreeHeap( GetProcessHeap(), 0, info
);
574 /******************************************************************************
575 * NtFlushKey [NTDLL.@]
576 * ZwFlushKey [NTDLL.@]
578 NTSTATUS WINAPI
NtFlushKey(HANDLE key
)
582 TRACE("key=%p\n", key
);
584 SERVER_START_REQ( flush_key
)
586 req
->hkey
= wine_server_obj_handle( key
);
587 ret
= wine_server_call( req
);
594 /******************************************************************************
595 * NtLoadKey [NTDLL.@]
596 * ZwLoadKey [NTDLL.@]
598 NTSTATUS WINAPI
NtLoadKey( const OBJECT_ATTRIBUTES
*attr
, OBJECT_ATTRIBUTES
*file
)
604 TRACE("(%p,%p)\n", attr
, file
);
606 ret
= NtCreateFile(&hive
, GENERIC_READ
, file
, &io
, NULL
, FILE_ATTRIBUTE_NORMAL
, 0,
607 FILE_OPEN
, 0, NULL
, 0);
610 SERVER_START_REQ( load_registry
)
612 req
->hkey
= wine_server_obj_handle( attr
->RootDirectory
);
613 req
->file
= wine_server_obj_handle( hive
);
614 wine_server_add_data(req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
615 ret
= wine_server_call( req
);
624 /******************************************************************************
625 * NtNotifyChangeKey [NTDLL.@]
626 * ZwNotifyChangeKey [NTDLL.@]
628 NTSTATUS WINAPI
NtNotifyChangeKey(
631 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
632 IN PVOID ApcContext OPTIONAL
,
633 OUT PIO_STATUS_BLOCK IoStatusBlock
,
634 IN ULONG CompletionFilter
,
635 IN BOOLEAN Asynchronous
,
636 OUT PVOID ChangeBuffer
,
638 IN BOOLEAN WatchSubtree
)
642 TRACE("(%p,%p,%p,%p,%p,0x%08x, 0x%08x,%p,0x%08x,0x%08x)\n",
643 KeyHandle
, Event
, ApcRoutine
, ApcContext
, IoStatusBlock
, CompletionFilter
,
644 Asynchronous
, ChangeBuffer
, Length
, WatchSubtree
);
646 if (ApcRoutine
|| ApcContext
|| ChangeBuffer
|| Length
)
647 FIXME("Unimplemented optional parameter\n");
651 OBJECT_ATTRIBUTES attr
;
652 InitializeObjectAttributes( &attr
, NULL
, 0, NULL
, NULL
);
653 ret
= NtCreateEvent( &Event
, EVENT_ALL_ACCESS
, &attr
, SynchronizationEvent
, FALSE
);
654 if (ret
!= STATUS_SUCCESS
)
658 SERVER_START_REQ( set_registry_notification
)
660 req
->hkey
= wine_server_obj_handle( KeyHandle
);
661 req
->event
= wine_server_obj_handle( Event
);
662 req
->subtree
= WatchSubtree
;
663 req
->filter
= CompletionFilter
;
664 ret
= wine_server_call( req
);
670 if (ret
== STATUS_SUCCESS
)
671 NtWaitForSingleObject( Event
, FALSE
, NULL
);
675 return STATUS_SUCCESS
;
678 /******************************************************************************
679 * NtQueryMultipleValueKey [NTDLL]
680 * ZwQueryMultipleValueKey
683 NTSTATUS WINAPI
NtQueryMultipleValueKey(
685 PKEY_MULTIPLE_VALUE_INFORMATION ListOfValuesToQuery
,
687 PVOID MultipleValueInformation
,
691 FIXME("(%p,%p,0x%08x,%p,0x%08x,%p) stub!\n",
692 KeyHandle
, ListOfValuesToQuery
, NumberOfItems
, MultipleValueInformation
,
693 Length
,ReturnLength
);
694 return STATUS_SUCCESS
;
697 /******************************************************************************
698 * NtReplaceKey [NTDLL.@]
699 * ZwReplaceKey [NTDLL.@]
701 NTSTATUS WINAPI
NtReplaceKey(
702 IN POBJECT_ATTRIBUTES ObjectAttributes
,
704 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
706 FIXME("(%s,%p,%s),stub!\n", debugstr_ObjectAttributes(ObjectAttributes
), Key
,
707 debugstr_ObjectAttributes(ReplacedObjectAttributes
) );
708 return STATUS_SUCCESS
;
710 /******************************************************************************
711 * NtRestoreKey [NTDLL.@]
712 * ZwRestoreKey [NTDLL.@]
714 NTSTATUS WINAPI
NtRestoreKey(
719 FIXME("(%p,%p,0x%08x) stub\n",
720 KeyHandle
, FileHandle
, RestoreFlags
);
721 return STATUS_SUCCESS
;
723 /******************************************************************************
724 * NtSaveKey [NTDLL.@]
725 * ZwSaveKey [NTDLL.@]
727 NTSTATUS WINAPI
NtSaveKey(IN HANDLE KeyHandle
, IN HANDLE FileHandle
)
731 TRACE("(%p,%p)\n", KeyHandle
, FileHandle
);
733 SERVER_START_REQ( save_registry
)
735 req
->hkey
= wine_server_obj_handle( KeyHandle
);
736 req
->file
= wine_server_obj_handle( FileHandle
);
737 ret
= wine_server_call( req
);
743 /******************************************************************************
744 * NtSetInformationKey [NTDLL.@]
745 * ZwSetInformationKey [NTDLL.@]
747 NTSTATUS WINAPI
NtSetInformationKey(
749 IN
const int KeyInformationClass
,
750 IN PVOID KeyInformation
,
751 IN ULONG KeyInformationLength
)
753 FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
754 KeyHandle
, KeyInformationClass
, KeyInformation
, KeyInformationLength
);
755 return STATUS_SUCCESS
;
759 /******************************************************************************
760 * NtSetValueKey [NTDLL.@]
761 * ZwSetValueKey [NTDLL.@]
764 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
765 * NT does definitely care (aj)
767 NTSTATUS WINAPI
NtSetValueKey( HANDLE hkey
, const UNICODE_STRING
*name
, ULONG TitleIndex
,
768 ULONG type
, const void *data
, ULONG count
)
772 TRACE( "(%p,%s,%d,%p,%d)\n", hkey
, debugstr_us(name
), type
, data
, count
);
774 if (name
->Length
> MAX_VALUE_LENGTH
) return STATUS_BUFFER_OVERFLOW
;
776 SERVER_START_REQ( set_key_value
)
778 req
->hkey
= wine_server_obj_handle( hkey
);
780 req
->namelen
= name
->Length
;
781 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
782 wine_server_add_data( req
, data
, count
);
783 ret
= wine_server_call( req
);
789 /******************************************************************************
790 * RtlpNtSetValueKey [NTDLL.@]
793 NTSTATUS WINAPI
RtlpNtSetValueKey( HANDLE hkey
, ULONG type
, const void *data
,
799 return NtSetValueKey( hkey
, &name
, 0, type
, data
, count
);
802 /******************************************************************************
803 * NtUnloadKey [NTDLL.@]
804 * ZwUnloadKey [NTDLL.@]
806 NTSTATUS WINAPI
NtUnloadKey(IN POBJECT_ATTRIBUTES attr
)
810 TRACE("(%p)\n", attr
);
812 SERVER_START_REQ( unload_registry
)
814 req
->hkey
= wine_server_obj_handle( attr
->RootDirectory
);
815 ret
= wine_server_call(req
);
822 /******************************************************************************
823 * RtlFormatCurrentUserKeyPath [NTDLL.@]
826 NTSTATUS WINAPI
RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath
)
828 static const WCHAR pathW
[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
832 status
= NtOpenThreadToken(GetCurrentThread(), TOKEN_READ
, TRUE
, &token
);
833 if (status
== STATUS_NO_TOKEN
)
834 status
= NtOpenProcessToken(GetCurrentProcess(), TOKEN_READ
, &token
);
835 if (status
== STATUS_SUCCESS
)
837 char buffer
[sizeof(TOKEN_USER
) + sizeof(SID
) + sizeof(DWORD
)*SID_MAX_SUB_AUTHORITIES
];
838 DWORD len
= sizeof(buffer
);
840 status
= NtQueryInformationToken(token
, TokenUser
, buffer
, len
, &len
);
841 if (status
== STATUS_SUCCESS
)
843 KeyPath
->MaximumLength
= 0;
844 status
= RtlConvertSidToUnicodeString(KeyPath
, ((TOKEN_USER
*)buffer
)->User
.Sid
, FALSE
);
845 if (status
== STATUS_BUFFER_OVERFLOW
)
847 PWCHAR buf
= RtlAllocateHeap(GetProcessHeap(), 0,
848 sizeof(pathW
) + KeyPath
->Length
+ sizeof(WCHAR
));
851 memcpy(buf
, pathW
, sizeof(pathW
));
852 KeyPath
->MaximumLength
= KeyPath
->Length
+ sizeof(WCHAR
);
853 KeyPath
->Buffer
= (PWCHAR
)((LPBYTE
)buf
+ sizeof(pathW
));
854 status
= RtlConvertSidToUnicodeString(KeyPath
,
855 ((TOKEN_USER
*)buffer
)->User
.Sid
, FALSE
);
856 KeyPath
->Buffer
= buf
;
857 KeyPath
->Length
+= sizeof(pathW
);
858 KeyPath
->MaximumLength
+= sizeof(pathW
);
861 status
= STATUS_NO_MEMORY
;
869 /******************************************************************************
870 * RtlOpenCurrentUser [NTDLL.@]
873 * If we return just HKEY_CURRENT_USER the advapi tries to find a remote
874 * registry (odd handle) and fails.
876 NTSTATUS WINAPI
RtlOpenCurrentUser(
877 IN ACCESS_MASK DesiredAccess
, /* [in] */
878 OUT PHANDLE KeyHandle
) /* [out] handle of HKEY_CURRENT_USER */
880 OBJECT_ATTRIBUTES ObjectAttributes
;
881 UNICODE_STRING ObjectName
;
884 TRACE("(0x%08x, %p)\n",DesiredAccess
, KeyHandle
);
886 if ((ret
= RtlFormatCurrentUserKeyPath(&ObjectName
))) return ret
;
887 InitializeObjectAttributes(&ObjectAttributes
,&ObjectName
,OBJ_CASE_INSENSITIVE
,0, NULL
);
888 ret
= NtCreateKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
889 RtlFreeUnicodeString(&ObjectName
);
894 static NTSTATUS
RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo
,
895 PRTL_QUERY_REGISTRY_TABLE pQuery
, PVOID pContext
, PVOID pEnvironment
)
898 UNICODE_STRING src
, dst
;
903 NTSTATUS status
= STATUS_SUCCESS
;
910 if (pQuery
->Flags
& RTL_QUERY_REGISTRY_DIRECT
)
911 return STATUS_INVALID_PARAMETER
;
914 status
= pQuery
->QueryRoutine(pQuery
->Name
, pQuery
->DefaultType
, pQuery
->DefaultData
,
915 pQuery
->DefaultLength
, pContext
, pQuery
->EntryContext
);
919 len
= pInfo
->DataLength
;
921 if (pQuery
->Flags
& RTL_QUERY_REGISTRY_DIRECT
)
923 str
= pQuery
->EntryContext
;
928 if (!(pQuery
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
))
930 RtlInitUnicodeString(&src
, (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
));
932 dst
.MaximumLength
= 0;
933 RtlExpandEnvironmentStrings_U(pEnvironment
, &src
, &dst
, &res
);
935 dst
.MaximumLength
= res
;
936 dst
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, res
* sizeof(WCHAR
));
937 RtlExpandEnvironmentStrings_U(pEnvironment
, &src
, &dst
, &res
);
938 status
= pQuery
->QueryRoutine(pQuery
->Name
, pInfo
->Type
, dst
.Buffer
,
939 dst
.Length
, pContext
, pQuery
->EntryContext
);
940 RtlFreeHeap(GetProcessHeap(), 0, dst
.Buffer
);
945 if (str
->Buffer
== NULL
)
946 RtlCreateUnicodeString(str
, (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
));
948 RtlAppendUnicodeToString(str
, (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
));
952 if (!(pQuery
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
))
953 return STATUS_INVALID_PARAMETER
;
955 if (str
->Buffer
== NULL
)
957 str
->Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
958 str
->MaximumLength
= len
;
960 len
= min(len
, str
->MaximumLength
);
961 memcpy(str
->Buffer
, ((CHAR
*)pInfo
) + pInfo
->DataOffset
, len
);
966 bin
= pQuery
->EntryContext
;
967 if (pInfo
->DataLength
<= sizeof(ULONG
))
968 memcpy(bin
, ((CHAR
*)pInfo
) + pInfo
->DataOffset
,
972 if (bin
[0] <= sizeof(ULONG
))
974 memcpy(&bin
[1], ((CHAR
*)pInfo
) + pInfo
->DataOffset
,
975 min(-bin
[0], pInfo
->DataLength
));
979 len
= min(bin
[0], pInfo
->DataLength
);
981 bin
[2] = pInfo
->Type
;
982 memcpy(&bin
[3], ((CHAR
*)pInfo
) + pInfo
->DataOffset
, len
);
990 if((pQuery
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
) ||
991 (pInfo
->Type
!= REG_EXPAND_SZ
&& pInfo
->Type
!= REG_MULTI_SZ
))
993 status
= pQuery
->QueryRoutine(pQuery
->Name
, pInfo
->Type
,
994 ((CHAR
*)pInfo
) + pInfo
->DataOffset
, pInfo
->DataLength
,
995 pContext
, pQuery
->EntryContext
);
997 else if (pInfo
->Type
== REG_EXPAND_SZ
)
999 RtlInitUnicodeString(&src
, (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
));
1001 dst
.MaximumLength
= 0;
1002 RtlExpandEnvironmentStrings_U(pEnvironment
, &src
, &dst
, &res
);
1004 dst
.MaximumLength
= res
;
1005 dst
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, res
* sizeof(WCHAR
));
1006 RtlExpandEnvironmentStrings_U(pEnvironment
, &src
, &dst
, &res
);
1007 status
= pQuery
->QueryRoutine(pQuery
->Name
, pInfo
->Type
, dst
.Buffer
,
1008 dst
.Length
, pContext
, pQuery
->EntryContext
);
1009 RtlFreeHeap(GetProcessHeap(), 0, dst
.Buffer
);
1011 else /* REG_MULTI_SZ */
1013 if(pQuery
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
)
1015 for (offset
= 0; offset
<= pInfo
->DataLength
; offset
+= len
+ sizeof(WCHAR
))
1017 wstr
= (WCHAR
*)(((CHAR
*)pInfo
) + offset
);
1018 len
= strlenW(wstr
) * sizeof(WCHAR
);
1019 status
= pQuery
->QueryRoutine(pQuery
->Name
, pInfo
->Type
, wstr
, len
,
1020 pContext
, pQuery
->EntryContext
);
1021 if(status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
1027 while(count
<=pInfo
->DataLength
)
1029 String
= (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
)+count
;
1030 count
+=strlenW(String
)+1;
1031 RtlInitUnicodeString(&src
, (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
));
1033 dst
.MaximumLength
= 0;
1034 RtlExpandEnvironmentStrings_U(pEnvironment
, &src
, &dst
, &res
);
1036 dst
.MaximumLength
= res
;
1037 dst
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, res
* sizeof(WCHAR
));
1038 RtlExpandEnvironmentStrings_U(pEnvironment
, &src
, &dst
, &res
);
1039 status
= pQuery
->QueryRoutine(pQuery
->Name
, pInfo
->Type
, dst
.Buffer
,
1040 dst
.Length
, pContext
, pQuery
->EntryContext
);
1041 RtlFreeHeap(GetProcessHeap(), 0, dst
.Buffer
);
1042 if(status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
1052 static NTSTATUS
RTL_GetKeyHandle(ULONG RelativeTo
, PCWSTR Path
, PHANDLE handle
)
1054 UNICODE_STRING KeyString
;
1055 OBJECT_ATTRIBUTES regkey
;
1060 static const WCHAR empty
[] = {0};
1061 static const WCHAR control
[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1062 '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1063 'C','o','n','t','r','o','l','\\',0};
1065 static const WCHAR devicemap
[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1066 'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1068 static const WCHAR services
[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1069 'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1070 'S','e','r','v','i','c','e','s','\\',0};
1072 static const WCHAR user
[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1073 'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1075 static const WCHAR windows_nt
[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1076 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1077 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1079 switch (RelativeTo
& 0xff)
1081 case RTL_REGISTRY_ABSOLUTE
:
1085 case RTL_REGISTRY_CONTROL
:
1089 case RTL_REGISTRY_DEVICEMAP
:
1093 case RTL_REGISTRY_SERVICES
:
1097 case RTL_REGISTRY_USER
:
1101 case RTL_REGISTRY_WINDOWS_NT
:
1106 return STATUS_INVALID_PARAMETER
;
1109 len
= (strlenW(base
) + strlenW(Path
) + 1) * sizeof(WCHAR
);
1110 KeyString
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
1111 if (KeyString
.Buffer
== NULL
)
1112 return STATUS_NO_MEMORY
;
1114 strcpyW(KeyString
.Buffer
, base
);
1115 strcatW(KeyString
.Buffer
, Path
);
1116 KeyString
.Length
= len
- sizeof(WCHAR
);
1117 KeyString
.MaximumLength
= len
;
1118 InitializeObjectAttributes(®key
, &KeyString
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
1119 status
= NtOpenKey(handle
, KEY_ALL_ACCESS
, ®key
);
1120 RtlFreeHeap(GetProcessHeap(), 0, KeyString
.Buffer
);
1124 /*************************************************************************
1125 * RtlQueryRegistryValues [NTDLL.@]
1127 * Query multiple registry values with a signle call.
1130 * RelativeTo [I] Registry path that Path refers to
1131 * Path [I] Path to key
1132 * QueryTable [I] Table of key values to query
1133 * Context [I] Parameter to pass to the application defined QueryRoutine function
1134 * Environment [I] Optional parameter to use when performing expansion
1137 * STATUS_SUCCESS or an appropriate NTSTATUS error code.
1139 NTSTATUS WINAPI
RtlQueryRegistryValues(IN ULONG RelativeTo
, IN PCWSTR Path
,
1140 IN PRTL_QUERY_REGISTRY_TABLE QueryTable
, IN PVOID Context
,
1141 IN PVOID Environment OPTIONAL
)
1143 UNICODE_STRING Value
;
1144 HANDLE handle
, topkey
;
1145 PKEY_VALUE_FULL_INFORMATION pInfo
= NULL
;
1146 ULONG len
, buflen
= 0;
1147 NTSTATUS status
=STATUS_SUCCESS
, ret
= STATUS_SUCCESS
;
1150 TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo
, debugstr_w(Path
), QueryTable
, Context
, Environment
);
1153 return STATUS_INVALID_PARAMETER
;
1155 /* get a valid handle */
1156 if (RelativeTo
& RTL_REGISTRY_HANDLE
)
1157 topkey
= handle
= (HANDLE
)Path
;
1160 status
= RTL_GetKeyHandle(RelativeTo
, Path
, &topkey
);
1163 if(status
!= STATUS_SUCCESS
)
1166 /* Process query table entries */
1167 for (; QueryTable
->QueryRoutine
!= NULL
|| QueryTable
->Name
!= NULL
; ++QueryTable
)
1169 if (QueryTable
->Flags
&
1170 (RTL_QUERY_REGISTRY_SUBKEY
| RTL_QUERY_REGISTRY_TOPKEY
))
1172 /* topkey must be kept open just in case we will reuse it later */
1173 if (handle
!= topkey
)
1176 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_SUBKEY
)
1179 status
= RTL_GetKeyHandle(PtrToUlong(QueryTable
->Name
), Path
, &handle
);
1180 if(status
!= STATUS_SUCCESS
)
1190 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_NOVALUE
)
1192 QueryTable
->QueryRoutine(QueryTable
->Name
, REG_NONE
, NULL
, 0,
1193 Context
, QueryTable
->EntryContext
);
1199 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
)
1201 ret
= STATUS_OBJECT_NAME_NOT_FOUND
;
1207 if (QueryTable
->Name
== NULL
)
1209 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_DIRECT
)
1211 ret
= STATUS_INVALID_PARAMETER
;
1215 /* Report all subkeys */
1218 status
= NtEnumerateValueKey(handle
, i
,
1219 KeyValueFullInformation
, pInfo
, buflen
, &len
);
1220 if (status
== STATUS_NO_MORE_ENTRIES
)
1222 if (status
== STATUS_BUFFER_OVERFLOW
||
1223 status
== STATUS_BUFFER_TOO_SMALL
)
1226 RtlFreeHeap(GetProcessHeap(), 0, pInfo
);
1227 pInfo
= RtlAllocateHeap(GetProcessHeap(), 0, buflen
);
1228 NtEnumerateValueKey(handle
, i
, KeyValueFullInformation
,
1229 pInfo
, buflen
, &len
);
1232 status
= RTL_ReportRegistryValue(pInfo
, QueryTable
, Context
, Environment
);
1233 if(status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
1238 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_DELETE
)
1240 RtlInitUnicodeString(&Value
, pInfo
->Name
);
1241 NtDeleteValueKey(handle
, &Value
);
1245 if (i
== 0 && (QueryTable
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
))
1247 ret
= STATUS_OBJECT_NAME_NOT_FOUND
;
1253 RtlInitUnicodeString(&Value
, QueryTable
->Name
);
1254 status
= NtQueryValueKey(handle
, &Value
, KeyValueFullInformation
,
1255 pInfo
, buflen
, &len
);
1256 if (status
== STATUS_BUFFER_OVERFLOW
||
1257 status
== STATUS_BUFFER_TOO_SMALL
)
1260 RtlFreeHeap(GetProcessHeap(), 0, pInfo
);
1261 pInfo
= RtlAllocateHeap(GetProcessHeap(), 0, buflen
);
1262 status
= NtQueryValueKey(handle
, &Value
,
1263 KeyValueFullInformation
, pInfo
, buflen
, &len
);
1265 if (status
!= STATUS_SUCCESS
)
1267 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
)
1269 ret
= STATUS_OBJECT_NAME_NOT_FOUND
;
1272 status
= RTL_ReportRegistryValue(NULL
, QueryTable
, Context
, Environment
);
1273 if(status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
1281 status
= RTL_ReportRegistryValue(pInfo
, QueryTable
, Context
, Environment
);
1282 if(status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
1287 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_DELETE
)
1288 NtDeleteValueKey(handle
, &Value
);
1294 RtlFreeHeap(GetProcessHeap(), 0, pInfo
);
1295 if (handle
!= topkey
)
1301 /*************************************************************************
1302 * RtlCheckRegistryKey [NTDLL.@]
1304 * Query multiple registry values with a signle call.
1307 * RelativeTo [I] Registry path that Path refers to
1308 * Path [I] Path to key
1311 * STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1313 NTSTATUS WINAPI
RtlCheckRegistryKey(IN ULONG RelativeTo
, IN PWSTR Path
)
1318 TRACE("(%d, %s)\n", RelativeTo
, debugstr_w(Path
));
1320 if((!RelativeTo
) && Path
== NULL
)
1321 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1322 if(RelativeTo
& RTL_REGISTRY_HANDLE
)
1323 return STATUS_SUCCESS
;
1325 status
= RTL_GetKeyHandle(RelativeTo
, Path
, &handle
);
1326 if (handle
) NtClose(handle
);
1327 if (status
== STATUS_INVALID_HANDLE
) status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1331 /*************************************************************************
1332 * RtlDeleteRegistryValue [NTDLL.@]
1334 * Query multiple registry values with a signle call.
1337 * RelativeTo [I] Registry path that Path refers to
1338 * Path [I] Path to key
1339 * ValueName [I] Name of the value to delete
1342 * STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1344 NTSTATUS WINAPI
RtlDeleteRegistryValue(IN ULONG RelativeTo
, IN PCWSTR Path
, IN PCWSTR ValueName
)
1348 UNICODE_STRING Value
;
1350 TRACE("(%d, %s, %s)\n", RelativeTo
, debugstr_w(Path
), debugstr_w(ValueName
));
1352 RtlInitUnicodeString(&Value
, ValueName
);
1353 if(RelativeTo
== RTL_REGISTRY_HANDLE
)
1355 return NtDeleteValueKey((HANDLE
)Path
, &Value
);
1357 status
= RTL_GetKeyHandle(RelativeTo
, Path
, &handle
);
1358 if (status
) return status
;
1359 status
= NtDeleteValueKey(handle
, &Value
);
1364 /*************************************************************************
1365 * RtlWriteRegistryValue [NTDLL.@]
1367 * Sets the registry value with provided data.
1370 * RelativeTo [I] Registry path that path parameter refers to
1371 * path [I] Path to the key (or handle - see RTL_GetKeyHandle)
1372 * name [I] Name of the registry value to set
1373 * type [I] Type of the registry key to set
1374 * data [I] Pointer to the user data to be set
1375 * length [I] Length of the user data pointed by data
1378 * STATUS_SUCCESS if the specified key is successfully set,
1379 * or an NTSTATUS error code.
1381 NTSTATUS WINAPI
RtlWriteRegistryValue( ULONG RelativeTo
, PCWSTR path
, PCWSTR name
,
1382 ULONG type
, PVOID data
, ULONG length
)
1388 TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo
, debugstr_w(path
), debugstr_w(name
),
1389 type
, data
, length
);
1391 RtlInitUnicodeString( &str
, name
);
1393 if (RelativeTo
== RTL_REGISTRY_HANDLE
)
1394 return NtSetValueKey( (HANDLE
)path
, &str
, 0, type
, data
, length
);
1396 status
= RTL_GetKeyHandle( RelativeTo
, path
, &hkey
);
1397 if (status
!= STATUS_SUCCESS
) return status
;
1399 status
= NtSetValueKey( hkey
, &str
, 0, type
, data
, length
);