user32/tests: Use wine_dbgstr_rect() to print RECTs.
[wine.git] / dlls / ntdll / reg.c
blob8af21819ef61163c222ada530f200247155a9f57
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 HANDLE token;
915 NTSTATUS status;
917 status = NtOpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &token);
918 if (status == STATUS_NO_TOKEN)
919 status = NtOpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token);
920 if (status == STATUS_SUCCESS)
922 char buffer[sizeof(TOKEN_USER) + sizeof(SID) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES];
923 DWORD len = sizeof(buffer);
925 status = NtQueryInformationToken(token, TokenUser, buffer, len, &len);
926 if (status == STATUS_SUCCESS)
928 KeyPath->MaximumLength = 0;
929 status = RtlConvertSidToUnicodeString(KeyPath, ((TOKEN_USER *)buffer)->User.Sid, FALSE);
930 if (status == STATUS_BUFFER_OVERFLOW)
932 PWCHAR buf = RtlAllocateHeap(GetProcessHeap(), 0,
933 sizeof(pathW) + KeyPath->Length + sizeof(WCHAR));
934 if (buf)
936 memcpy(buf, pathW, sizeof(pathW));
937 KeyPath->MaximumLength = KeyPath->Length + sizeof(WCHAR);
938 KeyPath->Buffer = (PWCHAR)((LPBYTE)buf + sizeof(pathW));
939 status = RtlConvertSidToUnicodeString(KeyPath,
940 ((TOKEN_USER *)buffer)->User.Sid, FALSE);
941 KeyPath->Buffer = buf;
942 KeyPath->Length += sizeof(pathW);
943 KeyPath->MaximumLength += sizeof(pathW);
945 else
946 status = STATUS_NO_MEMORY;
949 NtClose(token);
951 return status;
954 /******************************************************************************
955 * RtlOpenCurrentUser [NTDLL.@]
957 * NOTES
958 * If we return just HKEY_CURRENT_USER the advapi tries to find a remote
959 * registry (odd handle) and fails.
961 NTSTATUS WINAPI RtlOpenCurrentUser(
962 IN ACCESS_MASK DesiredAccess, /* [in] */
963 OUT PHANDLE KeyHandle) /* [out] handle of HKEY_CURRENT_USER */
965 OBJECT_ATTRIBUTES ObjectAttributes;
966 UNICODE_STRING ObjectName;
967 NTSTATUS ret;
969 TRACE("(0x%08x, %p)\n",DesiredAccess, KeyHandle);
971 if ((ret = RtlFormatCurrentUserKeyPath(&ObjectName))) return ret;
972 InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
973 ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
974 RtlFreeUnicodeString(&ObjectName);
975 return ret;
979 static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
980 PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
982 PUNICODE_STRING str;
983 UNICODE_STRING src, dst;
984 LONG *bin;
985 ULONG offset;
986 PWSTR wstr;
987 DWORD res;
988 NTSTATUS status = STATUS_SUCCESS;
989 ULONG len;
990 LPWSTR String;
991 ULONG count = 0;
993 if (pInfo == NULL)
995 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
996 return STATUS_INVALID_PARAMETER;
997 else
999 status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
1000 pQuery->DefaultLength, pContext, pQuery->EntryContext);
1002 return status;
1004 len = pInfo->DataLength;
1006 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
1008 str = pQuery->EntryContext;
1010 switch(pInfo->Type)
1012 case REG_EXPAND_SZ:
1013 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
1015 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1016 res = 0;
1017 dst.MaximumLength = 0;
1018 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1019 dst.Length = 0;
1020 dst.MaximumLength = res;
1021 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1022 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1023 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1024 dst.Length, pContext, pQuery->EntryContext);
1025 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1028 case REG_SZ:
1029 case REG_LINK:
1030 if (str->Buffer == NULL)
1031 RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1032 else
1033 RtlAppendUnicodeToString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1034 break;
1036 case REG_MULTI_SZ:
1037 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
1038 return STATUS_INVALID_PARAMETER;
1040 if (str->Buffer == NULL)
1042 str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1043 str->MaximumLength = len;
1045 len = min(len, str->MaximumLength);
1046 memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
1047 str->Length = len;
1048 break;
1050 default:
1051 bin = pQuery->EntryContext;
1052 if (pInfo->DataLength <= sizeof(ULONG))
1053 memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
1054 pInfo->DataLength);
1055 else
1057 if (bin[0] <= sizeof(ULONG))
1059 memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
1060 min(-bin[0], pInfo->DataLength));
1062 else
1064 len = min(bin[0], pInfo->DataLength);
1065 bin[1] = len;
1066 bin[2] = pInfo->Type;
1067 memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
1070 break;
1073 else
1075 if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
1076 (pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
1078 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type,
1079 ((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
1080 pContext, pQuery->EntryContext);
1082 else if (pInfo->Type == REG_EXPAND_SZ)
1084 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1085 res = 0;
1086 dst.MaximumLength = 0;
1087 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1088 dst.Length = 0;
1089 dst.MaximumLength = res;
1090 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1091 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1092 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1093 dst.Length, pContext, pQuery->EntryContext);
1094 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1096 else /* REG_MULTI_SZ */
1098 if(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
1100 for (offset = 0; offset <= pInfo->DataLength; offset += len + sizeof(WCHAR))
1102 wstr = (WCHAR*)(((CHAR*)pInfo) + offset);
1103 len = strlenW(wstr) * sizeof(WCHAR);
1104 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, wstr, len,
1105 pContext, pQuery->EntryContext);
1106 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1107 return status;
1110 else
1112 while(count<=pInfo->DataLength)
1114 String = (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset)+count;
1115 count+=strlenW(String)+1;
1116 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1117 res = 0;
1118 dst.MaximumLength = 0;
1119 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1120 dst.Length = 0;
1121 dst.MaximumLength = res;
1122 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1123 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1124 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1125 dst.Length, pContext, pQuery->EntryContext);
1126 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1127 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1128 return status;
1133 return status;
1137 static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
1139 UNICODE_STRING KeyString;
1140 OBJECT_ATTRIBUTES regkey;
1141 PCWSTR base;
1142 INT len;
1143 NTSTATUS status;
1145 static const WCHAR empty[] = {0};
1146 static const WCHAR control[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1147 '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1148 'C','o','n','t','r','o','l','\\',0};
1150 static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1151 'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1153 static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1154 'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1155 'S','e','r','v','i','c','e','s','\\',0};
1157 static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1158 'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1160 static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1161 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1162 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1164 switch (RelativeTo & 0xff)
1166 case RTL_REGISTRY_ABSOLUTE:
1167 base = empty;
1168 break;
1170 case RTL_REGISTRY_CONTROL:
1171 base = control;
1172 break;
1174 case RTL_REGISTRY_DEVICEMAP:
1175 base = devicemap;
1176 break;
1178 case RTL_REGISTRY_SERVICES:
1179 base = services;
1180 break;
1182 case RTL_REGISTRY_USER:
1183 base = user;
1184 break;
1186 case RTL_REGISTRY_WINDOWS_NT:
1187 base = windows_nt;
1188 break;
1190 default:
1191 return STATUS_INVALID_PARAMETER;
1194 len = (strlenW(base) + strlenW(Path) + 1) * sizeof(WCHAR);
1195 KeyString.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1196 if (KeyString.Buffer == NULL)
1197 return STATUS_NO_MEMORY;
1199 strcpyW(KeyString.Buffer, base);
1200 strcatW(KeyString.Buffer, Path);
1201 KeyString.Length = len - sizeof(WCHAR);
1202 KeyString.MaximumLength = len;
1203 InitializeObjectAttributes(&regkey, &KeyString, OBJ_CASE_INSENSITIVE, NULL, NULL);
1204 status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
1205 RtlFreeHeap(GetProcessHeap(), 0, KeyString.Buffer);
1206 return status;
1209 /*************************************************************************
1210 * RtlQueryRegistryValues [NTDLL.@]
1212 * Query multiple registry values with a signle call.
1214 * PARAMS
1215 * RelativeTo [I] Registry path that Path refers to
1216 * Path [I] Path to key
1217 * QueryTable [I] Table of key values to query
1218 * Context [I] Parameter to pass to the application defined QueryRoutine function
1219 * Environment [I] Optional parameter to use when performing expansion
1221 * RETURNS
1222 * STATUS_SUCCESS or an appropriate NTSTATUS error code.
1224 NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
1225 IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
1226 IN PVOID Environment OPTIONAL)
1228 UNICODE_STRING Value;
1229 HANDLE handle, topkey;
1230 PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
1231 ULONG len, buflen = 0;
1232 NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
1233 INT i;
1235 TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
1237 if(Path == NULL)
1238 return STATUS_INVALID_PARAMETER;
1240 /* get a valid handle */
1241 if (RelativeTo & RTL_REGISTRY_HANDLE)
1242 topkey = handle = (HANDLE)Path;
1243 else
1245 status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
1246 handle = topkey;
1248 if(status != STATUS_SUCCESS)
1249 return status;
1251 /* Process query table entries */
1252 for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
1254 if (QueryTable->Flags &
1255 (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
1257 /* topkey must be kept open just in case we will reuse it later */
1258 if (handle != topkey)
1259 NtClose(handle);
1261 if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
1263 handle = 0;
1264 status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
1265 if(status != STATUS_SUCCESS)
1267 ret = status;
1268 goto out;
1271 else
1272 handle = topkey;
1275 if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
1277 QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
1278 Context, QueryTable->EntryContext);
1279 continue;
1282 if (!handle)
1284 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1286 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1287 goto out;
1289 continue;
1292 if (QueryTable->Name == NULL)
1294 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
1296 ret = STATUS_INVALID_PARAMETER;
1297 goto out;
1300 /* Report all subkeys */
1301 for (i = 0;; ++i)
1303 status = NtEnumerateValueKey(handle, i,
1304 KeyValueFullInformation, pInfo, buflen, &len);
1305 if (status == STATUS_NO_MORE_ENTRIES)
1306 break;
1307 if (status == STATUS_BUFFER_OVERFLOW ||
1308 status == STATUS_BUFFER_TOO_SMALL)
1310 buflen = len;
1311 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1312 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1313 NtEnumerateValueKey(handle, i, KeyValueFullInformation,
1314 pInfo, buflen, &len);
1317 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1318 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1320 ret = status;
1321 goto out;
1323 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1325 RtlInitUnicodeString(&Value, pInfo->Name);
1326 NtDeleteValueKey(handle, &Value);
1330 if (i == 0 && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
1332 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1333 goto out;
1336 else
1338 RtlInitUnicodeString(&Value, QueryTable->Name);
1339 status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
1340 pInfo, buflen, &len);
1341 if (status == STATUS_BUFFER_OVERFLOW ||
1342 status == STATUS_BUFFER_TOO_SMALL)
1344 buflen = len;
1345 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1346 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1347 status = NtQueryValueKey(handle, &Value,
1348 KeyValueFullInformation, pInfo, buflen, &len);
1350 if (status != STATUS_SUCCESS)
1352 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1354 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1355 goto out;
1357 status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
1358 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1360 ret = status;
1361 goto out;
1364 else
1366 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1367 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1369 ret = status;
1370 goto out;
1372 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1373 NtDeleteValueKey(handle, &Value);
1378 out:
1379 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1380 if (handle != topkey)
1381 NtClose(handle);
1382 NtClose(topkey);
1383 return ret;
1386 /*************************************************************************
1387 * RtlCheckRegistryKey [NTDLL.@]
1389 * Query multiple registry values with a signle call.
1391 * PARAMS
1392 * RelativeTo [I] Registry path that Path refers to
1393 * Path [I] Path to key
1395 * RETURNS
1396 * STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1398 NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
1400 HANDLE handle;
1401 NTSTATUS status;
1403 TRACE("(%d, %s)\n", RelativeTo, debugstr_w(Path));
1405 if((!RelativeTo) && Path == NULL)
1406 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1407 if(RelativeTo & RTL_REGISTRY_HANDLE)
1408 return STATUS_SUCCESS;
1410 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1411 if (handle) NtClose(handle);
1412 if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
1413 return status;
1416 /*************************************************************************
1417 * RtlDeleteRegistryValue [NTDLL.@]
1419 * Query multiple registry values with a signle call.
1421 * PARAMS
1422 * RelativeTo [I] Registry path that Path refers to
1423 * Path [I] Path to key
1424 * ValueName [I] Name of the value to delete
1426 * RETURNS
1427 * STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1429 NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
1431 NTSTATUS status;
1432 HANDLE handle;
1433 UNICODE_STRING Value;
1435 TRACE("(%d, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
1437 RtlInitUnicodeString(&Value, ValueName);
1438 if(RelativeTo == RTL_REGISTRY_HANDLE)
1440 return NtDeleteValueKey((HANDLE)Path, &Value);
1442 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1443 if (status) return status;
1444 status = NtDeleteValueKey(handle, &Value);
1445 NtClose(handle);
1446 return status;
1449 /*************************************************************************
1450 * RtlWriteRegistryValue [NTDLL.@]
1452 * Sets the registry value with provided data.
1454 * PARAMS
1455 * RelativeTo [I] Registry path that path parameter refers to
1456 * path [I] Path to the key (or handle - see RTL_GetKeyHandle)
1457 * name [I] Name of the registry value to set
1458 * type [I] Type of the registry key to set
1459 * data [I] Pointer to the user data to be set
1460 * length [I] Length of the user data pointed by data
1462 * RETURNS
1463 * STATUS_SUCCESS if the specified key is successfully set,
1464 * or an NTSTATUS error code.
1466 NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
1467 ULONG type, PVOID data, ULONG length )
1469 HANDLE hkey;
1470 NTSTATUS status;
1471 UNICODE_STRING str;
1473 TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
1474 type, data, length );
1476 RtlInitUnicodeString( &str, name );
1478 if (RelativeTo == RTL_REGISTRY_HANDLE)
1479 return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
1481 status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
1482 if (status != STATUS_SUCCESS) return status;
1484 status = NtSetValueKey( hkey, &str, 0, type, data, length );
1485 NtClose( hkey );
1487 return status;
1490 /*************************************************************************
1491 * NtQueryLicenseValue [NTDLL.@]
1493 * NOTES
1494 * On Windows all license properties are stored in a single key, but
1495 * unless there is some app which explicitly depends on that, there is
1496 * no good reason to reproduce that.
1498 NTSTATUS WINAPI NtQueryLicenseValue( const UNICODE_STRING *name, ULONG *result_type,
1499 PVOID data, ULONG length, ULONG *result_len )
1501 static const WCHAR LicenseInformationW[] = {'M','a','c','h','i','n','e','\\',
1502 'S','o','f','t','w','a','r','e','\\',
1503 'W','i','n','e','\\','L','i','c','e','n','s','e',
1504 'I','n','f','o','r','m','a','t','i','o','n',0};
1505 KEY_VALUE_PARTIAL_INFORMATION *info;
1506 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
1507 DWORD info_length, count;
1508 OBJECT_ATTRIBUTES attr;
1509 UNICODE_STRING keyW;
1510 HANDLE hkey;
1512 if (!name || !name->Buffer || !name->Length || !result_len)
1513 return STATUS_INVALID_PARAMETER;
1515 info_length = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + length;
1516 info = RtlAllocateHeap( GetProcessHeap(), 0, info_length );
1517 if (!info) return STATUS_NO_MEMORY;
1519 attr.Length = sizeof(attr);
1520 attr.RootDirectory = 0;
1521 attr.ObjectName = &keyW;
1522 attr.Attributes = 0;
1523 attr.SecurityDescriptor = NULL;
1524 attr.SecurityQualityOfService = NULL;
1525 RtlInitUnicodeString( &keyW, LicenseInformationW );
1527 /* @@ Wine registry key: HKLM\Software\Wine\LicenseInformation */
1528 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
1530 status = NtQueryValueKey( hkey, name, KeyValuePartialInformation,
1531 info, info_length, &count );
1532 if (!status || status == STATUS_BUFFER_OVERFLOW)
1534 if (result_type)
1535 *result_type = info->Type;
1537 *result_len = info->DataLength;
1539 if (status == STATUS_BUFFER_OVERFLOW)
1540 status = STATUS_BUFFER_TOO_SMALL;
1541 else
1542 memcpy( data, info->Data, info->DataLength );
1544 NtClose( hkey );
1547 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1548 FIXME( "License key %s not found\n", debugstr_w(name->Buffer) );
1550 RtlFreeHeap( GetProcessHeap(), 0, info );
1551 return status;