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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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"
36 #include "wine/library.h"
37 #include "ntdll_misc.h"
38 #include "wine/debug.h"
39 #include "wine/unicode.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
43 /* maximum length of a key/value name in bytes (without terminating null) */
44 #define MAX_NAME_LENGTH ((MAX_PATH-1) * sizeof(WCHAR))
46 /******************************************************************************
47 * NtCreateKey [NTDLL.@]
48 * ZwCreateKey [NTDLL.@]
50 NTSTATUS WINAPI
NtCreateKey( PHANDLE retkey
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
51 ULONG TitleIndex
, const UNICODE_STRING
*class, ULONG options
,
56 TRACE( "(%p,%s,%s,%lx,%lx,%p)\n", attr
->RootDirectory
, debugstr_us(attr
->ObjectName
),
57 debugstr_us(class), options
, access
, retkey
);
59 if (attr
->ObjectName
->Length
> MAX_NAME_LENGTH
) return STATUS_BUFFER_OVERFLOW
;
60 if (!retkey
) return STATUS_INVALID_PARAMETER
;
62 SERVER_START_REQ( create_key
)
64 req
->parent
= attr
->RootDirectory
;
66 req
->options
= options
;
68 req
->namelen
= attr
->ObjectName
->Length
;
69 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
70 if (class) wine_server_add_data( req
, class->Buffer
, class->Length
);
71 if (!(ret
= wine_server_call( req
)))
73 *retkey
= reply
->hkey
;
74 if (dispos
) *dispos
= reply
->created
? REG_CREATED_NEW_KEY
: REG_OPENED_EXISTING_KEY
;
78 TRACE("<- %p\n", *retkey
);
82 /******************************************************************************
83 * RtlpNtCreateKey [NTDLL.@]
87 NTSTATUS WINAPI
RtlpNtCreateKey( PHANDLE retkey
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
88 ULONG TitleIndex
, const UNICODE_STRING
*class, ULONG options
,
95 memcpy( &oa
, attr
, sizeof oa
);
96 oa
.Attributes
&= ~(OBJ_PERMANENT
|OBJ_EXCLUSIVE
);
100 return NtCreateKey(retkey
, access
, attr
, 0, NULL
, 0, dispos
);
103 /******************************************************************************
104 * NtOpenKey [NTDLL.@]
105 * ZwOpenKey [NTDLL.@]
107 * OUT HANDLE retkey (returns 0 when failure)
108 * IN ACCESS_MASK access
109 * IN POBJECT_ATTRIBUTES attr
111 NTSTATUS WINAPI
NtOpenKey( PHANDLE retkey
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
114 DWORD len
= attr
->ObjectName
->Length
;
116 TRACE( "(%p,%s,%lx,%p)\n", attr
->RootDirectory
,
117 debugstr_us(attr
->ObjectName
), access
, retkey
);
119 if (len
> MAX_NAME_LENGTH
) return STATUS_BUFFER_OVERFLOW
;
120 if (!retkey
) return STATUS_INVALID_PARAMETER
;
122 SERVER_START_REQ( open_key
)
124 req
->parent
= attr
->RootDirectory
;
125 req
->access
= access
;
126 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
127 ret
= wine_server_call( req
);
128 *retkey
= reply
->hkey
;
131 TRACE("<- %p\n", *retkey
);
135 /******************************************************************************
136 * RtlpNtOpenKey [NTDLL.@]
140 NTSTATUS WINAPI
RtlpNtOpenKey( PHANDLE retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
143 attr
->Attributes
&= ~(OBJ_PERMANENT
|OBJ_EXCLUSIVE
);
144 return NtOpenKey(retkey
, access
, attr
);
147 /******************************************************************************
148 * NtDeleteKey [NTDLL.@]
149 * ZwDeleteKey [NTDLL.@]
151 NTSTATUS WINAPI
NtDeleteKey( HANDLE hkey
)
155 TRACE( "(%p)\n", hkey
);
157 SERVER_START_REQ( delete_key
)
160 ret
= wine_server_call( req
);
166 /******************************************************************************
167 * RtlpNtMakeTemporaryKey [NTDLL.@]
171 NTSTATUS WINAPI
RtlpNtMakeTemporaryKey( HANDLE hkey
)
173 return NtDeleteKey(hkey
);
176 /******************************************************************************
177 * NtDeleteValueKey [NTDLL.@]
178 * ZwDeleteValueKey [NTDLL.@]
180 NTSTATUS WINAPI
NtDeleteValueKey( HANDLE hkey
, const UNICODE_STRING
*name
)
184 TRACE( "(%p,%s)\n", hkey
, debugstr_us(name
) );
185 if (name
->Length
> MAX_NAME_LENGTH
) return STATUS_BUFFER_OVERFLOW
;
187 SERVER_START_REQ( delete_key_value
)
190 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
191 ret
= wine_server_call( req
);
198 /******************************************************************************
201 * Implementation of NtQueryKey and NtEnumerateKey
203 static NTSTATUS
enumerate_key( HANDLE handle
, int index
, KEY_INFORMATION_CLASS info_class
,
204 void *info
, DWORD length
, DWORD
*result_len
)
213 case KeyBasicInformation
: data_ptr
= ((KEY_BASIC_INFORMATION
*)info
)->Name
; break;
214 case KeyFullInformation
: data_ptr
= ((KEY_FULL_INFORMATION
*)info
)->Class
; break;
215 case KeyNodeInformation
: data_ptr
= ((KEY_NODE_INFORMATION
*)info
)->Name
; break;
217 FIXME( "Information class %d not implemented\n", info_class
);
218 return STATUS_INVALID_PARAMETER
;
220 fixed_size
= (char *)data_ptr
- (char *)info
;
222 SERVER_START_REQ( enum_key
)
226 req
->info_class
= info_class
;
227 if (length
> fixed_size
) wine_server_set_reply( req
, data_ptr
, length
- fixed_size
);
228 if (!(ret
= wine_server_call( req
)))
232 RtlSecondsSince1970ToTime( reply
->modif
, &modif
);
236 case KeyBasicInformation
:
238 KEY_BASIC_INFORMATION keyinfo
;
239 fixed_size
= (char *)keyinfo
.Name
- (char *)&keyinfo
;
240 keyinfo
.LastWriteTime
= modif
;
241 keyinfo
.TitleIndex
= 0;
242 keyinfo
.NameLength
= reply
->namelen
;
243 memcpy( info
, &keyinfo
, min( length
, fixed_size
) );
246 case KeyFullInformation
:
248 KEY_FULL_INFORMATION keyinfo
;
249 fixed_size
= (char *)keyinfo
.Class
- (char *)&keyinfo
;
250 keyinfo
.LastWriteTime
= modif
;
251 keyinfo
.TitleIndex
= 0;
252 keyinfo
.ClassLength
= wine_server_reply_size(reply
);
253 keyinfo
.ClassOffset
= keyinfo
.ClassLength
? fixed_size
: -1;
254 keyinfo
.SubKeys
= reply
->subkeys
;
255 keyinfo
.MaxNameLen
= reply
->max_subkey
;
256 keyinfo
.MaxClassLen
= reply
->max_class
;
257 keyinfo
.Values
= reply
->values
;
258 keyinfo
.MaxValueNameLen
= reply
->max_value
;
259 keyinfo
.MaxValueDataLen
= reply
->max_data
;
260 memcpy( info
, &keyinfo
, min( length
, fixed_size
) );
263 case KeyNodeInformation
:
265 KEY_NODE_INFORMATION keyinfo
;
266 fixed_size
= (char *)keyinfo
.Name
- (char *)&keyinfo
;
267 keyinfo
.LastWriteTime
= modif
;
268 keyinfo
.TitleIndex
= 0;
269 keyinfo
.ClassLength
= max( 0, wine_server_reply_size(reply
) - reply
->namelen
);
270 keyinfo
.ClassOffset
= keyinfo
.ClassLength
? fixed_size
+ reply
->namelen
: -1;
271 keyinfo
.NameLength
= reply
->namelen
;
272 memcpy( info
, &keyinfo
, min( length
, fixed_size
) );
276 *result_len
= fixed_size
+ reply
->total
;
277 if (length
< *result_len
) ret
= STATUS_BUFFER_OVERFLOW
;
286 /******************************************************************************
287 * NtEnumerateKey [NTDLL.@]
288 * ZwEnumerateKey [NTDLL.@]
291 * the name copied into the buffer is NOT 0-terminated
293 NTSTATUS WINAPI
NtEnumerateKey( HANDLE handle
, ULONG index
, KEY_INFORMATION_CLASS info_class
,
294 void *info
, DWORD length
, DWORD
*result_len
)
296 /* -1 means query key, so avoid it here */
297 if (index
== (ULONG
)-1) return STATUS_NO_MORE_ENTRIES
;
298 return enumerate_key( handle
, index
, info_class
, info
, length
, result_len
);
302 /******************************************************************************
303 * RtlpNtEnumerateSubKey [NTDLL.@]
306 NTSTATUS WINAPI
RtlpNtEnumerateSubKey( HANDLE handle
, UNICODE_STRING
*out
, ULONG index
)
308 KEY_BASIC_INFORMATION
*info
;
309 DWORD dwLen
, dwResultLen
;
314 dwLen
= out
->Length
+ sizeof(KEY_BASIC_INFORMATION
);
315 info
= (KEY_BASIC_INFORMATION
*)RtlAllocateHeap( GetProcessHeap(), 0, dwLen
);
317 return STATUS_NO_MEMORY
;
325 ret
= NtEnumerateKey( handle
, index
, KeyBasicInformation
, info
, dwLen
, &dwResultLen
);
326 dwResultLen
-= sizeof(KEY_BASIC_INFORMATION
);
328 if (ret
== STATUS_BUFFER_OVERFLOW
)
329 out
->Length
= dwResultLen
;
332 if (out
->Length
< info
->NameLength
)
334 out
->Length
= dwResultLen
;
335 ret
= STATUS_BUFFER_OVERFLOW
;
339 out
->Length
= info
->NameLength
;
340 memcpy(out
->Buffer
, info
->Name
, info
->NameLength
);
345 RtlFreeHeap( GetProcessHeap(), 0, info
);
349 /******************************************************************************
350 * NtQueryKey [NTDLL.@]
351 * ZwQueryKey [NTDLL.@]
353 NTSTATUS WINAPI
NtQueryKey( HANDLE handle
, KEY_INFORMATION_CLASS info_class
,
354 void *info
, DWORD length
, DWORD
*result_len
)
356 return enumerate_key( handle
, -1, info_class
, info
, length
, result_len
);
360 /* fill the key value info structure for a specific info class */
361 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class
, void *info
,
362 DWORD length
, int type
, int name_len
, int data_len
)
366 case KeyValueBasicInformation
:
368 KEY_VALUE_BASIC_INFORMATION keyinfo
;
369 keyinfo
.TitleIndex
= 0;
371 keyinfo
.NameLength
= name_len
;
372 length
= min( length
, (char *)keyinfo
.Name
- (char *)&keyinfo
);
373 memcpy( info
, &keyinfo
, length
);
376 case KeyValueFullInformation
:
378 KEY_VALUE_FULL_INFORMATION keyinfo
;
379 keyinfo
.TitleIndex
= 0;
381 keyinfo
.DataOffset
= (char *)keyinfo
.Name
- (char *)&keyinfo
+ name_len
;
382 keyinfo
.DataLength
= data_len
;
383 keyinfo
.NameLength
= name_len
;
384 length
= min( length
, (char *)keyinfo
.Name
- (char *)&keyinfo
);
385 memcpy( info
, &keyinfo
, length
);
388 case KeyValuePartialInformation
:
390 KEY_VALUE_PARTIAL_INFORMATION keyinfo
;
391 keyinfo
.TitleIndex
= 0;
393 keyinfo
.DataLength
= data_len
;
394 length
= min( length
, (char *)keyinfo
.Data
- (char *)&keyinfo
);
395 memcpy( info
, &keyinfo
, length
);
404 /******************************************************************************
405 * NtEnumerateValueKey [NTDLL.@]
406 * ZwEnumerateValueKey [NTDLL.@]
408 NTSTATUS WINAPI
NtEnumerateValueKey( HANDLE handle
, ULONG index
,
409 KEY_VALUE_INFORMATION_CLASS info_class
,
410 void *info
, DWORD length
, DWORD
*result_len
)
416 TRACE( "(%p,%lu,%d,%p,%ld)\n", handle
, index
, info_class
, info
, length
);
418 /* compute the length we want to retrieve */
421 case KeyValueBasicInformation
: ptr
= ((KEY_VALUE_BASIC_INFORMATION
*)info
)->Name
; break;
422 case KeyValueFullInformation
: ptr
= ((KEY_VALUE_FULL_INFORMATION
*)info
)->Name
; break;
423 case KeyValuePartialInformation
: ptr
= ((KEY_VALUE_PARTIAL_INFORMATION
*)info
)->Data
; break;
425 FIXME( "Information class %d not implemented\n", info_class
);
426 return STATUS_INVALID_PARAMETER
;
428 fixed_size
= (char *)ptr
- (char *)info
;
430 SERVER_START_REQ( enum_key_value
)
434 req
->info_class
= info_class
;
435 if (length
> fixed_size
) wine_server_set_reply( req
, ptr
, length
- fixed_size
);
436 if (!(ret
= wine_server_call( req
)))
438 copy_key_value_info( info_class
, info
, length
, reply
->type
, reply
->namelen
,
439 wine_server_reply_size(reply
) - reply
->namelen
);
440 *result_len
= fixed_size
+ reply
->total
;
441 if (length
< *result_len
) ret
= STATUS_BUFFER_OVERFLOW
;
449 /******************************************************************************
450 * NtQueryValueKey [NTDLL.@]
451 * ZwQueryValueKey [NTDLL.@]
454 * the name in the KeyValueInformation is never set
456 NTSTATUS WINAPI
NtQueryValueKey( HANDLE handle
, const UNICODE_STRING
*name
,
457 KEY_VALUE_INFORMATION_CLASS info_class
,
458 void *info
, DWORD length
, DWORD
*result_len
)
462 unsigned int fixed_size
= 0;
464 TRACE( "(%p,%s,%d,%p,%ld)\n", handle
, debugstr_us(name
), info_class
, info
, length
);
466 if (name
->Length
> MAX_NAME_LENGTH
) return STATUS_BUFFER_OVERFLOW
;
468 /* compute the length we want to retrieve */
471 case KeyValueBasicInformation
:
472 fixed_size
= (char *)((KEY_VALUE_BASIC_INFORMATION
*)info
)->Name
- (char *)info
;
475 case KeyValueFullInformation
:
476 data_ptr
= (UCHAR
*)((KEY_VALUE_FULL_INFORMATION
*)info
)->Name
;
477 fixed_size
= (char *)data_ptr
- (char *)info
;
479 case KeyValuePartialInformation
:
480 data_ptr
= ((KEY_VALUE_PARTIAL_INFORMATION
*)info
)->Data
;
481 fixed_size
= (char *)data_ptr
- (char *)info
;
484 FIXME( "Information class %d not implemented\n", info_class
);
485 return STATUS_INVALID_PARAMETER
;
488 SERVER_START_REQ( get_key_value
)
491 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
492 if (length
> fixed_size
) wine_server_set_reply( req
, data_ptr
, length
- fixed_size
);
493 if (!(ret
= wine_server_call( req
)))
495 copy_key_value_info( info_class
, info
, length
, reply
->type
,
496 0, wine_server_reply_size(reply
) );
497 *result_len
= fixed_size
+ reply
->total
;
498 if (length
< *result_len
) ret
= STATUS_BUFFER_OVERFLOW
;
505 /******************************************************************************
506 * RtlpNtQueryValueKey [NTDLL.@]
509 NTSTATUS WINAPI
RtlpNtQueryValueKey( HANDLE handle
, ULONG
*result_type
, PBYTE dest
,
512 KEY_VALUE_PARTIAL_INFORMATION
*info
;
516 DWORD dwLen
= sizeof (KEY_VALUE_PARTIAL_INFORMATION
) + result_len
? *result_len
: 0;
518 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)RtlAllocateHeap( GetProcessHeap(), 0, dwLen
);
520 return STATUS_NO_MEMORY
;
523 ret
= NtQueryValueKey( handle
, &name
, KeyValuePartialInformation
, info
, dwLen
, &dwResultLen
);
525 if (!ret
|| ret
== STATUS_BUFFER_OVERFLOW
)
528 *result_len
= info
->DataLength
;
531 *result_type
= info
->Type
;
533 if (ret
!= STATUS_BUFFER_OVERFLOW
)
534 memcpy( dest
, info
->Data
, info
->DataLength
);
537 RtlFreeHeap( GetProcessHeap(), 0, info
);
541 /******************************************************************************
542 * NtFlushKey [NTDLL.@]
543 * ZwFlushKey [NTDLL.@]
545 NTSTATUS WINAPI
NtFlushKey(HANDLE key
)
549 TRACE("key=%p\n", key
);
551 SERVER_START_REQ( flush_key
)
554 ret
= wine_server_call( req
);
561 /******************************************************************************
562 * NtLoadKey [NTDLL.@]
563 * ZwLoadKey [NTDLL.@]
565 NTSTATUS WINAPI
NtLoadKey( const OBJECT_ATTRIBUTES
*attr
, OBJECT_ATTRIBUTES
*file
)
571 TRACE("(%p,%p)\n", attr
, file
);
573 ret
= NtCreateFile(&hive
, GENERIC_READ
, file
, &io
, NULL
, FILE_ATTRIBUTE_NORMAL
, 0,
574 OPEN_EXISTING
, 0, NULL
, 0);
577 SERVER_START_REQ( load_registry
)
579 req
->hkey
= attr
->RootDirectory
;
581 wine_server_add_data(req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
582 ret
= wine_server_call( req
);
591 /******************************************************************************
592 * NtNotifyChangeKey [NTDLL.@]
593 * ZwNotifyChangeKey [NTDLL.@]
595 NTSTATUS WINAPI
NtNotifyChangeKey(
598 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
599 IN PVOID ApcContext OPTIONAL
,
600 OUT PIO_STATUS_BLOCK IoStatusBlock
,
601 IN ULONG CompletionFilter
,
602 IN BOOLEAN Asynchronous
,
603 OUT PVOID ChangeBuffer
,
605 IN BOOLEAN WatchSubtree
)
609 TRACE("(%p,%p,%p,%p,%p,0x%08lx, 0x%08x,%p,0x%08lx,0x%08x)\n",
610 KeyHandle
, Event
, ApcRoutine
, ApcContext
, IoStatusBlock
, CompletionFilter
,
611 Asynchronous
, ChangeBuffer
, Length
, WatchSubtree
);
613 if (ApcRoutine
|| ApcContext
|| ChangeBuffer
|| Length
)
614 FIXME("Unimplemented optional parameter\n");
618 OBJECT_ATTRIBUTES attr
;
619 InitializeObjectAttributes( &attr
, NULL
, 0, NULL
, NULL
);
620 ret
= NtCreateEvent( &Event
, EVENT_ALL_ACCESS
, &attr
, FALSE
, FALSE
);
621 if (ret
!= STATUS_SUCCESS
)
625 SERVER_START_REQ( set_registry_notification
)
627 req
->hkey
= KeyHandle
;
629 req
->subtree
= WatchSubtree
;
630 req
->filter
= CompletionFilter
;
631 ret
= wine_server_call( req
);
637 if (ret
== STATUS_SUCCESS
)
638 NtWaitForSingleObject( Event
, FALSE
, NULL
);
642 return STATUS_SUCCESS
;
645 /******************************************************************************
646 * NtQueryMultipleValueKey [NTDLL]
647 * ZwQueryMultipleValueKey
650 NTSTATUS WINAPI
NtQueryMultipleValueKey(
652 PKEY_MULTIPLE_VALUE_INFORMATION ListOfValuesToQuery
,
654 PVOID MultipleValueInformation
,
658 FIXME("(%p,%p,0x%08lx,%p,0x%08lx,%p) stub!\n",
659 KeyHandle
, ListOfValuesToQuery
, NumberOfItems
, MultipleValueInformation
,
660 Length
,ReturnLength
);
661 return STATUS_SUCCESS
;
664 /******************************************************************************
665 * NtReplaceKey [NTDLL.@]
666 * ZwReplaceKey [NTDLL.@]
668 NTSTATUS WINAPI
NtReplaceKey(
669 IN POBJECT_ATTRIBUTES ObjectAttributes
,
671 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
673 FIXME("(%p),stub!\n", Key
);
674 dump_ObjectAttributes(ObjectAttributes
);
675 dump_ObjectAttributes(ReplacedObjectAttributes
);
676 return STATUS_SUCCESS
;
678 /******************************************************************************
679 * NtRestoreKey [NTDLL.@]
680 * ZwRestoreKey [NTDLL.@]
682 NTSTATUS WINAPI
NtRestoreKey(
687 FIXME("(%p,%p,0x%08lx) stub\n",
688 KeyHandle
, FileHandle
, RestoreFlags
);
689 return STATUS_SUCCESS
;
691 /******************************************************************************
692 * NtSaveKey [NTDLL.@]
693 * ZwSaveKey [NTDLL.@]
695 NTSTATUS WINAPI
NtSaveKey(IN HANDLE KeyHandle
, IN HANDLE FileHandle
)
699 TRACE("(%p,%p)\n", KeyHandle
, FileHandle
);
701 SERVER_START_REQ( save_registry
)
703 req
->hkey
= KeyHandle
;
704 req
->file
= FileHandle
;
705 ret
= wine_server_call( req
);
711 /******************************************************************************
712 * NtSetInformationKey [NTDLL.@]
713 * ZwSetInformationKey [NTDLL.@]
715 NTSTATUS WINAPI
NtSetInformationKey(
717 IN
const int KeyInformationClass
,
718 IN PVOID KeyInformation
,
719 IN ULONG KeyInformationLength
)
721 FIXME("(%p,0x%08x,%p,0x%08lx) stub\n",
722 KeyHandle
, KeyInformationClass
, KeyInformation
, KeyInformationLength
);
723 return STATUS_SUCCESS
;
727 /******************************************************************************
728 * NtSetValueKey [NTDLL.@]
729 * ZwSetValueKey [NTDLL.@]
732 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
733 * NT does definitely care (aj)
735 NTSTATUS WINAPI
NtSetValueKey( HANDLE hkey
, const UNICODE_STRING
*name
, ULONG TitleIndex
,
736 ULONG type
, const void *data
, ULONG count
)
740 TRACE( "(%p,%s,%ld,%p,%ld)\n", hkey
, debugstr_us(name
), type
, data
, count
);
742 if (name
->Length
> MAX_NAME_LENGTH
) return STATUS_BUFFER_OVERFLOW
;
744 SERVER_START_REQ( set_key_value
)
748 req
->namelen
= name
->Length
;
749 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
750 wine_server_add_data( req
, data
, count
);
751 ret
= wine_server_call( req
);
757 /******************************************************************************
758 * RtlpNtSetValueKey [NTDLL.@]
761 NTSTATUS WINAPI
RtlpNtSetValueKey( HANDLE hkey
, ULONG type
, const void *data
,
767 return NtSetValueKey( hkey
, &name
, 0, type
, data
, count
);
770 /******************************************************************************
771 * NtUnloadKey [NTDLL.@]
772 * ZwUnloadKey [NTDLL.@]
774 NTSTATUS WINAPI
NtUnloadKey(IN HANDLE KeyHandle
)
778 TRACE("(%p)\n", KeyHandle
);
780 SERVER_START_REQ( unload_registry
)
782 req
->hkey
= KeyHandle
;
783 ret
= wine_server_call(req
);
790 /******************************************************************************
791 * RtlFormatCurrentUserKeyPath [NTDLL.@]
794 NTSTATUS WINAPI
RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath
)
796 static const WCHAR pathW
[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
800 status
= NtOpenThreadToken(GetCurrentThread(), TOKEN_READ
, TRUE
, &token
);
801 if (status
== STATUS_NO_TOKEN
)
802 status
= NtOpenProcessToken(GetCurrentProcess(), TOKEN_READ
, &token
);
803 if (status
== STATUS_SUCCESS
)
805 char buffer
[sizeof(TOKEN_USER
) + sizeof(SID
) + sizeof(DWORD
)*SID_MAX_SUB_AUTHORITIES
];
806 DWORD len
= sizeof(buffer
);
808 status
= NtQueryInformationToken(token
, TokenUser
, buffer
, len
, &len
);
809 if (status
== STATUS_SUCCESS
)
811 KeyPath
->MaximumLength
= 0;
812 status
= RtlConvertSidToUnicodeString(KeyPath
, ((TOKEN_USER
*)buffer
)->User
.Sid
, FALSE
);
813 if (status
== STATUS_BUFFER_OVERFLOW
)
815 PWCHAR buf
= RtlAllocateHeap(GetProcessHeap(), 0,
816 sizeof(pathW
) + KeyPath
->Length
+ sizeof(WCHAR
));
819 memcpy(buf
, pathW
, sizeof(pathW
));
820 KeyPath
->MaximumLength
= KeyPath
->Length
+ sizeof(WCHAR
);
821 KeyPath
->Buffer
= (PWCHAR
)((LPBYTE
)buf
+ sizeof(pathW
));
822 status
= RtlConvertSidToUnicodeString(KeyPath
,
823 ((TOKEN_USER
*)buffer
)->User
.Sid
, FALSE
);
824 KeyPath
->Buffer
= (PWCHAR
)buf
;
825 KeyPath
->Length
+= sizeof(pathW
);
826 KeyPath
->MaximumLength
+= sizeof(pathW
);
829 status
= STATUS_NO_MEMORY
;
837 /******************************************************************************
838 * RtlOpenCurrentUser [NTDLL.@]
840 * if we return just HKEY_CURRENT_USER the advapi tries to find a remote
841 * registry (odd handle) and fails
844 DWORD WINAPI
RtlOpenCurrentUser(
845 IN ACCESS_MASK DesiredAccess
, /* [in] */
846 OUT PHANDLE KeyHandle
) /* [out] handle of HKEY_CURRENT_USER */
848 OBJECT_ATTRIBUTES ObjectAttributes
;
849 UNICODE_STRING ObjectName
;
852 TRACE("(0x%08lx, %p)\n",DesiredAccess
, KeyHandle
);
854 RtlFormatCurrentUserKeyPath(&ObjectName
);
855 InitializeObjectAttributes(&ObjectAttributes
,&ObjectName
,OBJ_CASE_INSENSITIVE
,0, NULL
);
856 ret
= NtCreateKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
857 RtlFreeUnicodeString(&ObjectName
);
862 static NTSTATUS
RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo
,
863 PRTL_QUERY_REGISTRY_TABLE pQuery
, PVOID pContext
, PVOID pEnvironment
)
866 UNICODE_STRING src
, dst
;
871 NTSTATUS status
= STATUS_SUCCESS
;
878 if (pQuery
->Flags
& RTL_QUERY_REGISTRY_DIRECT
)
879 return STATUS_INVALID_PARAMETER
;
882 status
= pQuery
->QueryRoutine(pQuery
->Name
, pQuery
->DefaultType
, pQuery
->DefaultData
,
883 pQuery
->DefaultLength
, pContext
, pQuery
->EntryContext
);
887 len
= pInfo
->DataLength
;
889 if (pQuery
->Flags
& RTL_QUERY_REGISTRY_DIRECT
)
891 str
= (PUNICODE_STRING
)pQuery
->EntryContext
;
896 if (!(pQuery
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
))
898 RtlInitUnicodeString(&src
, (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
));
900 dst
.MaximumLength
= 0;
901 RtlExpandEnvironmentStrings_U(pEnvironment
, &src
, &dst
, &res
);
903 dst
.MaximumLength
= res
;
904 dst
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, res
* sizeof(WCHAR
));
905 RtlExpandEnvironmentStrings_U(pEnvironment
, &src
, &dst
, &res
);
906 status
= pQuery
->QueryRoutine(pQuery
->Name
, pInfo
->Type
, dst
.Buffer
,
907 dst
.Length
, pContext
, pQuery
->EntryContext
);
908 RtlFreeHeap(GetProcessHeap(), 0, dst
.Buffer
);
913 if (str
->Buffer
== NULL
)
914 RtlCreateUnicodeString(str
, (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
));
916 RtlAppendUnicodeToString(str
, (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
));
920 if (!(pQuery
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
))
921 return STATUS_INVALID_PARAMETER
;
923 if (str
->Buffer
== NULL
)
925 str
->Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
926 str
->MaximumLength
= len
;
928 len
= min(len
, str
->MaximumLength
);
929 memcpy(str
->Buffer
, ((CHAR
*)pInfo
) + pInfo
->DataOffset
, len
);
934 bin
= (LONG
*)pQuery
->EntryContext
;
935 if (pInfo
->DataLength
<= sizeof(ULONG
))
936 memcpy(bin
, ((CHAR
*)pInfo
) + pInfo
->DataOffset
,
940 if (bin
[0] <= sizeof(ULONG
))
942 memcpy(&bin
[1], ((CHAR
*)pInfo
) + pInfo
->DataOffset
,
943 min(-bin
[0], pInfo
->DataLength
));
947 len
= min(bin
[0], pInfo
->DataLength
);
949 bin
[2] = pInfo
->Type
;
950 memcpy(&bin
[3], ((CHAR
*)pInfo
) + pInfo
->DataOffset
, len
);
958 if((pQuery
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
) ||
959 (pInfo
->Type
!= REG_EXPAND_SZ
&& pInfo
->Type
!= REG_MULTI_SZ
))
961 status
= pQuery
->QueryRoutine(pInfo
->Name
, pInfo
->Type
,
962 ((CHAR
*)pInfo
) + pInfo
->DataOffset
, pInfo
->DataLength
,
963 pContext
, pQuery
->EntryContext
);
965 else if (pInfo
->Type
== REG_EXPAND_SZ
)
967 RtlInitUnicodeString(&src
, (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
));
969 dst
.MaximumLength
= 0;
970 RtlExpandEnvironmentStrings_U(pEnvironment
, &src
, &dst
, &res
);
972 dst
.MaximumLength
= res
;
973 dst
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, res
* sizeof(WCHAR
));
974 RtlExpandEnvironmentStrings_U(pEnvironment
, &src
, &dst
, &res
);
975 status
= pQuery
->QueryRoutine(pQuery
->Name
, pInfo
->Type
, dst
.Buffer
,
976 dst
.Length
, pContext
, pQuery
->EntryContext
);
977 RtlFreeHeap(GetProcessHeap(), 0, dst
.Buffer
);
979 else /* REG_MULTI_SZ */
981 if(pQuery
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
)
983 for (offset
= 0; offset
<= pInfo
->DataLength
; offset
+= len
+ sizeof(WCHAR
))
985 wstr
= (WCHAR
*)(((CHAR
*)pInfo
) + offset
);
986 len
= strlenW(wstr
) * sizeof(WCHAR
);
987 status
= pQuery
->QueryRoutine(pQuery
->Name
, pInfo
->Type
, wstr
, len
,
988 pContext
, pQuery
->EntryContext
);
989 if(status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
995 while(count
<=pInfo
->DataLength
)
997 String
= (WCHAR
*)(((CHAR
*)pInfo
) + pInfo
->DataOffset
)+count
;
998 count
+=strlenW(String
)+1;
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
);
1010 if(status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
1020 static NTSTATUS
RTL_GetKeyHandle(ULONG RelativeTo
, PCWSTR Path
, PHANDLE handle
)
1022 UNICODE_STRING KeyString
;
1023 OBJECT_ATTRIBUTES regkey
;
1028 static const WCHAR empty
[] = {0};
1029 static const WCHAR control
[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1030 '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t',' ','C','o','n','t','r','o','l','S','e','t','\\',
1031 'C','o','n','t','r','o','l','\\',0};
1033 static const WCHAR devicemap
[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1034 'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1036 static const WCHAR services
[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1037 'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1038 'S','e','r','v','i','c','e','s','\\',0};
1040 static const WCHAR user
[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1041 'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1043 static const WCHAR windows_nt
[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1044 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1045 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1047 switch (RelativeTo
& 0xff)
1049 case RTL_REGISTRY_ABSOLUTE
:
1053 case RTL_REGISTRY_CONTROL
:
1057 case RTL_REGISTRY_DEVICEMAP
:
1061 case RTL_REGISTRY_SERVICES
:
1065 case RTL_REGISTRY_USER
:
1069 case RTL_REGISTRY_WINDOWS_NT
:
1074 return STATUS_INVALID_PARAMETER
;
1077 len
= (strlenW(base
) + strlenW(Path
) + 1) * sizeof(WCHAR
);
1078 KeyString
.Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
1079 if (KeyString
.Buffer
== NULL
)
1080 return STATUS_NO_MEMORY
;
1082 strcpyW(KeyString
.Buffer
, base
);
1083 strcatW(KeyString
.Buffer
, Path
);
1084 KeyString
.Length
= len
- sizeof(WCHAR
);
1085 KeyString
.MaximumLength
= len
;
1086 InitializeObjectAttributes(®key
, &KeyString
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
1087 status
= NtOpenKey(handle
, KEY_ALL_ACCESS
, ®key
);
1088 RtlFreeHeap(GetProcessHeap(), 0, KeyString
.Buffer
);
1092 /*************************************************************************
1093 * RtlQueryRegistryValues [NTDLL.@]
1095 * Query multiple registry values with a signle call.
1098 * RelativeTo [I] Registry path that Path refers to
1099 * Path [I] Path to key
1100 * QueryTable [I] Table of key values to query
1101 * Context [I] Paremeter to pass to the application defined QueryRoutine function
1102 * Environment [I] Optional parameter to use when performing expantion
1105 * STATUS_SUCCESS or an appropriate NTSTATUS error code.
1107 NTSTATUS WINAPI
RtlQueryRegistryValues(IN ULONG RelativeTo
, IN PCWSTR Path
,
1108 IN PRTL_QUERY_REGISTRY_TABLE QueryTable
, IN PVOID Context
,
1109 IN PVOID Environment OPTIONAL
)
1111 UNICODE_STRING Value
;
1112 HANDLE handle
, topkey
;
1113 PKEY_VALUE_FULL_INFORMATION pInfo
= NULL
;
1114 ULONG len
, buflen
= 0;
1115 NTSTATUS status
=STATUS_SUCCESS
, ret
= STATUS_SUCCESS
;
1118 TRACE("(%ld, %s, %p, %p, %p)\n", RelativeTo
, debugstr_w(Path
), QueryTable
, Context
, Environment
);
1121 return STATUS_INVALID_PARAMETER
;
1123 /* get a valid handle */
1124 if (RelativeTo
& RTL_REGISTRY_HANDLE
)
1125 topkey
= handle
= (HANDLE
)Path
;
1128 status
= RTL_GetKeyHandle(RelativeTo
, Path
, &topkey
);
1131 if(status
!= STATUS_SUCCESS
)
1134 /* Process query table entries */
1135 for (; QueryTable
->QueryRoutine
!= NULL
|| QueryTable
->Name
!= NULL
; ++QueryTable
)
1137 if (QueryTable
->Flags
&
1138 (RTL_QUERY_REGISTRY_SUBKEY
| RTL_QUERY_REGISTRY_TOPKEY
))
1140 /* topkey must be kept open just in case we will reuse it later */
1141 if (handle
!= topkey
)
1144 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_SUBKEY
)
1147 status
= RTL_GetKeyHandle((ULONG
)QueryTable
->Name
, Path
, &handle
);
1148 if(status
!= STATUS_SUCCESS
)
1158 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_NOVALUE
)
1160 QueryTable
->QueryRoutine(QueryTable
->Name
, REG_NONE
, NULL
, 0,
1161 Context
, QueryTable
->EntryContext
);
1167 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
)
1169 ret
= STATUS_OBJECT_NAME_NOT_FOUND
;
1175 if (QueryTable
->Name
== NULL
)
1177 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_DIRECT
)
1179 ret
= STATUS_INVALID_PARAMETER
;
1183 /* Report all subkeys */
1186 status
= NtEnumerateValueKey(handle
, i
,
1187 KeyValueFullInformation
, pInfo
, buflen
, &len
);
1188 if (status
== STATUS_NO_MORE_ENTRIES
)
1190 if (status
== STATUS_BUFFER_OVERFLOW
||
1191 status
== STATUS_BUFFER_TOO_SMALL
)
1194 RtlFreeHeap(GetProcessHeap(), 0, pInfo
);
1195 pInfo
= (KEY_VALUE_FULL_INFORMATION
*)RtlAllocateHeap(
1196 GetProcessHeap(), 0, buflen
);
1197 NtEnumerateValueKey(handle
, i
, KeyValueFullInformation
,
1198 pInfo
, buflen
, &len
);
1201 status
= RTL_ReportRegistryValue(pInfo
, QueryTable
, Context
, Environment
);
1202 if(status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
1207 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_DELETE
)
1209 RtlInitUnicodeString(&Value
, pInfo
->Name
);
1210 NtDeleteValueKey(handle
, &Value
);
1214 if (i
== 0 && (QueryTable
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
))
1216 ret
= STATUS_OBJECT_NAME_NOT_FOUND
;
1222 RtlInitUnicodeString(&Value
, QueryTable
->Name
);
1223 status
= NtQueryValueKey(handle
, &Value
, KeyValueFullInformation
,
1224 pInfo
, buflen
, &len
);
1225 if (status
== STATUS_BUFFER_OVERFLOW
||
1226 status
== STATUS_BUFFER_TOO_SMALL
)
1229 RtlFreeHeap(GetProcessHeap(), 0, pInfo
);
1230 pInfo
= (KEY_VALUE_FULL_INFORMATION
*)RtlAllocateHeap(
1231 GetProcessHeap(), 0, buflen
);
1232 status
= NtQueryValueKey(handle
, &Value
,
1233 KeyValueFullInformation
, pInfo
, buflen
, &len
);
1235 if (status
!= STATUS_SUCCESS
)
1237 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
)
1239 ret
= STATUS_OBJECT_NAME_NOT_FOUND
;
1242 status
= RTL_ReportRegistryValue(NULL
, QueryTable
, Context
, Environment
);
1243 if(status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
1251 status
= RTL_ReportRegistryValue(pInfo
, QueryTable
, Context
, Environment
);
1252 if(status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
1257 if (QueryTable
->Flags
& RTL_QUERY_REGISTRY_DELETE
)
1258 NtDeleteValueKey(handle
, &Value
);
1264 RtlFreeHeap(GetProcessHeap(), 0, pInfo
);
1265 if (handle
!= topkey
)
1271 /*************************************************************************
1272 * RtlCheckRegistryKey [NTDLL.@]
1274 * Query multiple registry values with a signle call.
1277 * RelativeTo [I] Registry path that Path refers to
1278 * Path [I] Path to key
1281 * STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1283 NTSTATUS WINAPI
RtlCheckRegistryKey(IN ULONG RelativeTo
, IN PWSTR Path
)
1288 TRACE("(%ld, %s)\n", RelativeTo
, debugstr_w(Path
));
1290 if((!RelativeTo
) && Path
== NULL
)
1291 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1292 if(RelativeTo
& RTL_REGISTRY_HANDLE
)
1293 return STATUS_SUCCESS
;
1295 status
= RTL_GetKeyHandle(RelativeTo
, Path
, &handle
);
1296 if (handle
) NtClose(handle
);
1297 if (status
== STATUS_INVALID_HANDLE
) status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1301 /*************************************************************************
1302 * RtlDeleteRegistryValue [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
1309 * ValueName [I] Name of the value to delete
1312 * STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1314 NTSTATUS WINAPI
RtlDeleteRegistryValue(IN ULONG RelativeTo
, IN PCWSTR Path
, IN PCWSTR ValueName
)
1318 UNICODE_STRING Value
;
1320 TRACE("(%ld, %s, %s)\n", RelativeTo
, debugstr_w(Path
), debugstr_w(ValueName
));
1322 RtlInitUnicodeString(&Value
, ValueName
);
1323 if(RelativeTo
== RTL_REGISTRY_HANDLE
)
1325 return NtDeleteValueKey((HANDLE
)Path
, &Value
);
1327 status
= RTL_GetKeyHandle(RelativeTo
, Path
, &handle
);
1328 if (status
) return status
;
1329 status
= NtDeleteValueKey(handle
, &Value
);