ws2_32: Accept shouldn't fail when addrlen32 is NULL.
[wine.git] / dlls / ntdll / reg.c
blob6dc5d61966873d8333272e594453635a67b73d47
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 value name in bytes (without terminating null) */
46 #define MAX_VALUE_LENGTH (16383 * sizeof(WCHAR))
48 /******************************************************************************
49 * NtCreateKey [NTDLL.@]
50 * ZwCreateKey [NTDLL.@]
52 NTSTATUS WINAPI NtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
53 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
54 PULONG dispos )
56 NTSTATUS ret;
57 data_size_t len;
58 struct object_attributes *objattr;
60 if (!retkey || !attr) return STATUS_ACCESS_VIOLATION;
61 if (attr->Length > sizeof(OBJECT_ATTRIBUTES)) return STATUS_INVALID_PARAMETER;
63 TRACE( "(%p,%s,%s,%x,%x,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
64 debugstr_us(class), options, access, retkey );
66 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
68 SERVER_START_REQ( create_key )
70 req->access = access;
71 req->options = options;
72 wine_server_add_data( req, objattr, len );
73 if (class) wine_server_add_data( req, class->Buffer, class->Length );
74 if (!(ret = wine_server_call( req )))
76 *retkey = wine_server_ptr_handle( reply->hkey );
77 if (dispos) *dispos = reply->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
80 SERVER_END_REQ;
82 TRACE("<- %p\n", *retkey);
83 RtlFreeHeap( GetProcessHeap(), 0, objattr );
84 return ret;
87 NTSTATUS WINAPI NtCreateKeyTransacted( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
88 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
89 HANDLE transacted, ULONG *dispos )
91 FIXME( "(%p,%s,%s,%x,%x,%p,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
92 debugstr_us(class), options, access, transacted, retkey );
93 return STATUS_NOT_IMPLEMENTED;
96 NTSTATUS WINAPI NtRenameKey( HANDLE handle, UNICODE_STRING *name )
98 FIXME( "(%p %s)\n", handle, debugstr_us(name) );
99 return STATUS_NOT_IMPLEMENTED;
102 /******************************************************************************
103 * RtlpNtCreateKey [NTDLL.@]
105 * See NtCreateKey.
107 NTSTATUS WINAPI RtlpNtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
108 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
109 PULONG dispos )
111 OBJECT_ATTRIBUTES oa;
113 if (attr)
115 oa = *attr;
116 oa.Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
117 attr = &oa;
120 return NtCreateKey(retkey, access, attr, 0, NULL, 0, dispos);
123 static NTSTATUS open_key( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, ULONG options )
125 NTSTATUS ret;
127 if (!retkey || !attr || !attr->ObjectName) return STATUS_ACCESS_VIOLATION;
128 if ((ret = validate_open_object_attributes( attr ))) return ret;
130 TRACE( "(%p,%s,%x,%p)\n", attr->RootDirectory,
131 debugstr_us(attr->ObjectName), access, retkey );
132 if (options)
133 FIXME("options %x not implemented\n", options);
135 SERVER_START_REQ( open_key )
137 req->parent = wine_server_obj_handle( attr->RootDirectory );
138 req->access = access;
139 req->attributes = attr->Attributes;
140 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
141 ret = wine_server_call( req );
142 *retkey = wine_server_ptr_handle( reply->hkey );
144 SERVER_END_REQ;
145 TRACE("<- %p\n", *retkey);
146 return ret;
149 /******************************************************************************
150 * NtOpenKeyEx [NTDLL.@]
151 * ZwOpenKeyEx [NTDLL.@]
153 NTSTATUS WINAPI NtOpenKeyEx( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, ULONG options )
155 return open_key( retkey, access, attr, options );
158 /******************************************************************************
159 * NtOpenKey [NTDLL.@]
160 * ZwOpenKey [NTDLL.@]
162 * OUT HANDLE retkey (returns 0 when failure)
163 * IN ACCESS_MASK access
164 * IN POBJECT_ATTRIBUTES attr
166 NTSTATUS WINAPI NtOpenKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
168 return open_key( retkey, access, attr, 0 );
171 NTSTATUS WINAPI NtOpenKeyTransactedEx( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
172 ULONG options, HANDLE transaction )
174 FIXME( "(%p %x %p %x %p)\n", retkey, access, attr, options, transaction );
175 return STATUS_NOT_IMPLEMENTED;
178 NTSTATUS WINAPI NtOpenKeyTransacted( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
179 HANDLE transaction )
181 return NtOpenKeyTransactedEx( retkey, access, attr, 0, transaction );
184 /******************************************************************************
185 * RtlpNtOpenKey [NTDLL.@]
187 * See NtOpenKey.
189 NTSTATUS WINAPI RtlpNtOpenKey( PHANDLE retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
191 if (attr)
192 attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
193 return NtOpenKey(retkey, access, attr);
196 /******************************************************************************
197 * NtDeleteKey [NTDLL.@]
198 * ZwDeleteKey [NTDLL.@]
200 NTSTATUS WINAPI NtDeleteKey( HANDLE hkey )
202 NTSTATUS ret;
204 TRACE( "(%p)\n", hkey );
206 SERVER_START_REQ( delete_key )
208 req->hkey = wine_server_obj_handle( hkey );
209 ret = wine_server_call( req );
211 SERVER_END_REQ;
212 return ret;
215 /******************************************************************************
216 * RtlpNtMakeTemporaryKey [NTDLL.@]
218 * See NtDeleteKey.
220 NTSTATUS WINAPI RtlpNtMakeTemporaryKey( HANDLE hkey )
222 return NtDeleteKey(hkey);
225 /******************************************************************************
226 * NtDeleteValueKey [NTDLL.@]
227 * ZwDeleteValueKey [NTDLL.@]
229 NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name )
231 NTSTATUS ret;
233 TRACE( "(%p,%s)\n", hkey, debugstr_us(name) );
234 if (name->Length > MAX_VALUE_LENGTH) return STATUS_OBJECT_NAME_NOT_FOUND;
236 SERVER_START_REQ( delete_key_value )
238 req->hkey = wine_server_obj_handle( hkey );
239 wine_server_add_data( req, name->Buffer, name->Length );
240 ret = wine_server_call( req );
242 SERVER_END_REQ;
243 return ret;
247 /******************************************************************************
248 * enumerate_key
250 * Implementation of NtQueryKey and NtEnumerateKey
252 static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS info_class,
253 void *info, DWORD length, DWORD *result_len )
256 NTSTATUS ret;
257 void *data_ptr;
258 size_t fixed_size;
260 switch(info_class)
262 case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break;
263 case KeyFullInformation: data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
264 case KeyNodeInformation: data_ptr = ((KEY_NODE_INFORMATION *)info)->Name; break;
265 case KeyNameInformation: data_ptr = ((KEY_NAME_INFORMATION *)info)->Name; break;
266 case KeyCachedInformation: data_ptr = ((KEY_CACHED_INFORMATION *)info)+1; break;
267 default:
268 FIXME( "Information class %d not implemented\n", info_class );
269 return STATUS_INVALID_PARAMETER;
271 fixed_size = (char *)data_ptr - (char *)info;
273 SERVER_START_REQ( enum_key )
275 req->hkey = wine_server_obj_handle( handle );
276 req->index = index;
277 req->info_class = info_class;
278 if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
279 if (!(ret = wine_server_call( req )))
281 switch(info_class)
283 case KeyBasicInformation:
285 KEY_BASIC_INFORMATION keyinfo;
286 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
287 keyinfo.LastWriteTime.QuadPart = reply->modif;
288 keyinfo.TitleIndex = 0;
289 keyinfo.NameLength = reply->namelen;
290 memcpy( info, &keyinfo, min( length, fixed_size ) );
292 break;
293 case KeyFullInformation:
295 KEY_FULL_INFORMATION keyinfo;
296 fixed_size = (char *)keyinfo.Class - (char *)&keyinfo;
297 keyinfo.LastWriteTime.QuadPart = reply->modif;
298 keyinfo.TitleIndex = 0;
299 keyinfo.ClassLength = wine_server_reply_size(reply);
300 keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
301 keyinfo.SubKeys = reply->subkeys;
302 keyinfo.MaxNameLen = reply->max_subkey;
303 keyinfo.MaxClassLen = reply->max_class;
304 keyinfo.Values = reply->values;
305 keyinfo.MaxValueNameLen = reply->max_value;
306 keyinfo.MaxValueDataLen = reply->max_data;
307 memcpy( info, &keyinfo, min( length, fixed_size ) );
309 break;
310 case KeyNodeInformation:
312 KEY_NODE_INFORMATION keyinfo;
313 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
314 keyinfo.LastWriteTime.QuadPart = reply->modif;
315 keyinfo.TitleIndex = 0;
316 if (reply->namelen < wine_server_reply_size(reply))
318 keyinfo.ClassLength = wine_server_reply_size(reply) - reply->namelen;
319 keyinfo.ClassOffset = fixed_size + reply->namelen;
321 else
323 keyinfo.ClassLength = 0;
324 keyinfo.ClassOffset = -1;
326 keyinfo.NameLength = reply->namelen;
327 memcpy( info, &keyinfo, min( length, fixed_size ) );
329 break;
330 case KeyNameInformation:
332 KEY_NAME_INFORMATION keyinfo;
333 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
334 keyinfo.NameLength = reply->namelen;
335 memcpy( info, &keyinfo, min( length, fixed_size ) );
337 break;
338 case KeyCachedInformation:
340 KEY_CACHED_INFORMATION keyinfo;
341 fixed_size = sizeof(keyinfo);
342 keyinfo.LastWriteTime.QuadPart = reply->modif;
343 keyinfo.TitleIndex = 0;
344 keyinfo.SubKeys = reply->subkeys;
345 keyinfo.MaxNameLen = reply->max_subkey;
346 keyinfo.Values = reply->values;
347 keyinfo.MaxValueNameLen = reply->max_value;
348 keyinfo.MaxValueDataLen = reply->max_data;
349 keyinfo.NameLength = reply->namelen;
350 memcpy( info, &keyinfo, min( length, fixed_size ) );
352 break;
353 default:
354 break;
356 *result_len = fixed_size + reply->total;
357 if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
360 SERVER_END_REQ;
361 return ret;
366 /******************************************************************************
367 * NtEnumerateKey [NTDLL.@]
368 * ZwEnumerateKey [NTDLL.@]
370 * NOTES
371 * the name copied into the buffer is NOT 0-terminated
373 NTSTATUS WINAPI NtEnumerateKey( HANDLE handle, ULONG index, KEY_INFORMATION_CLASS info_class,
374 void *info, DWORD length, DWORD *result_len )
376 /* -1 means query key, so avoid it here */
377 if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
378 return enumerate_key( handle, index, info_class, info, length, result_len );
382 /******************************************************************************
383 * RtlpNtEnumerateSubKey [NTDLL.@]
386 NTSTATUS WINAPI RtlpNtEnumerateSubKey( HANDLE handle, UNICODE_STRING *out, ULONG index )
388 KEY_BASIC_INFORMATION *info;
389 DWORD dwLen, dwResultLen;
390 NTSTATUS ret;
392 if (out->Length)
394 dwLen = out->Length + sizeof(KEY_BASIC_INFORMATION);
395 info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
396 if (!info)
397 return STATUS_NO_MEMORY;
399 else
401 dwLen = 0;
402 info = NULL;
405 ret = NtEnumerateKey( handle, index, KeyBasicInformation, info, dwLen, &dwResultLen );
406 dwResultLen -= sizeof(KEY_BASIC_INFORMATION);
408 if (ret == STATUS_BUFFER_OVERFLOW)
409 out->Length = dwResultLen;
410 else if (!ret)
412 if (out->Length < info->NameLength)
414 out->Length = dwResultLen;
415 ret = STATUS_BUFFER_OVERFLOW;
417 else
419 out->Length = info->NameLength;
420 memcpy(out->Buffer, info->Name, info->NameLength);
424 RtlFreeHeap( GetProcessHeap(), 0, info );
425 return ret;
428 /******************************************************************************
429 * NtQueryKey [NTDLL.@]
430 * ZwQueryKey [NTDLL.@]
432 NTSTATUS WINAPI NtQueryKey( HANDLE handle, KEY_INFORMATION_CLASS info_class,
433 void *info, DWORD length, DWORD *result_len )
435 return enumerate_key( handle, -1, info_class, info, length, result_len );
439 /* fill the key value info structure for a specific info class */
440 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info,
441 DWORD length, int type, int name_len, int data_len )
443 switch(info_class)
445 case KeyValueBasicInformation:
447 KEY_VALUE_BASIC_INFORMATION keyinfo;
448 keyinfo.TitleIndex = 0;
449 keyinfo.Type = type;
450 keyinfo.NameLength = name_len;
451 length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
452 memcpy( info, &keyinfo, length );
453 break;
455 case KeyValueFullInformation:
457 KEY_VALUE_FULL_INFORMATION keyinfo;
458 keyinfo.TitleIndex = 0;
459 keyinfo.Type = type;
460 keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len;
461 keyinfo.DataLength = data_len;
462 keyinfo.NameLength = name_len;
463 length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
464 memcpy( info, &keyinfo, length );
465 break;
467 case KeyValuePartialInformation:
469 KEY_VALUE_PARTIAL_INFORMATION keyinfo;
470 keyinfo.TitleIndex = 0;
471 keyinfo.Type = type;
472 keyinfo.DataLength = data_len;
473 length = min( length, (char *)keyinfo.Data - (char *)&keyinfo );
474 memcpy( info, &keyinfo, length );
475 break;
477 default:
478 break;
483 /******************************************************************************
484 * NtEnumerateValueKey [NTDLL.@]
485 * ZwEnumerateValueKey [NTDLL.@]
487 NTSTATUS WINAPI NtEnumerateValueKey( HANDLE handle, ULONG index,
488 KEY_VALUE_INFORMATION_CLASS info_class,
489 void *info, DWORD length, DWORD *result_len )
491 NTSTATUS ret;
492 void *ptr;
493 size_t fixed_size;
495 TRACE( "(%p,%u,%d,%p,%d)\n", handle, index, info_class, info, length );
497 /* compute the length we want to retrieve */
498 switch(info_class)
500 case KeyValueBasicInformation: ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break;
501 case KeyValueFullInformation: ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break;
502 case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break;
503 default:
504 FIXME( "Information class %d not implemented\n", info_class );
505 return STATUS_INVALID_PARAMETER;
507 fixed_size = (char *)ptr - (char *)info;
509 SERVER_START_REQ( enum_key_value )
511 req->hkey = wine_server_obj_handle( handle );
512 req->index = index;
513 req->info_class = info_class;
514 if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size );
515 if (!(ret = wine_server_call( req )))
517 copy_key_value_info( info_class, info, length, reply->type, reply->namelen,
518 wine_server_reply_size(reply) - reply->namelen );
519 *result_len = fixed_size + reply->total;
520 if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
523 SERVER_END_REQ;
524 return ret;
528 /******************************************************************************
529 * NtQueryValueKey [NTDLL.@]
530 * ZwQueryValueKey [NTDLL.@]
532 * NOTES
533 * the name in the KeyValueInformation is never set
535 NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name,
536 KEY_VALUE_INFORMATION_CLASS info_class,
537 void *info, DWORD length, DWORD *result_len )
539 NTSTATUS ret;
540 UCHAR *data_ptr;
541 unsigned int fixed_size, min_size;
543 TRACE( "(%p,%s,%d,%p,%d)\n", handle, debugstr_us(name), info_class, info, length );
545 if (name->Length > MAX_VALUE_LENGTH) return STATUS_OBJECT_NAME_NOT_FOUND;
547 /* compute the length we want to retrieve */
548 switch(info_class)
550 case KeyValueBasicInformation:
552 KEY_VALUE_BASIC_INFORMATION *basic_info = info;
553 min_size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);
554 fixed_size = min_size + name->Length;
555 if (min_size < length)
556 memcpy(basic_info->Name, name->Buffer, min(length - min_size, name->Length));
557 data_ptr = NULL;
558 break;
560 case KeyValueFullInformation:
562 KEY_VALUE_FULL_INFORMATION *full_info = info;
563 min_size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
564 fixed_size = min_size + name->Length;
565 if (min_size < length)
566 memcpy(full_info->Name, name->Buffer, min(length - min_size, name->Length));
567 data_ptr = (UCHAR *)full_info->Name + name->Length;
568 break;
570 case KeyValuePartialInformation:
571 min_size = fixed_size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
572 data_ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data;
573 break;
574 default:
575 FIXME( "Information class %d not implemented\n", info_class );
576 return STATUS_INVALID_PARAMETER;
579 SERVER_START_REQ( get_key_value )
581 req->hkey = wine_server_obj_handle( handle );
582 wine_server_add_data( req, name->Buffer, name->Length );
583 if (length > fixed_size && data_ptr) wine_server_set_reply( req, data_ptr, length - fixed_size );
584 if (!(ret = wine_server_call( req )))
586 copy_key_value_info( info_class, info, length, reply->type,
587 name->Length, reply->total );
588 *result_len = fixed_size + (info_class == KeyValueBasicInformation ? 0 : reply->total);
589 if (length < min_size) ret = STATUS_BUFFER_TOO_SMALL;
590 else if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
593 SERVER_END_REQ;
594 return ret;
597 /******************************************************************************
598 * RtlpNtQueryValueKey [NTDLL.@]
601 NTSTATUS WINAPI RtlpNtQueryValueKey( HANDLE handle, ULONG *result_type, PBYTE dest,
602 DWORD *result_len, void *unknown )
604 KEY_VALUE_PARTIAL_INFORMATION *info;
605 UNICODE_STRING name;
606 NTSTATUS ret;
607 DWORD dwResultLen;
608 DWORD dwLen = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + (result_len ? *result_len : 0);
610 info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
611 if (!info)
612 return STATUS_NO_MEMORY;
614 name.Length = 0;
615 ret = NtQueryValueKey( handle, &name, KeyValuePartialInformation, info, dwLen, &dwResultLen );
617 if (!ret || ret == STATUS_BUFFER_OVERFLOW)
619 if (result_len)
620 *result_len = info->DataLength;
622 if (result_type)
623 *result_type = info->Type;
625 if (ret != STATUS_BUFFER_OVERFLOW)
626 memcpy( dest, info->Data, info->DataLength );
629 RtlFreeHeap( GetProcessHeap(), 0, info );
630 return ret;
633 /******************************************************************************
634 * NtFlushKey [NTDLL.@]
635 * ZwFlushKey [NTDLL.@]
637 NTSTATUS WINAPI NtFlushKey(HANDLE key)
639 NTSTATUS ret;
641 TRACE("key=%p\n", key);
643 SERVER_START_REQ( flush_key )
645 req->hkey = wine_server_obj_handle( key );
646 ret = wine_server_call( req );
648 SERVER_END_REQ;
650 return ret;
653 /******************************************************************************
654 * NtLoadKey [NTDLL.@]
655 * ZwLoadKey [NTDLL.@]
657 NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file )
659 NTSTATUS ret;
660 HANDLE hive;
661 IO_STATUS_BLOCK io;
662 data_size_t len;
663 struct object_attributes *objattr;
665 TRACE("(%p,%p)\n", attr, file);
667 ret = NtCreateFile(&hive, GENERIC_READ | SYNCHRONIZE, file, &io, NULL, FILE_ATTRIBUTE_NORMAL, 0,
668 FILE_OPEN, 0, NULL, 0);
669 if (ret) return ret;
671 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
673 SERVER_START_REQ( load_registry )
675 req->file = wine_server_obj_handle( hive );
676 wine_server_add_data( req, objattr, len );
677 ret = wine_server_call( req );
679 SERVER_END_REQ;
681 NtClose(hive);
682 RtlFreeHeap( GetProcessHeap(), 0, objattr );
683 return ret;
686 /******************************************************************************
687 * NtNotifyChangeMultipleKeys [NTDLL.@]
688 * ZwNotifyChangeMultipleKeys [NTDLL.@]
690 NTSTATUS WINAPI NtNotifyChangeMultipleKeys(
691 HANDLE KeyHandle,
692 ULONG Count,
693 OBJECT_ATTRIBUTES *SubordinateObjects,
694 HANDLE Event,
695 PIO_APC_ROUTINE ApcRoutine,
696 PVOID ApcContext,
697 PIO_STATUS_BLOCK IoStatusBlock,
698 ULONG CompletionFilter,
699 BOOLEAN WatchSubtree,
700 PVOID ChangeBuffer,
701 ULONG Length,
702 BOOLEAN Asynchronous)
704 NTSTATUS ret;
706 TRACE("(%p,%u,%p,%p,%p,%p,%p,0x%08x, 0x%08x,%p,0x%08x,0x%08x)\n",
707 KeyHandle, Count, SubordinateObjects, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
708 Asynchronous, ChangeBuffer, Length, WatchSubtree);
710 if (Count || SubordinateObjects || ApcRoutine || ApcContext || ChangeBuffer || Length)
711 FIXME("Unimplemented optional parameter\n");
713 if (!Asynchronous)
715 OBJECT_ATTRIBUTES attr;
716 InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
717 ret = NtCreateEvent( &Event, EVENT_ALL_ACCESS, &attr, SynchronizationEvent, FALSE );
718 if (ret != STATUS_SUCCESS)
719 return ret;
722 SERVER_START_REQ( set_registry_notification )
724 req->hkey = wine_server_obj_handle( KeyHandle );
725 req->event = wine_server_obj_handle( Event );
726 req->subtree = WatchSubtree;
727 req->filter = CompletionFilter;
728 ret = wine_server_call( req );
730 SERVER_END_REQ;
732 if (!Asynchronous)
734 if (ret == STATUS_PENDING)
735 ret = NtWaitForSingleObject( Event, FALSE, NULL );
736 NtClose( Event );
739 return ret;
742 /******************************************************************************
743 * NtNotifyChangeKey [NTDLL.@]
744 * ZwNotifyChangeKey [NTDLL.@]
746 NTSTATUS WINAPI NtNotifyChangeKey(
747 IN HANDLE KeyHandle,
748 IN HANDLE Event,
749 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
750 IN PVOID ApcContext OPTIONAL,
751 OUT PIO_STATUS_BLOCK IoStatusBlock,
752 IN ULONG CompletionFilter,
753 IN BOOLEAN WatchSubtree,
754 OUT PVOID ChangeBuffer,
755 IN ULONG Length,
756 IN BOOLEAN Asynchronous)
758 return NtNotifyChangeMultipleKeys(KeyHandle, 0, NULL, Event, ApcRoutine, ApcContext,
759 IoStatusBlock, CompletionFilter, WatchSubtree,
760 ChangeBuffer, Length, Asynchronous);
763 /******************************************************************************
764 * NtQueryMultipleValueKey [NTDLL]
765 * ZwQueryMultipleValueKey
768 NTSTATUS WINAPI NtQueryMultipleValueKey(
769 HANDLE KeyHandle,
770 PKEY_MULTIPLE_VALUE_INFORMATION ListOfValuesToQuery,
771 ULONG NumberOfItems,
772 PVOID MultipleValueInformation,
773 ULONG Length,
774 PULONG ReturnLength)
776 FIXME("(%p,%p,0x%08x,%p,0x%08x,%p) stub!\n",
777 KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
778 Length,ReturnLength);
779 return STATUS_SUCCESS;
782 /******************************************************************************
783 * NtReplaceKey [NTDLL.@]
784 * ZwReplaceKey [NTDLL.@]
786 NTSTATUS WINAPI NtReplaceKey(
787 IN POBJECT_ATTRIBUTES ObjectAttributes,
788 IN HANDLE Key,
789 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
791 FIXME("(%s,%p,%s),stub!\n", debugstr_ObjectAttributes(ObjectAttributes), Key,
792 debugstr_ObjectAttributes(ReplacedObjectAttributes) );
793 return STATUS_SUCCESS;
795 /******************************************************************************
796 * NtRestoreKey [NTDLL.@]
797 * ZwRestoreKey [NTDLL.@]
799 NTSTATUS WINAPI NtRestoreKey(
800 HANDLE KeyHandle,
801 HANDLE FileHandle,
802 ULONG RestoreFlags)
804 FIXME("(%p,%p,0x%08x) stub\n",
805 KeyHandle, FileHandle, RestoreFlags);
806 return STATUS_SUCCESS;
808 /******************************************************************************
809 * NtSaveKey [NTDLL.@]
810 * ZwSaveKey [NTDLL.@]
812 NTSTATUS WINAPI NtSaveKey(IN HANDLE KeyHandle, IN HANDLE FileHandle)
814 NTSTATUS ret;
816 TRACE("(%p,%p)\n", KeyHandle, FileHandle);
818 SERVER_START_REQ( save_registry )
820 req->hkey = wine_server_obj_handle( KeyHandle );
821 req->file = wine_server_obj_handle( FileHandle );
822 ret = wine_server_call( req );
824 SERVER_END_REQ;
826 return ret;
828 /******************************************************************************
829 * NtSetInformationKey [NTDLL.@]
830 * ZwSetInformationKey [NTDLL.@]
832 NTSTATUS WINAPI NtSetInformationKey(
833 IN HANDLE KeyHandle,
834 IN const int KeyInformationClass,
835 IN PVOID KeyInformation,
836 IN ULONG KeyInformationLength)
838 FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
839 KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
840 return STATUS_SUCCESS;
844 /******************************************************************************
845 * NtSetValueKey [NTDLL.@]
846 * ZwSetValueKey [NTDLL.@]
848 * NOTES
849 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
850 * NT does definitely care (aj)
852 NTSTATUS WINAPI NtSetValueKey( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
853 ULONG type, const void *data, ULONG count )
855 NTSTATUS ret;
857 TRACE( "(%p,%s,%d,%p,%d)\n", hkey, debugstr_us(name), type, data, count );
859 if (name->Length > MAX_VALUE_LENGTH) return STATUS_INVALID_PARAMETER;
861 SERVER_START_REQ( set_key_value )
863 req->hkey = wine_server_obj_handle( hkey );
864 req->type = type;
865 req->namelen = name->Length;
866 wine_server_add_data( req, name->Buffer, name->Length );
867 wine_server_add_data( req, data, count );
868 ret = wine_server_call( req );
870 SERVER_END_REQ;
871 return ret;
874 /******************************************************************************
875 * RtlpNtSetValueKey [NTDLL.@]
878 NTSTATUS WINAPI RtlpNtSetValueKey( HANDLE hkey, ULONG type, const void *data,
879 ULONG count )
881 UNICODE_STRING name;
883 name.Length = 0;
884 return NtSetValueKey( hkey, &name, 0, type, data, count );
887 /******************************************************************************
888 * NtUnloadKey [NTDLL.@]
889 * ZwUnloadKey [NTDLL.@]
891 NTSTATUS WINAPI NtUnloadKey(IN POBJECT_ATTRIBUTES attr)
893 NTSTATUS ret;
895 TRACE("(%p)\n", attr);
897 SERVER_START_REQ( unload_registry )
899 req->hkey = wine_server_obj_handle( attr->RootDirectory );
900 ret = wine_server_call(req);
902 SERVER_END_REQ;
904 return ret;
907 /******************************************************************************
908 * RtlFormatCurrentUserKeyPath [NTDLL.@]
911 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
913 static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
914 char buffer[sizeof(TOKEN_USER) + sizeof(SID) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES];
915 DWORD len = sizeof(buffer);
916 NTSTATUS status;
918 status = NtQueryInformationToken(GetCurrentThreadEffectiveToken(), TokenUser, buffer, len, &len);
919 if (status == STATUS_SUCCESS)
921 KeyPath->MaximumLength = 0;
922 status = RtlConvertSidToUnicodeString(KeyPath, ((TOKEN_USER *)buffer)->User.Sid, FALSE);
923 if (status == STATUS_BUFFER_OVERFLOW)
925 PWCHAR buf = RtlAllocateHeap(GetProcessHeap(), 0,
926 sizeof(pathW) + KeyPath->Length + sizeof(WCHAR));
927 if (buf)
929 memcpy(buf, pathW, sizeof(pathW));
930 KeyPath->MaximumLength = KeyPath->Length + sizeof(WCHAR);
931 KeyPath->Buffer = (PWCHAR)((LPBYTE)buf + sizeof(pathW));
932 status = RtlConvertSidToUnicodeString(KeyPath,
933 ((TOKEN_USER *)buffer)->User.Sid, FALSE);
934 KeyPath->Buffer = buf;
935 KeyPath->Length += sizeof(pathW);
936 KeyPath->MaximumLength += sizeof(pathW);
938 else
939 status = STATUS_NO_MEMORY;
942 return status;
945 /******************************************************************************
946 * RtlOpenCurrentUser [NTDLL.@]
948 * NOTES
949 * If we return just HKEY_CURRENT_USER the advapi tries to find a remote
950 * registry (odd handle) and fails.
952 NTSTATUS WINAPI RtlOpenCurrentUser(
953 IN ACCESS_MASK DesiredAccess, /* [in] */
954 OUT PHANDLE KeyHandle) /* [out] handle of HKEY_CURRENT_USER */
956 OBJECT_ATTRIBUTES ObjectAttributes;
957 UNICODE_STRING ObjectName;
958 NTSTATUS ret;
960 TRACE("(0x%08x, %p)\n",DesiredAccess, KeyHandle);
962 if ((ret = RtlFormatCurrentUserKeyPath(&ObjectName))) return ret;
963 InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
964 ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
965 RtlFreeUnicodeString(&ObjectName);
966 return ret;
970 static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
971 PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
973 PUNICODE_STRING str;
974 UNICODE_STRING src, dst;
975 LONG *bin;
976 ULONG offset;
977 PWSTR wstr;
978 DWORD res;
979 NTSTATUS status = STATUS_SUCCESS;
980 ULONG len;
981 LPWSTR String;
982 ULONG count = 0;
984 if (pInfo == NULL)
986 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
987 return STATUS_INVALID_PARAMETER;
988 else
990 status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
991 pQuery->DefaultLength, pContext, pQuery->EntryContext);
993 return status;
995 len = pInfo->DataLength;
997 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
999 str = pQuery->EntryContext;
1001 switch(pInfo->Type)
1003 case REG_EXPAND_SZ:
1004 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
1006 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1007 res = 0;
1008 dst.MaximumLength = 0;
1009 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1010 dst.Length = 0;
1011 dst.MaximumLength = res;
1012 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1013 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1014 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1015 dst.Length, pContext, pQuery->EntryContext);
1016 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1019 case REG_SZ:
1020 case REG_LINK:
1021 if (str->Buffer == NULL)
1022 RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1023 else
1024 RtlAppendUnicodeToString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1025 break;
1027 case REG_MULTI_SZ:
1028 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
1029 return STATUS_INVALID_PARAMETER;
1031 if (str->Buffer == NULL)
1033 str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1034 str->MaximumLength = len;
1036 len = min(len, str->MaximumLength);
1037 memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
1038 str->Length = len;
1039 break;
1041 default:
1042 bin = pQuery->EntryContext;
1043 if (pInfo->DataLength <= sizeof(ULONG))
1044 memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
1045 pInfo->DataLength);
1046 else
1048 if (bin[0] <= sizeof(ULONG))
1050 memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
1051 min(-bin[0], pInfo->DataLength));
1053 else
1055 len = min(bin[0], pInfo->DataLength);
1056 bin[1] = len;
1057 bin[2] = pInfo->Type;
1058 memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
1061 break;
1064 else
1066 if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
1067 (pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
1069 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type,
1070 ((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
1071 pContext, pQuery->EntryContext);
1073 else if (pInfo->Type == REG_EXPAND_SZ)
1075 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1076 res = 0;
1077 dst.MaximumLength = 0;
1078 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1079 dst.Length = 0;
1080 dst.MaximumLength = res;
1081 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1082 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1083 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1084 dst.Length, pContext, pQuery->EntryContext);
1085 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1087 else /* REG_MULTI_SZ */
1089 if(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
1091 for (offset = 0; offset <= pInfo->DataLength; offset += len + sizeof(WCHAR))
1093 wstr = (WCHAR*)(((CHAR*)pInfo) + offset);
1094 len = strlenW(wstr) * sizeof(WCHAR);
1095 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, wstr, len,
1096 pContext, pQuery->EntryContext);
1097 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1098 return status;
1101 else
1103 while(count<=pInfo->DataLength)
1105 String = (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset)+count;
1106 count+=strlenW(String)+1;
1107 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1108 res = 0;
1109 dst.MaximumLength = 0;
1110 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1111 dst.Length = 0;
1112 dst.MaximumLength = res;
1113 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1114 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1115 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1116 dst.Length, pContext, pQuery->EntryContext);
1117 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1118 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1119 return status;
1124 return status;
1128 static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
1130 UNICODE_STRING KeyString;
1131 OBJECT_ATTRIBUTES regkey;
1132 PCWSTR base;
1133 INT len;
1134 NTSTATUS status;
1136 static const WCHAR empty[] = {0};
1137 static const WCHAR control[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1138 '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1139 'C','o','n','t','r','o','l','\\',0};
1141 static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1142 'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1144 static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1145 'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1146 'S','e','r','v','i','c','e','s','\\',0};
1148 static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1149 'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1151 static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1152 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1153 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1155 switch (RelativeTo & 0xff)
1157 case RTL_REGISTRY_ABSOLUTE:
1158 base = empty;
1159 break;
1161 case RTL_REGISTRY_CONTROL:
1162 base = control;
1163 break;
1165 case RTL_REGISTRY_DEVICEMAP:
1166 base = devicemap;
1167 break;
1169 case RTL_REGISTRY_SERVICES:
1170 base = services;
1171 break;
1173 case RTL_REGISTRY_USER:
1174 base = user;
1175 break;
1177 case RTL_REGISTRY_WINDOWS_NT:
1178 base = windows_nt;
1179 break;
1181 default:
1182 return STATUS_INVALID_PARAMETER;
1185 len = (strlenW(base) + strlenW(Path) + 1) * sizeof(WCHAR);
1186 KeyString.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1187 if (KeyString.Buffer == NULL)
1188 return STATUS_NO_MEMORY;
1190 strcpyW(KeyString.Buffer, base);
1191 strcatW(KeyString.Buffer, Path);
1192 KeyString.Length = len - sizeof(WCHAR);
1193 KeyString.MaximumLength = len;
1194 InitializeObjectAttributes(&regkey, &KeyString, OBJ_CASE_INSENSITIVE, NULL, NULL);
1195 status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
1196 RtlFreeHeap(GetProcessHeap(), 0, KeyString.Buffer);
1197 return status;
1200 /*************************************************************************
1201 * RtlQueryRegistryValues [NTDLL.@]
1203 * Query multiple registry values with a single call.
1205 * PARAMS
1206 * RelativeTo [I] Registry path that Path refers to
1207 * Path [I] Path to key
1208 * QueryTable [I] Table of key values to query
1209 * Context [I] Parameter to pass to the application defined QueryRoutine function
1210 * Environment [I] Optional parameter to use when performing expansion
1212 * RETURNS
1213 * STATUS_SUCCESS or an appropriate NTSTATUS error code.
1215 NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
1216 IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
1217 IN PVOID Environment OPTIONAL)
1219 UNICODE_STRING Value;
1220 HANDLE handle, topkey;
1221 PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
1222 ULONG len, buflen = 0;
1223 NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
1224 INT i;
1226 TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
1228 if(Path == NULL)
1229 return STATUS_INVALID_PARAMETER;
1231 /* get a valid handle */
1232 if (RelativeTo & RTL_REGISTRY_HANDLE)
1233 topkey = handle = (HANDLE)Path;
1234 else
1236 status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
1237 handle = topkey;
1239 if(status != STATUS_SUCCESS)
1240 return status;
1242 /* Process query table entries */
1243 for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
1245 if (QueryTable->Flags &
1246 (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
1248 /* topkey must be kept open just in case we will reuse it later */
1249 if (handle != topkey)
1250 NtClose(handle);
1252 if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
1254 handle = 0;
1255 status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
1256 if(status != STATUS_SUCCESS)
1258 ret = status;
1259 goto out;
1262 else
1263 handle = topkey;
1266 if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
1268 QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
1269 Context, QueryTable->EntryContext);
1270 continue;
1273 if (!handle)
1275 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1277 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1278 goto out;
1280 continue;
1283 if (QueryTable->Name == NULL)
1285 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
1287 ret = STATUS_INVALID_PARAMETER;
1288 goto out;
1291 /* Report all subkeys */
1292 for (i = 0;; ++i)
1294 status = NtEnumerateValueKey(handle, i,
1295 KeyValueFullInformation, pInfo, buflen, &len);
1296 if (status == STATUS_NO_MORE_ENTRIES)
1297 break;
1298 if (status == STATUS_BUFFER_OVERFLOW ||
1299 status == STATUS_BUFFER_TOO_SMALL)
1301 buflen = len;
1302 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1303 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1304 NtEnumerateValueKey(handle, i, KeyValueFullInformation,
1305 pInfo, buflen, &len);
1308 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1309 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1311 ret = status;
1312 goto out;
1314 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1316 RtlInitUnicodeString(&Value, pInfo->Name);
1317 NtDeleteValueKey(handle, &Value);
1321 if (i == 0 && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
1323 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1324 goto out;
1327 else
1329 RtlInitUnicodeString(&Value, QueryTable->Name);
1330 status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
1331 pInfo, buflen, &len);
1332 if (status == STATUS_BUFFER_OVERFLOW ||
1333 status == STATUS_BUFFER_TOO_SMALL)
1335 buflen = len;
1336 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1337 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1338 status = NtQueryValueKey(handle, &Value,
1339 KeyValueFullInformation, pInfo, buflen, &len);
1341 if (status != STATUS_SUCCESS)
1343 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1345 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1346 goto out;
1348 status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
1349 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1351 ret = status;
1352 goto out;
1355 else
1357 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1358 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1360 ret = status;
1361 goto out;
1363 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1364 NtDeleteValueKey(handle, &Value);
1369 out:
1370 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1371 if (handle != topkey)
1372 NtClose(handle);
1373 NtClose(topkey);
1374 return ret;
1377 /*************************************************************************
1378 * RtlCheckRegistryKey [NTDLL.@]
1380 * Query multiple registry values with a single call.
1382 * PARAMS
1383 * RelativeTo [I] Registry path that Path refers to
1384 * Path [I] Path to key
1386 * RETURNS
1387 * STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1389 NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
1391 HANDLE handle;
1392 NTSTATUS status;
1394 TRACE("(%d, %s)\n", RelativeTo, debugstr_w(Path));
1396 if((!RelativeTo) && Path == NULL)
1397 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1398 if(RelativeTo & RTL_REGISTRY_HANDLE)
1399 return STATUS_SUCCESS;
1401 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1402 if (handle) NtClose(handle);
1403 if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
1404 return status;
1407 /*************************************************************************
1408 * RtlDeleteRegistryValue [NTDLL.@]
1410 * Query multiple registry values with a single call.
1412 * PARAMS
1413 * RelativeTo [I] Registry path that Path refers to
1414 * Path [I] Path to key
1415 * ValueName [I] Name of the value to delete
1417 * RETURNS
1418 * STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1420 NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
1422 NTSTATUS status;
1423 HANDLE handle;
1424 UNICODE_STRING Value;
1426 TRACE("(%d, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
1428 RtlInitUnicodeString(&Value, ValueName);
1429 if(RelativeTo == RTL_REGISTRY_HANDLE)
1431 return NtDeleteValueKey((HANDLE)Path, &Value);
1433 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1434 if (status) return status;
1435 status = NtDeleteValueKey(handle, &Value);
1436 NtClose(handle);
1437 return status;
1440 /*************************************************************************
1441 * RtlWriteRegistryValue [NTDLL.@]
1443 * Sets the registry value with provided data.
1445 * PARAMS
1446 * RelativeTo [I] Registry path that path parameter refers to
1447 * path [I] Path to the key (or handle - see RTL_GetKeyHandle)
1448 * name [I] Name of the registry value to set
1449 * type [I] Type of the registry key to set
1450 * data [I] Pointer to the user data to be set
1451 * length [I] Length of the user data pointed by data
1453 * RETURNS
1454 * STATUS_SUCCESS if the specified key is successfully set,
1455 * or an NTSTATUS error code.
1457 NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
1458 ULONG type, PVOID data, ULONG length )
1460 HANDLE hkey;
1461 NTSTATUS status;
1462 UNICODE_STRING str;
1464 TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
1465 type, data, length );
1467 RtlInitUnicodeString( &str, name );
1469 if (RelativeTo == RTL_REGISTRY_HANDLE)
1470 return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
1472 status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
1473 if (status != STATUS_SUCCESS) return status;
1475 status = NtSetValueKey( hkey, &str, 0, type, data, length );
1476 NtClose( hkey );
1478 return status;
1481 /*************************************************************************
1482 * NtQueryLicenseValue [NTDLL.@]
1484 * NOTES
1485 * On Windows all license properties are stored in a single key, but
1486 * unless there is some app which explicitly depends on that, there is
1487 * no good reason to reproduce that.
1489 NTSTATUS WINAPI NtQueryLicenseValue( const UNICODE_STRING *name, ULONG *result_type,
1490 PVOID data, ULONG length, ULONG *result_len )
1492 static const WCHAR LicenseInformationW[] = {'M','a','c','h','i','n','e','\\',
1493 'S','o','f','t','w','a','r','e','\\',
1494 'W','i','n','e','\\','L','i','c','e','n','s','e',
1495 'I','n','f','o','r','m','a','t','i','o','n',0};
1496 KEY_VALUE_PARTIAL_INFORMATION *info;
1497 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
1498 DWORD info_length, count;
1499 OBJECT_ATTRIBUTES attr;
1500 UNICODE_STRING keyW;
1501 HANDLE hkey;
1503 if (!name || !name->Buffer || !name->Length || !result_len)
1504 return STATUS_INVALID_PARAMETER;
1506 info_length = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + length;
1507 info = RtlAllocateHeap( GetProcessHeap(), 0, info_length );
1508 if (!info) return STATUS_NO_MEMORY;
1510 attr.Length = sizeof(attr);
1511 attr.RootDirectory = 0;
1512 attr.ObjectName = &keyW;
1513 attr.Attributes = 0;
1514 attr.SecurityDescriptor = NULL;
1515 attr.SecurityQualityOfService = NULL;
1516 RtlInitUnicodeString( &keyW, LicenseInformationW );
1518 /* @@ Wine registry key: HKLM\Software\Wine\LicenseInformation */
1519 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
1521 status = NtQueryValueKey( hkey, name, KeyValuePartialInformation,
1522 info, info_length, &count );
1523 if (!status || status == STATUS_BUFFER_OVERFLOW)
1525 if (result_type)
1526 *result_type = info->Type;
1528 *result_len = info->DataLength;
1530 if (status == STATUS_BUFFER_OVERFLOW)
1531 status = STATUS_BUFFER_TOO_SMALL;
1532 else
1533 memcpy( data, info->Data, info->DataLength );
1535 NtClose( hkey );
1538 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1539 FIXME( "License key %s not found\n", debugstr_w(name->Buffer) );
1541 RtlFreeHeap( GetProcessHeap(), 0, info );
1542 return status;