ntdll: Added NtNotifyChangeMultipleKeys implementation.
[wine.git] / dlls / ntdll / reg.c
blob5248595214635f81d0bbe0697cb85726aa2a447f
1 /*
2 * Registry functions
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
22 * NOTES:
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
29 #include "config.h"
30 #include "wine/port.h"
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <string.h>
36 #include "ntstatus.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,
56 PULONG dispos )
58 NTSTATUS ret;
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 );
70 req->access = access;
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;
82 SERVER_END_REQ;
83 TRACE("<- %p\n", *retkey);
84 return ret;
87 /******************************************************************************
88 * RtlpNtCreateKey [NTDLL.@]
90 * See NtCreateKey.
92 NTSTATUS WINAPI RtlpNtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
93 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
94 PULONG dispos )
96 OBJECT_ATTRIBUTES oa;
98 if (attr)
100 oa = *attr;
101 oa.Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
102 attr = &oa;
105 return NtCreateKey(retkey, access, attr, 0, NULL, 0, dispos);
108 /******************************************************************************
109 * NtOpenKeyEx [NTDLL.@]
110 * ZwOpenKeyEx [NTDLL.@]
112 NTSTATUS WINAPI NtOpenKeyEx( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, ULONG options )
114 NTSTATUS ret;
115 DWORD len;
117 if (!retkey || !attr) return STATUS_ACCESS_VIOLATION;
118 if (attr->Length > sizeof(OBJECT_ATTRIBUTES)) return STATUS_INVALID_PARAMETER;
119 len = attr->ObjectName->Length;
120 TRACE( "(%p,%s,%x,%p)\n", attr->RootDirectory,
121 debugstr_us(attr->ObjectName), access, retkey );
122 if (options)
123 FIXME("options %x not implemented\n", options);
125 if (len > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
127 SERVER_START_REQ( open_key )
129 req->parent = wine_server_obj_handle( attr->RootDirectory );
130 req->access = access;
131 req->attributes = attr->Attributes;
132 wine_server_add_data( req, attr->ObjectName->Buffer, len );
133 ret = wine_server_call( req );
134 *retkey = wine_server_ptr_handle( reply->hkey );
136 SERVER_END_REQ;
137 TRACE("<- %p\n", *retkey);
138 return ret;
141 /******************************************************************************
142 * NtOpenKey [NTDLL.@]
143 * ZwOpenKey [NTDLL.@]
145 * OUT HANDLE retkey (returns 0 when failure)
146 * IN ACCESS_MASK access
147 * IN POBJECT_ATTRIBUTES attr
149 NTSTATUS WINAPI NtOpenKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
151 return NtOpenKeyEx( retkey, access, attr, 0 );
154 /******************************************************************************
155 * RtlpNtOpenKey [NTDLL.@]
157 * See NtOpenKey.
159 NTSTATUS WINAPI RtlpNtOpenKey( PHANDLE retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
161 if (attr)
162 attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
163 return NtOpenKey(retkey, access, attr);
166 /******************************************************************************
167 * NtDeleteKey [NTDLL.@]
168 * ZwDeleteKey [NTDLL.@]
170 NTSTATUS WINAPI NtDeleteKey( HANDLE hkey )
172 NTSTATUS ret;
174 TRACE( "(%p)\n", hkey );
176 SERVER_START_REQ( delete_key )
178 req->hkey = wine_server_obj_handle( hkey );
179 ret = wine_server_call( req );
181 SERVER_END_REQ;
182 return ret;
185 /******************************************************************************
186 * RtlpNtMakeTemporaryKey [NTDLL.@]
188 * See NtDeleteKey.
190 NTSTATUS WINAPI RtlpNtMakeTemporaryKey( HANDLE hkey )
192 return NtDeleteKey(hkey);
195 /******************************************************************************
196 * NtDeleteValueKey [NTDLL.@]
197 * ZwDeleteValueKey [NTDLL.@]
199 NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name )
201 NTSTATUS ret;
203 TRACE( "(%p,%s)\n", hkey, debugstr_us(name) );
204 if (name->Length > MAX_VALUE_LENGTH) return STATUS_OBJECT_NAME_NOT_FOUND;
206 SERVER_START_REQ( delete_key_value )
208 req->hkey = wine_server_obj_handle( hkey );
209 wine_server_add_data( req, name->Buffer, name->Length );
210 ret = wine_server_call( req );
212 SERVER_END_REQ;
213 return ret;
217 /******************************************************************************
218 * enumerate_key
220 * Implementation of NtQueryKey and NtEnumerateKey
222 static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS info_class,
223 void *info, DWORD length, DWORD *result_len )
226 NTSTATUS ret;
227 void *data_ptr;
228 size_t fixed_size;
230 switch(info_class)
232 case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break;
233 case KeyFullInformation: data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
234 case KeyNodeInformation: data_ptr = ((KEY_NODE_INFORMATION *)info)->Name; break;
235 case KeyNameInformation: data_ptr = ((KEY_NAME_INFORMATION *)info)->Name; break;
236 default:
237 FIXME( "Information class %d not implemented\n", info_class );
238 return STATUS_INVALID_PARAMETER;
240 fixed_size = (char *)data_ptr - (char *)info;
242 SERVER_START_REQ( enum_key )
244 req->hkey = wine_server_obj_handle( handle );
245 req->index = index;
246 req->info_class = info_class;
247 if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
248 if (!(ret = wine_server_call( req )))
250 switch(info_class)
252 case KeyBasicInformation:
254 KEY_BASIC_INFORMATION keyinfo;
255 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
256 keyinfo.LastWriteTime.QuadPart = reply->modif;
257 keyinfo.TitleIndex = 0;
258 keyinfo.NameLength = reply->namelen;
259 memcpy( info, &keyinfo, min( length, fixed_size ) );
261 break;
262 case KeyFullInformation:
264 KEY_FULL_INFORMATION keyinfo;
265 fixed_size = (char *)keyinfo.Class - (char *)&keyinfo;
266 keyinfo.LastWriteTime.QuadPart = reply->modif;
267 keyinfo.TitleIndex = 0;
268 keyinfo.ClassLength = wine_server_reply_size(reply);
269 keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
270 keyinfo.SubKeys = reply->subkeys;
271 keyinfo.MaxNameLen = reply->max_subkey;
272 keyinfo.MaxClassLen = reply->max_class;
273 keyinfo.Values = reply->values;
274 keyinfo.MaxValueNameLen = reply->max_value;
275 keyinfo.MaxValueDataLen = reply->max_data;
276 memcpy( info, &keyinfo, min( length, fixed_size ) );
278 break;
279 case KeyNodeInformation:
281 KEY_NODE_INFORMATION keyinfo;
282 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
283 keyinfo.LastWriteTime.QuadPart = reply->modif;
284 keyinfo.TitleIndex = 0;
285 if (reply->namelen < wine_server_reply_size(reply))
287 keyinfo.ClassLength = wine_server_reply_size(reply) - reply->namelen;
288 keyinfo.ClassOffset = fixed_size + reply->namelen;
290 else
292 keyinfo.ClassLength = 0;
293 keyinfo.ClassOffset = -1;
295 keyinfo.NameLength = reply->namelen;
296 memcpy( info, &keyinfo, min( length, fixed_size ) );
298 break;
299 case KeyNameInformation:
301 KEY_NAME_INFORMATION keyinfo;
302 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
303 keyinfo.NameLength = reply->namelen;
304 memcpy( info, &keyinfo, min( length, fixed_size ) );
306 break;
308 *result_len = fixed_size + reply->total;
309 if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
312 SERVER_END_REQ;
313 return ret;
318 /******************************************************************************
319 * NtEnumerateKey [NTDLL.@]
320 * ZwEnumerateKey [NTDLL.@]
322 * NOTES
323 * the name copied into the buffer is NOT 0-terminated
325 NTSTATUS WINAPI NtEnumerateKey( HANDLE handle, ULONG index, KEY_INFORMATION_CLASS info_class,
326 void *info, DWORD length, DWORD *result_len )
328 /* -1 means query key, so avoid it here */
329 if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
330 return enumerate_key( handle, index, info_class, info, length, result_len );
334 /******************************************************************************
335 * RtlpNtEnumerateSubKey [NTDLL.@]
338 NTSTATUS WINAPI RtlpNtEnumerateSubKey( HANDLE handle, UNICODE_STRING *out, ULONG index )
340 KEY_BASIC_INFORMATION *info;
341 DWORD dwLen, dwResultLen;
342 NTSTATUS ret;
344 if (out->Length)
346 dwLen = out->Length + sizeof(KEY_BASIC_INFORMATION);
347 info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
348 if (!info)
349 return STATUS_NO_MEMORY;
351 else
353 dwLen = 0;
354 info = NULL;
357 ret = NtEnumerateKey( handle, index, KeyBasicInformation, info, dwLen, &dwResultLen );
358 dwResultLen -= sizeof(KEY_BASIC_INFORMATION);
360 if (ret == STATUS_BUFFER_OVERFLOW)
361 out->Length = dwResultLen;
362 else if (!ret)
364 if (out->Length < info->NameLength)
366 out->Length = dwResultLen;
367 ret = STATUS_BUFFER_OVERFLOW;
369 else
371 out->Length = info->NameLength;
372 memcpy(out->Buffer, info->Name, info->NameLength);
376 RtlFreeHeap( GetProcessHeap(), 0, info );
377 return ret;
380 /******************************************************************************
381 * NtQueryKey [NTDLL.@]
382 * ZwQueryKey [NTDLL.@]
384 NTSTATUS WINAPI NtQueryKey( HANDLE handle, KEY_INFORMATION_CLASS info_class,
385 void *info, DWORD length, DWORD *result_len )
387 return enumerate_key( handle, -1, info_class, info, length, result_len );
391 /* fill the key value info structure for a specific info class */
392 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info,
393 DWORD length, int type, int name_len, int data_len )
395 switch(info_class)
397 case KeyValueBasicInformation:
399 KEY_VALUE_BASIC_INFORMATION keyinfo;
400 keyinfo.TitleIndex = 0;
401 keyinfo.Type = type;
402 keyinfo.NameLength = name_len;
403 length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
404 memcpy( info, &keyinfo, length );
405 break;
407 case KeyValueFullInformation:
409 KEY_VALUE_FULL_INFORMATION keyinfo;
410 keyinfo.TitleIndex = 0;
411 keyinfo.Type = type;
412 keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len;
413 keyinfo.DataLength = data_len;
414 keyinfo.NameLength = name_len;
415 length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
416 memcpy( info, &keyinfo, length );
417 break;
419 case KeyValuePartialInformation:
421 KEY_VALUE_PARTIAL_INFORMATION keyinfo;
422 keyinfo.TitleIndex = 0;
423 keyinfo.Type = type;
424 keyinfo.DataLength = data_len;
425 length = min( length, (char *)keyinfo.Data - (char *)&keyinfo );
426 memcpy( info, &keyinfo, length );
427 break;
429 default:
430 break;
435 /******************************************************************************
436 * NtEnumerateValueKey [NTDLL.@]
437 * ZwEnumerateValueKey [NTDLL.@]
439 NTSTATUS WINAPI NtEnumerateValueKey( HANDLE handle, ULONG index,
440 KEY_VALUE_INFORMATION_CLASS info_class,
441 void *info, DWORD length, DWORD *result_len )
443 NTSTATUS ret;
444 void *ptr;
445 size_t fixed_size;
447 TRACE( "(%p,%u,%d,%p,%d)\n", handle, index, info_class, info, length );
449 /* compute the length we want to retrieve */
450 switch(info_class)
452 case KeyValueBasicInformation: ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break;
453 case KeyValueFullInformation: ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break;
454 case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break;
455 default:
456 FIXME( "Information class %d not implemented\n", info_class );
457 return STATUS_INVALID_PARAMETER;
459 fixed_size = (char *)ptr - (char *)info;
461 SERVER_START_REQ( enum_key_value )
463 req->hkey = wine_server_obj_handle( handle );
464 req->index = index;
465 req->info_class = info_class;
466 if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size );
467 if (!(ret = wine_server_call( req )))
469 copy_key_value_info( info_class, info, length, reply->type, reply->namelen,
470 wine_server_reply_size(reply) - reply->namelen );
471 *result_len = fixed_size + reply->total;
472 if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
475 SERVER_END_REQ;
476 return ret;
480 /******************************************************************************
481 * NtQueryValueKey [NTDLL.@]
482 * ZwQueryValueKey [NTDLL.@]
484 * NOTES
485 * the name in the KeyValueInformation is never set
487 NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name,
488 KEY_VALUE_INFORMATION_CLASS info_class,
489 void *info, DWORD length, DWORD *result_len )
491 NTSTATUS ret;
492 UCHAR *data_ptr;
493 unsigned int fixed_size = 0, min_size = 0;
495 TRACE( "(%p,%s,%d,%p,%d)\n", handle, debugstr_us(name), info_class, info, length );
497 if (name->Length > MAX_VALUE_LENGTH) return STATUS_OBJECT_NAME_NOT_FOUND;
499 /* compute the length we want to retrieve */
500 switch(info_class)
502 case KeyValueBasicInformation:
504 KEY_VALUE_BASIC_INFORMATION *basic_info = info;
505 min_size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);
506 fixed_size = min_size + name->Length;
507 if (min_size < length)
508 memcpy(basic_info->Name, name->Buffer, min(length - min_size, name->Length));
509 data_ptr = NULL;
510 break;
512 case KeyValueFullInformation:
514 KEY_VALUE_FULL_INFORMATION *full_info = info;
515 min_size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
516 fixed_size = min_size + name->Length;
517 if (min_size < length)
518 memcpy(full_info->Name, name->Buffer, min(length - min_size, name->Length));
519 data_ptr = (UCHAR *)full_info->Name + name->Length;
520 break;
522 case KeyValuePartialInformation:
523 min_size = fixed_size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
524 data_ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data;
525 break;
526 default:
527 FIXME( "Information class %d not implemented\n", info_class );
528 return STATUS_INVALID_PARAMETER;
531 SERVER_START_REQ( get_key_value )
533 req->hkey = wine_server_obj_handle( handle );
534 wine_server_add_data( req, name->Buffer, name->Length );
535 if (length > fixed_size && data_ptr) wine_server_set_reply( req, data_ptr, length - fixed_size );
536 if (!(ret = wine_server_call( req )))
538 copy_key_value_info( info_class, info, length, reply->type,
539 name->Length, reply->total );
540 *result_len = fixed_size + (info_class == KeyValueBasicInformation ? 0 : reply->total);
541 if (length < min_size) ret = STATUS_BUFFER_TOO_SMALL;
542 else if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
545 SERVER_END_REQ;
546 return ret;
549 /******************************************************************************
550 * RtlpNtQueryValueKey [NTDLL.@]
553 NTSTATUS WINAPI RtlpNtQueryValueKey( HANDLE handle, ULONG *result_type, PBYTE dest,
554 DWORD *result_len, void *unknown )
556 KEY_VALUE_PARTIAL_INFORMATION *info;
557 UNICODE_STRING name;
558 NTSTATUS ret;
559 DWORD dwResultLen;
560 DWORD dwLen = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + (result_len ? *result_len : 0);
562 info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
563 if (!info)
564 return STATUS_NO_MEMORY;
566 name.Length = 0;
567 ret = NtQueryValueKey( handle, &name, KeyValuePartialInformation, info, dwLen, &dwResultLen );
569 if (!ret || ret == STATUS_BUFFER_OVERFLOW)
571 if (result_len)
572 *result_len = info->DataLength;
574 if (result_type)
575 *result_type = info->Type;
577 if (ret != STATUS_BUFFER_OVERFLOW)
578 memcpy( dest, info->Data, info->DataLength );
581 RtlFreeHeap( GetProcessHeap(), 0, info );
582 return ret;
585 /******************************************************************************
586 * NtFlushKey [NTDLL.@]
587 * ZwFlushKey [NTDLL.@]
589 NTSTATUS WINAPI NtFlushKey(HANDLE key)
591 NTSTATUS ret;
593 TRACE("key=%p\n", key);
595 SERVER_START_REQ( flush_key )
597 req->hkey = wine_server_obj_handle( key );
598 ret = wine_server_call( req );
600 SERVER_END_REQ;
602 return ret;
605 /******************************************************************************
606 * NtLoadKey [NTDLL.@]
607 * ZwLoadKey [NTDLL.@]
609 NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file )
611 NTSTATUS ret;
612 HANDLE hive;
613 IO_STATUS_BLOCK io;
615 TRACE("(%p,%p)\n", attr, file);
617 ret = NtCreateFile(&hive, GENERIC_READ, file, &io, NULL, FILE_ATTRIBUTE_NORMAL, 0,
618 FILE_OPEN, 0, NULL, 0);
619 if (ret) return ret;
621 SERVER_START_REQ( load_registry )
623 req->hkey = wine_server_obj_handle( attr->RootDirectory );
624 req->file = wine_server_obj_handle( hive );
625 wine_server_add_data(req, attr->ObjectName->Buffer, attr->ObjectName->Length);
626 ret = wine_server_call( req );
628 SERVER_END_REQ;
630 NtClose(hive);
632 return ret;
635 /******************************************************************************
636 * NtNotifyChangeMultipleKeys [NTDLL.@]
637 * ZwNotifyChangeMultipleKeys [NTDLL.@]
639 NTSTATUS WINAPI NtNotifyChangeMultipleKeys(
640 HANDLE KeyHandle,
641 ULONG Count,
642 OBJECT_ATTRIBUTES *SubordinateObjects,
643 HANDLE Event,
644 PIO_APC_ROUTINE ApcRoutine,
645 PVOID ApcContext,
646 PIO_STATUS_BLOCK IoStatusBlock,
647 ULONG CompletionFilter,
648 BOOLEAN WatchSubtree,
649 PVOID ChangeBuffer,
650 ULONG Length,
651 BOOLEAN Asynchronous)
653 NTSTATUS ret;
655 TRACE("(%p,%u,%p,%p,%p,%p,%p,0x%08x, 0x%08x,%p,0x%08x,0x%08x)\n",
656 KeyHandle, Count, SubordinateObjects, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
657 Asynchronous, ChangeBuffer, Length, WatchSubtree);
659 if (Count || SubordinateObjects || ApcRoutine || ApcContext || ChangeBuffer || Length)
660 FIXME("Unimplemented optional parameter\n");
662 if (!Asynchronous)
664 OBJECT_ATTRIBUTES attr;
665 InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
666 ret = NtCreateEvent( &Event, EVENT_ALL_ACCESS, &attr, SynchronizationEvent, FALSE );
667 if (ret != STATUS_SUCCESS)
668 return ret;
671 SERVER_START_REQ( set_registry_notification )
673 req->hkey = wine_server_obj_handle( KeyHandle );
674 req->event = wine_server_obj_handle( Event );
675 req->subtree = WatchSubtree;
676 req->filter = CompletionFilter;
677 ret = wine_server_call( req );
679 SERVER_END_REQ;
681 if (!Asynchronous)
683 if (ret == STATUS_PENDING)
684 ret = NtWaitForSingleObject( Event, FALSE, NULL );
685 NtClose( Event );
688 return ret;
691 /******************************************************************************
692 * NtNotifyChangeKey [NTDLL.@]
693 * ZwNotifyChangeKey [NTDLL.@]
695 NTSTATUS WINAPI NtNotifyChangeKey(
696 IN HANDLE KeyHandle,
697 IN HANDLE Event,
698 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
699 IN PVOID ApcContext OPTIONAL,
700 OUT PIO_STATUS_BLOCK IoStatusBlock,
701 IN ULONG CompletionFilter,
702 IN BOOLEAN WatchSubtree,
703 OUT PVOID ChangeBuffer,
704 IN ULONG Length,
705 IN BOOLEAN Asynchronous)
707 return NtNotifyChangeMultipleKeys(KeyHandle, 0, NULL, Event, ApcRoutine, ApcContext,
708 IoStatusBlock, CompletionFilter, WatchSubtree,
709 ChangeBuffer, Length, Asynchronous);
712 /******************************************************************************
713 * NtQueryMultipleValueKey [NTDLL]
714 * ZwQueryMultipleValueKey
717 NTSTATUS WINAPI NtQueryMultipleValueKey(
718 HANDLE KeyHandle,
719 PKEY_MULTIPLE_VALUE_INFORMATION ListOfValuesToQuery,
720 ULONG NumberOfItems,
721 PVOID MultipleValueInformation,
722 ULONG Length,
723 PULONG ReturnLength)
725 FIXME("(%p,%p,0x%08x,%p,0x%08x,%p) stub!\n",
726 KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
727 Length,ReturnLength);
728 return STATUS_SUCCESS;
731 /******************************************************************************
732 * NtReplaceKey [NTDLL.@]
733 * ZwReplaceKey [NTDLL.@]
735 NTSTATUS WINAPI NtReplaceKey(
736 IN POBJECT_ATTRIBUTES ObjectAttributes,
737 IN HANDLE Key,
738 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
740 FIXME("(%s,%p,%s),stub!\n", debugstr_ObjectAttributes(ObjectAttributes), Key,
741 debugstr_ObjectAttributes(ReplacedObjectAttributes) );
742 return STATUS_SUCCESS;
744 /******************************************************************************
745 * NtRestoreKey [NTDLL.@]
746 * ZwRestoreKey [NTDLL.@]
748 NTSTATUS WINAPI NtRestoreKey(
749 HANDLE KeyHandle,
750 HANDLE FileHandle,
751 ULONG RestoreFlags)
753 FIXME("(%p,%p,0x%08x) stub\n",
754 KeyHandle, FileHandle, RestoreFlags);
755 return STATUS_SUCCESS;
757 /******************************************************************************
758 * NtSaveKey [NTDLL.@]
759 * ZwSaveKey [NTDLL.@]
761 NTSTATUS WINAPI NtSaveKey(IN HANDLE KeyHandle, IN HANDLE FileHandle)
763 NTSTATUS ret;
765 TRACE("(%p,%p)\n", KeyHandle, FileHandle);
767 SERVER_START_REQ( save_registry )
769 req->hkey = wine_server_obj_handle( KeyHandle );
770 req->file = wine_server_obj_handle( FileHandle );
771 ret = wine_server_call( req );
773 SERVER_END_REQ;
775 return ret;
777 /******************************************************************************
778 * NtSetInformationKey [NTDLL.@]
779 * ZwSetInformationKey [NTDLL.@]
781 NTSTATUS WINAPI NtSetInformationKey(
782 IN HANDLE KeyHandle,
783 IN const int KeyInformationClass,
784 IN PVOID KeyInformation,
785 IN ULONG KeyInformationLength)
787 FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
788 KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
789 return STATUS_SUCCESS;
793 /******************************************************************************
794 * NtSetValueKey [NTDLL.@]
795 * ZwSetValueKey [NTDLL.@]
797 * NOTES
798 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
799 * NT does definitely care (aj)
801 NTSTATUS WINAPI NtSetValueKey( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
802 ULONG type, const void *data, ULONG count )
804 NTSTATUS ret;
806 TRACE( "(%p,%s,%d,%p,%d)\n", hkey, debugstr_us(name), type, data, count );
808 if (name->Length > MAX_VALUE_LENGTH) return STATUS_INVALID_PARAMETER;
810 SERVER_START_REQ( set_key_value )
812 req->hkey = wine_server_obj_handle( hkey );
813 req->type = type;
814 req->namelen = name->Length;
815 wine_server_add_data( req, name->Buffer, name->Length );
816 wine_server_add_data( req, data, count );
817 ret = wine_server_call( req );
819 SERVER_END_REQ;
820 return ret;
823 /******************************************************************************
824 * RtlpNtSetValueKey [NTDLL.@]
827 NTSTATUS WINAPI RtlpNtSetValueKey( HANDLE hkey, ULONG type, const void *data,
828 ULONG count )
830 UNICODE_STRING name;
832 name.Length = 0;
833 return NtSetValueKey( hkey, &name, 0, type, data, count );
836 /******************************************************************************
837 * NtUnloadKey [NTDLL.@]
838 * ZwUnloadKey [NTDLL.@]
840 NTSTATUS WINAPI NtUnloadKey(IN POBJECT_ATTRIBUTES attr)
842 NTSTATUS ret;
844 TRACE("(%p)\n", attr);
846 SERVER_START_REQ( unload_registry )
848 req->hkey = wine_server_obj_handle( attr->RootDirectory );
849 ret = wine_server_call(req);
851 SERVER_END_REQ;
853 return ret;
856 /******************************************************************************
857 * RtlFormatCurrentUserKeyPath [NTDLL.@]
860 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
862 static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
863 HANDLE token;
864 NTSTATUS status;
866 status = NtOpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &token);
867 if (status == STATUS_NO_TOKEN)
868 status = NtOpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token);
869 if (status == STATUS_SUCCESS)
871 char buffer[sizeof(TOKEN_USER) + sizeof(SID) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES];
872 DWORD len = sizeof(buffer);
874 status = NtQueryInformationToken(token, TokenUser, buffer, len, &len);
875 if (status == STATUS_SUCCESS)
877 KeyPath->MaximumLength = 0;
878 status = RtlConvertSidToUnicodeString(KeyPath, ((TOKEN_USER *)buffer)->User.Sid, FALSE);
879 if (status == STATUS_BUFFER_OVERFLOW)
881 PWCHAR buf = RtlAllocateHeap(GetProcessHeap(), 0,
882 sizeof(pathW) + KeyPath->Length + sizeof(WCHAR));
883 if (buf)
885 memcpy(buf, pathW, sizeof(pathW));
886 KeyPath->MaximumLength = KeyPath->Length + sizeof(WCHAR);
887 KeyPath->Buffer = (PWCHAR)((LPBYTE)buf + sizeof(pathW));
888 status = RtlConvertSidToUnicodeString(KeyPath,
889 ((TOKEN_USER *)buffer)->User.Sid, FALSE);
890 KeyPath->Buffer = buf;
891 KeyPath->Length += sizeof(pathW);
892 KeyPath->MaximumLength += sizeof(pathW);
894 else
895 status = STATUS_NO_MEMORY;
898 NtClose(token);
900 return status;
903 /******************************************************************************
904 * RtlOpenCurrentUser [NTDLL.@]
906 * NOTES
907 * If we return just HKEY_CURRENT_USER the advapi tries to find a remote
908 * registry (odd handle) and fails.
910 NTSTATUS WINAPI RtlOpenCurrentUser(
911 IN ACCESS_MASK DesiredAccess, /* [in] */
912 OUT PHANDLE KeyHandle) /* [out] handle of HKEY_CURRENT_USER */
914 OBJECT_ATTRIBUTES ObjectAttributes;
915 UNICODE_STRING ObjectName;
916 NTSTATUS ret;
918 TRACE("(0x%08x, %p)\n",DesiredAccess, KeyHandle);
920 if ((ret = RtlFormatCurrentUserKeyPath(&ObjectName))) return ret;
921 InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
922 ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
923 RtlFreeUnicodeString(&ObjectName);
924 return ret;
928 static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
929 PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
931 PUNICODE_STRING str;
932 UNICODE_STRING src, dst;
933 LONG *bin;
934 ULONG offset;
935 PWSTR wstr;
936 DWORD res;
937 NTSTATUS status = STATUS_SUCCESS;
938 ULONG len;
939 LPWSTR String;
940 ULONG count = 0;
942 if (pInfo == NULL)
944 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
945 return STATUS_INVALID_PARAMETER;
946 else
948 status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
949 pQuery->DefaultLength, pContext, pQuery->EntryContext);
951 return status;
953 len = pInfo->DataLength;
955 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
957 str = pQuery->EntryContext;
959 switch(pInfo->Type)
961 case REG_EXPAND_SZ:
962 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
964 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
965 res = 0;
966 dst.MaximumLength = 0;
967 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
968 dst.Length = 0;
969 dst.MaximumLength = res;
970 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
971 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
972 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
973 dst.Length, pContext, pQuery->EntryContext);
974 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
977 case REG_SZ:
978 case REG_LINK:
979 if (str->Buffer == NULL)
980 RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
981 else
982 RtlAppendUnicodeToString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
983 break;
985 case REG_MULTI_SZ:
986 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
987 return STATUS_INVALID_PARAMETER;
989 if (str->Buffer == NULL)
991 str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
992 str->MaximumLength = len;
994 len = min(len, str->MaximumLength);
995 memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
996 str->Length = len;
997 break;
999 default:
1000 bin = pQuery->EntryContext;
1001 if (pInfo->DataLength <= sizeof(ULONG))
1002 memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
1003 pInfo->DataLength);
1004 else
1006 if (bin[0] <= sizeof(ULONG))
1008 memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
1009 min(-bin[0], pInfo->DataLength));
1011 else
1013 len = min(bin[0], pInfo->DataLength);
1014 bin[1] = len;
1015 bin[2] = pInfo->Type;
1016 memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
1019 break;
1022 else
1024 if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
1025 (pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
1027 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type,
1028 ((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
1029 pContext, pQuery->EntryContext);
1031 else if (pInfo->Type == REG_EXPAND_SZ)
1033 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1034 res = 0;
1035 dst.MaximumLength = 0;
1036 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1037 dst.Length = 0;
1038 dst.MaximumLength = res;
1039 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1040 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1041 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1042 dst.Length, pContext, pQuery->EntryContext);
1043 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1045 else /* REG_MULTI_SZ */
1047 if(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
1049 for (offset = 0; offset <= pInfo->DataLength; offset += len + sizeof(WCHAR))
1051 wstr = (WCHAR*)(((CHAR*)pInfo) + offset);
1052 len = strlenW(wstr) * sizeof(WCHAR);
1053 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, wstr, len,
1054 pContext, pQuery->EntryContext);
1055 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1056 return status;
1059 else
1061 while(count<=pInfo->DataLength)
1063 String = (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset)+count;
1064 count+=strlenW(String)+1;
1065 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1066 res = 0;
1067 dst.MaximumLength = 0;
1068 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1069 dst.Length = 0;
1070 dst.MaximumLength = res;
1071 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1072 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1073 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1074 dst.Length, pContext, pQuery->EntryContext);
1075 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1076 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1077 return status;
1082 return status;
1086 static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
1088 UNICODE_STRING KeyString;
1089 OBJECT_ATTRIBUTES regkey;
1090 PCWSTR base;
1091 INT len;
1092 NTSTATUS status;
1094 static const WCHAR empty[] = {0};
1095 static const WCHAR control[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1096 '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1097 'C','o','n','t','r','o','l','\\',0};
1099 static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1100 'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1102 static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1103 'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1104 'S','e','r','v','i','c','e','s','\\',0};
1106 static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1107 'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1109 static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1110 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1111 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1113 switch (RelativeTo & 0xff)
1115 case RTL_REGISTRY_ABSOLUTE:
1116 base = empty;
1117 break;
1119 case RTL_REGISTRY_CONTROL:
1120 base = control;
1121 break;
1123 case RTL_REGISTRY_DEVICEMAP:
1124 base = devicemap;
1125 break;
1127 case RTL_REGISTRY_SERVICES:
1128 base = services;
1129 break;
1131 case RTL_REGISTRY_USER:
1132 base = user;
1133 break;
1135 case RTL_REGISTRY_WINDOWS_NT:
1136 base = windows_nt;
1137 break;
1139 default:
1140 return STATUS_INVALID_PARAMETER;
1143 len = (strlenW(base) + strlenW(Path) + 1) * sizeof(WCHAR);
1144 KeyString.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1145 if (KeyString.Buffer == NULL)
1146 return STATUS_NO_MEMORY;
1148 strcpyW(KeyString.Buffer, base);
1149 strcatW(KeyString.Buffer, Path);
1150 KeyString.Length = len - sizeof(WCHAR);
1151 KeyString.MaximumLength = len;
1152 InitializeObjectAttributes(&regkey, &KeyString, OBJ_CASE_INSENSITIVE, NULL, NULL);
1153 status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
1154 RtlFreeHeap(GetProcessHeap(), 0, KeyString.Buffer);
1155 return status;
1158 /*************************************************************************
1159 * RtlQueryRegistryValues [NTDLL.@]
1161 * Query multiple registry values with a signle call.
1163 * PARAMS
1164 * RelativeTo [I] Registry path that Path refers to
1165 * Path [I] Path to key
1166 * QueryTable [I] Table of key values to query
1167 * Context [I] Parameter to pass to the application defined QueryRoutine function
1168 * Environment [I] Optional parameter to use when performing expansion
1170 * RETURNS
1171 * STATUS_SUCCESS or an appropriate NTSTATUS error code.
1173 NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
1174 IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
1175 IN PVOID Environment OPTIONAL)
1177 UNICODE_STRING Value;
1178 HANDLE handle, topkey;
1179 PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
1180 ULONG len, buflen = 0;
1181 NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
1182 INT i;
1184 TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
1186 if(Path == NULL)
1187 return STATUS_INVALID_PARAMETER;
1189 /* get a valid handle */
1190 if (RelativeTo & RTL_REGISTRY_HANDLE)
1191 topkey = handle = (HANDLE)Path;
1192 else
1194 status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
1195 handle = topkey;
1197 if(status != STATUS_SUCCESS)
1198 return status;
1200 /* Process query table entries */
1201 for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
1203 if (QueryTable->Flags &
1204 (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
1206 /* topkey must be kept open just in case we will reuse it later */
1207 if (handle != topkey)
1208 NtClose(handle);
1210 if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
1212 handle = 0;
1213 status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
1214 if(status != STATUS_SUCCESS)
1216 ret = status;
1217 goto out;
1220 else
1221 handle = topkey;
1224 if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
1226 QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
1227 Context, QueryTable->EntryContext);
1228 continue;
1231 if (!handle)
1233 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1235 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1236 goto out;
1238 continue;
1241 if (QueryTable->Name == NULL)
1243 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
1245 ret = STATUS_INVALID_PARAMETER;
1246 goto out;
1249 /* Report all subkeys */
1250 for (i = 0;; ++i)
1252 status = NtEnumerateValueKey(handle, i,
1253 KeyValueFullInformation, pInfo, buflen, &len);
1254 if (status == STATUS_NO_MORE_ENTRIES)
1255 break;
1256 if (status == STATUS_BUFFER_OVERFLOW ||
1257 status == STATUS_BUFFER_TOO_SMALL)
1259 buflen = len;
1260 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1261 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1262 NtEnumerateValueKey(handle, i, KeyValueFullInformation,
1263 pInfo, buflen, &len);
1266 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1267 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1269 ret = status;
1270 goto out;
1272 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1274 RtlInitUnicodeString(&Value, pInfo->Name);
1275 NtDeleteValueKey(handle, &Value);
1279 if (i == 0 && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
1281 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1282 goto out;
1285 else
1287 RtlInitUnicodeString(&Value, QueryTable->Name);
1288 status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
1289 pInfo, buflen, &len);
1290 if (status == STATUS_BUFFER_OVERFLOW ||
1291 status == STATUS_BUFFER_TOO_SMALL)
1293 buflen = len;
1294 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1295 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1296 status = NtQueryValueKey(handle, &Value,
1297 KeyValueFullInformation, pInfo, buflen, &len);
1299 if (status != STATUS_SUCCESS)
1301 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1303 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1304 goto out;
1306 status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
1307 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1309 ret = status;
1310 goto out;
1313 else
1315 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1316 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1318 ret = status;
1319 goto out;
1321 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1322 NtDeleteValueKey(handle, &Value);
1327 out:
1328 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1329 if (handle != topkey)
1330 NtClose(handle);
1331 NtClose(topkey);
1332 return ret;
1335 /*************************************************************************
1336 * RtlCheckRegistryKey [NTDLL.@]
1338 * Query multiple registry values with a signle call.
1340 * PARAMS
1341 * RelativeTo [I] Registry path that Path refers to
1342 * Path [I] Path to key
1344 * RETURNS
1345 * STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1347 NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
1349 HANDLE handle;
1350 NTSTATUS status;
1352 TRACE("(%d, %s)\n", RelativeTo, debugstr_w(Path));
1354 if((!RelativeTo) && Path == NULL)
1355 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1356 if(RelativeTo & RTL_REGISTRY_HANDLE)
1357 return STATUS_SUCCESS;
1359 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1360 if (handle) NtClose(handle);
1361 if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
1362 return status;
1365 /*************************************************************************
1366 * RtlDeleteRegistryValue [NTDLL.@]
1368 * Query multiple registry values with a signle call.
1370 * PARAMS
1371 * RelativeTo [I] Registry path that Path refers to
1372 * Path [I] Path to key
1373 * ValueName [I] Name of the value to delete
1375 * RETURNS
1376 * STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1378 NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
1380 NTSTATUS status;
1381 HANDLE handle;
1382 UNICODE_STRING Value;
1384 TRACE("(%d, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
1386 RtlInitUnicodeString(&Value, ValueName);
1387 if(RelativeTo == RTL_REGISTRY_HANDLE)
1389 return NtDeleteValueKey((HANDLE)Path, &Value);
1391 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1392 if (status) return status;
1393 status = NtDeleteValueKey(handle, &Value);
1394 NtClose(handle);
1395 return status;
1398 /*************************************************************************
1399 * RtlWriteRegistryValue [NTDLL.@]
1401 * Sets the registry value with provided data.
1403 * PARAMS
1404 * RelativeTo [I] Registry path that path parameter refers to
1405 * path [I] Path to the key (or handle - see RTL_GetKeyHandle)
1406 * name [I] Name of the registry value to set
1407 * type [I] Type of the registry key to set
1408 * data [I] Pointer to the user data to be set
1409 * length [I] Length of the user data pointed by data
1411 * RETURNS
1412 * STATUS_SUCCESS if the specified key is successfully set,
1413 * or an NTSTATUS error code.
1415 NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
1416 ULONG type, PVOID data, ULONG length )
1418 HANDLE hkey;
1419 NTSTATUS status;
1420 UNICODE_STRING str;
1422 TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
1423 type, data, length );
1425 RtlInitUnicodeString( &str, name );
1427 if (RelativeTo == RTL_REGISTRY_HANDLE)
1428 return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
1430 status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
1431 if (status != STATUS_SUCCESS) return status;
1433 status = NtSetValueKey( hkey, &str, 0, type, data, length );
1434 NtClose( hkey );
1436 return status;
1439 /*************************************************************************
1440 * NtQueryLicenseValue [NTDLL.@]
1442 * NOTES
1443 * On Windows all license properties are stored in a single key, but
1444 * unless there is some app which explicitly depends on that, there is
1445 * no good reason to reproduce that.
1447 NTSTATUS WINAPI NtQueryLicenseValue( const UNICODE_STRING *name, ULONG *result_type,
1448 PVOID data, ULONG length, ULONG *result_len )
1450 static const WCHAR LicenseInformationW[] = {'M','a','c','h','i','n','e','\\',
1451 'S','o','f','t','w','a','r','e','\\',
1452 'W','i','n','e','\\','L','i','c','e','n','s','e',
1453 'I','n','f','o','r','m','a','t','i','o','n',0};
1454 KEY_VALUE_PARTIAL_INFORMATION *info;
1455 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
1456 DWORD info_length, count;
1457 OBJECT_ATTRIBUTES attr;
1458 UNICODE_STRING keyW;
1459 HANDLE hkey;
1461 if (!name || !name->Buffer || !name->Length || !result_len)
1462 return STATUS_INVALID_PARAMETER;
1464 info_length = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + length;
1465 info = RtlAllocateHeap( GetProcessHeap(), 0, info_length );
1466 if (!info) return STATUS_NO_MEMORY;
1468 attr.Length = sizeof(attr);
1469 attr.RootDirectory = 0;
1470 attr.ObjectName = &keyW;
1471 attr.Attributes = 0;
1472 attr.SecurityDescriptor = NULL;
1473 attr.SecurityQualityOfService = NULL;
1474 RtlInitUnicodeString( &keyW, LicenseInformationW );
1476 /* @@ Wine registry key: HKLM\Software\Wine\LicenseInformation */
1477 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
1479 status = NtQueryValueKey( hkey, name, KeyValuePartialInformation,
1480 info, info_length, &count );
1481 if (!status || status == STATUS_BUFFER_OVERFLOW)
1483 if (result_type)
1484 *result_type = info->Type;
1486 *result_len = info->DataLength;
1488 if (status == STATUS_BUFFER_OVERFLOW)
1489 status = STATUS_BUFFER_TOO_SMALL;
1490 else
1491 memcpy( data, info->Data, info->DataLength );
1493 NtClose( hkey );
1496 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1497 FIXME( "License key %s not found\n", debugstr_w(name->Buffer) );
1499 RtlFreeHeap( GetProcessHeap(), 0, info );
1500 return status;