storage.dll16: Fix get_nth_next_small_blocknr.
[wine.git] / dlls / ntdll / reg.c
blob2dd75bea3a978d7c4900a32550bf7a2bfa6848c8
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 ret = wine_server_call( req );
75 *retkey = wine_server_ptr_handle( reply->hkey );
76 if (dispos && !ret) *dispos = reply->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
78 SERVER_END_REQ;
80 TRACE("<- %p\n", *retkey);
81 RtlFreeHeap( GetProcessHeap(), 0, objattr );
82 return ret;
85 NTSTATUS WINAPI NtCreateKeyTransacted( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
86 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
87 HANDLE transacted, ULONG *dispos )
89 FIXME( "(%p,%s,%s,%x,%x,%p,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
90 debugstr_us(class), options, access, transacted, retkey );
91 return STATUS_NOT_IMPLEMENTED;
94 NTSTATUS WINAPI NtRenameKey( HANDLE handle, UNICODE_STRING *name )
96 FIXME( "(%p %s)\n", handle, debugstr_us(name) );
97 return STATUS_NOT_IMPLEMENTED;
100 /******************************************************************************
101 * RtlpNtCreateKey [NTDLL.@]
103 * See NtCreateKey.
105 NTSTATUS WINAPI RtlpNtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
106 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
107 PULONG dispos )
109 OBJECT_ATTRIBUTES oa;
111 if (attr)
113 oa = *attr;
114 oa.Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
115 attr = &oa;
118 return NtCreateKey(retkey, access, attr, 0, NULL, 0, dispos);
121 static NTSTATUS open_key( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, ULONG options )
123 NTSTATUS ret;
125 if (!retkey || !attr || !attr->ObjectName) return STATUS_ACCESS_VIOLATION;
126 if ((ret = validate_open_object_attributes( attr ))) return ret;
128 TRACE( "(%p,%s,%x,%p)\n", attr->RootDirectory,
129 debugstr_us(attr->ObjectName), access, retkey );
130 if (options & ~REG_OPTION_OPEN_LINK)
131 FIXME("options %x not implemented\n", options);
133 SERVER_START_REQ( open_key )
135 req->parent = wine_server_obj_handle( attr->RootDirectory );
136 req->access = access;
137 req->attributes = attr->Attributes;
138 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
139 ret = wine_server_call( req );
140 *retkey = wine_server_ptr_handle( reply->hkey );
142 SERVER_END_REQ;
143 TRACE("<- %p\n", *retkey);
144 return ret;
147 /******************************************************************************
148 * NtOpenKeyEx [NTDLL.@]
149 * ZwOpenKeyEx [NTDLL.@]
151 NTSTATUS WINAPI NtOpenKeyEx( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, ULONG options )
153 return open_key( retkey, access, attr, options );
156 /******************************************************************************
157 * NtOpenKey [NTDLL.@]
158 * ZwOpenKey [NTDLL.@]
160 * OUT HANDLE retkey (returns 0 when failure)
161 * IN ACCESS_MASK access
162 * IN POBJECT_ATTRIBUTES attr
164 NTSTATUS WINAPI NtOpenKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
166 return open_key( retkey, access, attr, 0 );
169 NTSTATUS WINAPI NtOpenKeyTransactedEx( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
170 ULONG options, HANDLE transaction )
172 FIXME( "(%p %x %p %x %p)\n", retkey, access, attr, options, transaction );
173 return STATUS_NOT_IMPLEMENTED;
176 NTSTATUS WINAPI NtOpenKeyTransacted( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
177 HANDLE transaction )
179 return NtOpenKeyTransactedEx( retkey, access, attr, 0, transaction );
182 /******************************************************************************
183 * RtlpNtOpenKey [NTDLL.@]
185 * See NtOpenKey.
187 NTSTATUS WINAPI RtlpNtOpenKey( PHANDLE retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
189 if (attr)
190 attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
191 return NtOpenKey(retkey, access, attr);
194 /******************************************************************************
195 * NtDeleteKey [NTDLL.@]
196 * ZwDeleteKey [NTDLL.@]
198 NTSTATUS WINAPI NtDeleteKey( HANDLE hkey )
200 NTSTATUS ret;
202 TRACE( "(%p)\n", hkey );
204 SERVER_START_REQ( delete_key )
206 req->hkey = wine_server_obj_handle( hkey );
207 ret = wine_server_call( req );
209 SERVER_END_REQ;
210 return ret;
213 /******************************************************************************
214 * RtlpNtMakeTemporaryKey [NTDLL.@]
216 * See NtDeleteKey.
218 NTSTATUS WINAPI RtlpNtMakeTemporaryKey( HANDLE hkey )
220 return NtDeleteKey(hkey);
223 /******************************************************************************
224 * NtDeleteValueKey [NTDLL.@]
225 * ZwDeleteValueKey [NTDLL.@]
227 NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name )
229 NTSTATUS ret;
231 TRACE( "(%p,%s)\n", hkey, debugstr_us(name) );
232 if (name->Length > MAX_VALUE_LENGTH) return STATUS_OBJECT_NAME_NOT_FOUND;
234 SERVER_START_REQ( delete_key_value )
236 req->hkey = wine_server_obj_handle( hkey );
237 wine_server_add_data( req, name->Buffer, name->Length );
238 ret = wine_server_call( req );
240 SERVER_END_REQ;
241 return ret;
245 /******************************************************************************
246 * enumerate_key
248 * Implementation of NtQueryKey and NtEnumerateKey
250 static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS info_class,
251 void *info, DWORD length, DWORD *result_len )
254 NTSTATUS ret;
255 void *data_ptr;
256 size_t fixed_size;
258 switch(info_class)
260 case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break;
261 case KeyFullInformation: data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
262 case KeyNodeInformation: data_ptr = ((KEY_NODE_INFORMATION *)info)->Name; break;
263 case KeyNameInformation: data_ptr = ((KEY_NAME_INFORMATION *)info)->Name; break;
264 case KeyCachedInformation: data_ptr = ((KEY_CACHED_INFORMATION *)info)+1; break;
265 default:
266 FIXME( "Information class %d not implemented\n", info_class );
267 return STATUS_INVALID_PARAMETER;
269 fixed_size = (char *)data_ptr - (char *)info;
271 SERVER_START_REQ( enum_key )
273 req->hkey = wine_server_obj_handle( handle );
274 req->index = index;
275 req->info_class = info_class;
276 if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
277 if (!(ret = wine_server_call( req )))
279 switch(info_class)
281 case KeyBasicInformation:
283 KEY_BASIC_INFORMATION keyinfo;
284 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
285 keyinfo.LastWriteTime.QuadPart = reply->modif;
286 keyinfo.TitleIndex = 0;
287 keyinfo.NameLength = reply->namelen;
288 memcpy( info, &keyinfo, min( length, fixed_size ) );
290 break;
291 case KeyFullInformation:
293 KEY_FULL_INFORMATION keyinfo;
294 fixed_size = (char *)keyinfo.Class - (char *)&keyinfo;
295 keyinfo.LastWriteTime.QuadPart = reply->modif;
296 keyinfo.TitleIndex = 0;
297 keyinfo.ClassLength = wine_server_reply_size(reply);
298 keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
299 keyinfo.SubKeys = reply->subkeys;
300 keyinfo.MaxNameLen = reply->max_subkey;
301 keyinfo.MaxClassLen = reply->max_class;
302 keyinfo.Values = reply->values;
303 keyinfo.MaxValueNameLen = reply->max_value;
304 keyinfo.MaxValueDataLen = reply->max_data;
305 memcpy( info, &keyinfo, min( length, fixed_size ) );
307 break;
308 case KeyNodeInformation:
310 KEY_NODE_INFORMATION keyinfo;
311 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
312 keyinfo.LastWriteTime.QuadPart = reply->modif;
313 keyinfo.TitleIndex = 0;
314 if (reply->namelen < wine_server_reply_size(reply))
316 keyinfo.ClassLength = wine_server_reply_size(reply) - reply->namelen;
317 keyinfo.ClassOffset = fixed_size + reply->namelen;
319 else
321 keyinfo.ClassLength = 0;
322 keyinfo.ClassOffset = -1;
324 keyinfo.NameLength = reply->namelen;
325 memcpy( info, &keyinfo, min( length, fixed_size ) );
327 break;
328 case KeyNameInformation:
330 KEY_NAME_INFORMATION keyinfo;
331 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
332 keyinfo.NameLength = reply->namelen;
333 memcpy( info, &keyinfo, min( length, fixed_size ) );
335 break;
336 case KeyCachedInformation:
338 KEY_CACHED_INFORMATION keyinfo;
339 fixed_size = sizeof(keyinfo);
340 keyinfo.LastWriteTime.QuadPart = reply->modif;
341 keyinfo.TitleIndex = 0;
342 keyinfo.SubKeys = reply->subkeys;
343 keyinfo.MaxNameLen = reply->max_subkey;
344 keyinfo.Values = reply->values;
345 keyinfo.MaxValueNameLen = reply->max_value;
346 keyinfo.MaxValueDataLen = reply->max_data;
347 keyinfo.NameLength = reply->namelen;
348 memcpy( info, &keyinfo, min( length, fixed_size ) );
350 break;
351 default:
352 break;
354 *result_len = fixed_size + reply->total;
355 if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
358 SERVER_END_REQ;
359 return ret;
364 /******************************************************************************
365 * NtEnumerateKey [NTDLL.@]
366 * ZwEnumerateKey [NTDLL.@]
368 * NOTES
369 * the name copied into the buffer is NOT 0-terminated
371 NTSTATUS WINAPI NtEnumerateKey( HANDLE handle, ULONG index, KEY_INFORMATION_CLASS info_class,
372 void *info, DWORD length, DWORD *result_len )
374 /* -1 means query key, so avoid it here */
375 if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
376 return enumerate_key( handle, index, info_class, info, length, result_len );
380 /******************************************************************************
381 * RtlpNtEnumerateSubKey [NTDLL.@]
384 NTSTATUS WINAPI RtlpNtEnumerateSubKey( HANDLE handle, UNICODE_STRING *out, ULONG index )
386 KEY_BASIC_INFORMATION *info;
387 DWORD dwLen, dwResultLen;
388 NTSTATUS ret;
390 if (out->Length)
392 dwLen = out->Length + sizeof(KEY_BASIC_INFORMATION);
393 info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
394 if (!info)
395 return STATUS_NO_MEMORY;
397 else
399 dwLen = 0;
400 info = NULL;
403 ret = NtEnumerateKey( handle, index, KeyBasicInformation, info, dwLen, &dwResultLen );
404 dwResultLen -= sizeof(KEY_BASIC_INFORMATION);
406 if (ret == STATUS_BUFFER_OVERFLOW)
407 out->Length = dwResultLen;
408 else if (!ret)
410 if (out->Length < info->NameLength)
412 out->Length = dwResultLen;
413 ret = STATUS_BUFFER_OVERFLOW;
415 else
417 out->Length = info->NameLength;
418 memcpy(out->Buffer, info->Name, info->NameLength);
422 RtlFreeHeap( GetProcessHeap(), 0, info );
423 return ret;
426 /******************************************************************************
427 * NtQueryKey [NTDLL.@]
428 * ZwQueryKey [NTDLL.@]
430 NTSTATUS WINAPI NtQueryKey( HANDLE handle, KEY_INFORMATION_CLASS info_class,
431 void *info, DWORD length, DWORD *result_len )
433 return enumerate_key( handle, -1, info_class, info, length, result_len );
437 /* fill the key value info structure for a specific info class */
438 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info,
439 DWORD length, int type, int name_len, int data_len )
441 switch(info_class)
443 case KeyValueBasicInformation:
445 KEY_VALUE_BASIC_INFORMATION keyinfo;
446 keyinfo.TitleIndex = 0;
447 keyinfo.Type = type;
448 keyinfo.NameLength = name_len;
449 length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
450 memcpy( info, &keyinfo, length );
451 break;
453 case KeyValueFullInformation:
455 KEY_VALUE_FULL_INFORMATION keyinfo;
456 keyinfo.TitleIndex = 0;
457 keyinfo.Type = type;
458 keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len;
459 keyinfo.DataLength = data_len;
460 keyinfo.NameLength = name_len;
461 length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
462 memcpy( info, &keyinfo, length );
463 break;
465 case KeyValuePartialInformation:
467 KEY_VALUE_PARTIAL_INFORMATION keyinfo;
468 keyinfo.TitleIndex = 0;
469 keyinfo.Type = type;
470 keyinfo.DataLength = data_len;
471 length = min( length, (char *)keyinfo.Data - (char *)&keyinfo );
472 memcpy( info, &keyinfo, length );
473 break;
475 default:
476 break;
481 /******************************************************************************
482 * NtEnumerateValueKey [NTDLL.@]
483 * ZwEnumerateValueKey [NTDLL.@]
485 NTSTATUS WINAPI NtEnumerateValueKey( HANDLE handle, ULONG index,
486 KEY_VALUE_INFORMATION_CLASS info_class,
487 void *info, DWORD length, DWORD *result_len )
489 NTSTATUS ret;
490 void *ptr;
491 size_t fixed_size;
493 TRACE( "(%p,%u,%d,%p,%d)\n", handle, index, info_class, info, length );
495 /* compute the length we want to retrieve */
496 switch(info_class)
498 case KeyValueBasicInformation: ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break;
499 case KeyValueFullInformation: ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break;
500 case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break;
501 default:
502 FIXME( "Information class %d not implemented\n", info_class );
503 return STATUS_INVALID_PARAMETER;
505 fixed_size = (char *)ptr - (char *)info;
507 SERVER_START_REQ( enum_key_value )
509 req->hkey = wine_server_obj_handle( handle );
510 req->index = index;
511 req->info_class = info_class;
512 if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size );
513 if (!(ret = wine_server_call( req )))
515 copy_key_value_info( info_class, info, length, reply->type, reply->namelen,
516 wine_server_reply_size(reply) - reply->namelen );
517 *result_len = fixed_size + reply->total;
518 if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
521 SERVER_END_REQ;
522 return ret;
526 /******************************************************************************
527 * NtQueryValueKey [NTDLL.@]
528 * ZwQueryValueKey [NTDLL.@]
530 * NOTES
531 * the name in the KeyValueInformation is never set
533 NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name,
534 KEY_VALUE_INFORMATION_CLASS info_class,
535 void *info, DWORD length, DWORD *result_len )
537 NTSTATUS ret;
538 UCHAR *data_ptr;
539 unsigned int fixed_size, min_size;
541 TRACE( "(%p,%s,%d,%p,%d)\n", handle, debugstr_us(name), info_class, info, length );
543 if (name->Length > MAX_VALUE_LENGTH) return STATUS_OBJECT_NAME_NOT_FOUND;
545 /* compute the length we want to retrieve */
546 switch(info_class)
548 case KeyValueBasicInformation:
550 KEY_VALUE_BASIC_INFORMATION *basic_info = info;
551 min_size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);
552 fixed_size = min_size + name->Length;
553 if (min_size < length)
554 memcpy(basic_info->Name, name->Buffer, min(length - min_size, name->Length));
555 data_ptr = NULL;
556 break;
558 case KeyValueFullInformation:
560 KEY_VALUE_FULL_INFORMATION *full_info = info;
561 min_size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
562 fixed_size = min_size + name->Length;
563 if (min_size < length)
564 memcpy(full_info->Name, name->Buffer, min(length - min_size, name->Length));
565 data_ptr = (UCHAR *)full_info->Name + name->Length;
566 break;
568 case KeyValuePartialInformation:
569 min_size = fixed_size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
570 data_ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data;
571 break;
572 default:
573 FIXME( "Information class %d not implemented\n", info_class );
574 return STATUS_INVALID_PARAMETER;
577 SERVER_START_REQ( get_key_value )
579 req->hkey = wine_server_obj_handle( handle );
580 wine_server_add_data( req, name->Buffer, name->Length );
581 if (length > fixed_size && data_ptr) wine_server_set_reply( req, data_ptr, length - fixed_size );
582 if (!(ret = wine_server_call( req )))
584 copy_key_value_info( info_class, info, length, reply->type,
585 name->Length, reply->total );
586 *result_len = fixed_size + (info_class == KeyValueBasicInformation ? 0 : reply->total);
587 if (length < min_size) ret = STATUS_BUFFER_TOO_SMALL;
588 else if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
591 SERVER_END_REQ;
592 return ret;
595 /******************************************************************************
596 * RtlpNtQueryValueKey [NTDLL.@]
599 NTSTATUS WINAPI RtlpNtQueryValueKey( HANDLE handle, ULONG *result_type, PBYTE dest,
600 DWORD *result_len, void *unknown )
602 KEY_VALUE_PARTIAL_INFORMATION *info;
603 UNICODE_STRING name;
604 NTSTATUS ret;
605 DWORD dwResultLen;
606 DWORD dwLen = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + (result_len ? *result_len : 0);
608 info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
609 if (!info)
610 return STATUS_NO_MEMORY;
612 name.Length = 0;
613 ret = NtQueryValueKey( handle, &name, KeyValuePartialInformation, info, dwLen, &dwResultLen );
615 if (!ret || ret == STATUS_BUFFER_OVERFLOW)
617 if (result_len)
618 *result_len = info->DataLength;
620 if (result_type)
621 *result_type = info->Type;
623 if (ret != STATUS_BUFFER_OVERFLOW)
624 memcpy( dest, info->Data, info->DataLength );
627 RtlFreeHeap( GetProcessHeap(), 0, info );
628 return ret;
631 /******************************************************************************
632 * NtFlushKey [NTDLL.@]
633 * ZwFlushKey [NTDLL.@]
635 NTSTATUS WINAPI NtFlushKey(HANDLE key)
637 NTSTATUS ret;
639 TRACE("key=%p\n", key);
641 SERVER_START_REQ( flush_key )
643 req->hkey = wine_server_obj_handle( key );
644 ret = wine_server_call( req );
646 SERVER_END_REQ;
648 return ret;
651 /******************************************************************************
652 * NtLoadKey [NTDLL.@]
653 * ZwLoadKey [NTDLL.@]
655 NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file )
657 NTSTATUS ret;
658 HANDLE hive;
659 IO_STATUS_BLOCK io;
660 data_size_t len;
661 struct object_attributes *objattr;
663 TRACE("(%p,%p)\n", attr, file);
665 ret = NtCreateFile(&hive, GENERIC_READ | SYNCHRONIZE, file, &io, NULL, FILE_ATTRIBUTE_NORMAL, 0,
666 FILE_OPEN, 0, NULL, 0);
667 if (ret) return ret;
669 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
671 SERVER_START_REQ( load_registry )
673 req->file = wine_server_obj_handle( hive );
674 wine_server_add_data( req, objattr, len );
675 ret = wine_server_call( req );
677 SERVER_END_REQ;
679 NtClose(hive);
680 RtlFreeHeap( GetProcessHeap(), 0, objattr );
681 return ret;
684 /******************************************************************************
685 * NtLoadKey2 [NTDLL.@]
686 * ZwLoadKey2 [NTDLL.@]
688 NTSTATUS WINAPI NtLoadKey2(OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file, ULONG flags)
690 FIXME("(%p,%p,0x%08x) semi-stub: ignoring flags\n", attr, file, flags);
691 return NtLoadKey(attr, file);
694 /******************************************************************************
695 * NtNotifyChangeMultipleKeys [NTDLL.@]
696 * ZwNotifyChangeMultipleKeys [NTDLL.@]
698 NTSTATUS WINAPI NtNotifyChangeMultipleKeys(
699 HANDLE KeyHandle,
700 ULONG Count,
701 OBJECT_ATTRIBUTES *SubordinateObjects,
702 HANDLE Event,
703 PIO_APC_ROUTINE ApcRoutine,
704 PVOID ApcContext,
705 PIO_STATUS_BLOCK IoStatusBlock,
706 ULONG CompletionFilter,
707 BOOLEAN WatchSubtree,
708 PVOID ChangeBuffer,
709 ULONG Length,
710 BOOLEAN Asynchronous)
712 NTSTATUS ret;
714 TRACE("(%p,%u,%p,%p,%p,%p,%p,0x%08x, 0x%08x,%p,0x%08x,0x%08x)\n",
715 KeyHandle, Count, SubordinateObjects, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
716 Asynchronous, ChangeBuffer, Length, WatchSubtree);
718 if (Count || SubordinateObjects || ApcRoutine || ApcContext || ChangeBuffer || Length)
719 FIXME("Unimplemented optional parameter\n");
721 if (!Asynchronous)
723 OBJECT_ATTRIBUTES attr;
724 InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
725 ret = NtCreateEvent( &Event, EVENT_ALL_ACCESS, &attr, SynchronizationEvent, FALSE );
726 if (ret != STATUS_SUCCESS)
727 return ret;
730 SERVER_START_REQ( set_registry_notification )
732 req->hkey = wine_server_obj_handle( KeyHandle );
733 req->event = wine_server_obj_handle( Event );
734 req->subtree = WatchSubtree;
735 req->filter = CompletionFilter;
736 ret = wine_server_call( req );
738 SERVER_END_REQ;
740 if (!Asynchronous)
742 if (ret == STATUS_PENDING)
743 ret = NtWaitForSingleObject( Event, FALSE, NULL );
744 NtClose( Event );
747 return ret;
750 /******************************************************************************
751 * NtNotifyChangeKey [NTDLL.@]
752 * ZwNotifyChangeKey [NTDLL.@]
754 NTSTATUS WINAPI NtNotifyChangeKey(
755 IN HANDLE KeyHandle,
756 IN HANDLE Event,
757 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
758 IN PVOID ApcContext OPTIONAL,
759 OUT PIO_STATUS_BLOCK IoStatusBlock,
760 IN ULONG CompletionFilter,
761 IN BOOLEAN WatchSubtree,
762 OUT PVOID ChangeBuffer,
763 IN ULONG Length,
764 IN BOOLEAN Asynchronous)
766 return NtNotifyChangeMultipleKeys(KeyHandle, 0, NULL, Event, ApcRoutine, ApcContext,
767 IoStatusBlock, CompletionFilter, WatchSubtree,
768 ChangeBuffer, Length, Asynchronous);
771 /******************************************************************************
772 * NtQueryMultipleValueKey [NTDLL]
773 * ZwQueryMultipleValueKey
776 NTSTATUS WINAPI NtQueryMultipleValueKey(
777 HANDLE KeyHandle,
778 PKEY_MULTIPLE_VALUE_INFORMATION ListOfValuesToQuery,
779 ULONG NumberOfItems,
780 PVOID MultipleValueInformation,
781 ULONG Length,
782 PULONG ReturnLength)
784 FIXME("(%p,%p,0x%08x,%p,0x%08x,%p) stub!\n",
785 KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
786 Length,ReturnLength);
787 return STATUS_SUCCESS;
790 /******************************************************************************
791 * NtReplaceKey [NTDLL.@]
792 * ZwReplaceKey [NTDLL.@]
794 NTSTATUS WINAPI NtReplaceKey(
795 IN POBJECT_ATTRIBUTES ObjectAttributes,
796 IN HANDLE Key,
797 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
799 FIXME("(%s,%p,%s),stub!\n", debugstr_ObjectAttributes(ObjectAttributes), Key,
800 debugstr_ObjectAttributes(ReplacedObjectAttributes) );
801 return STATUS_SUCCESS;
803 /******************************************************************************
804 * NtRestoreKey [NTDLL.@]
805 * ZwRestoreKey [NTDLL.@]
807 NTSTATUS WINAPI NtRestoreKey(
808 HANDLE KeyHandle,
809 HANDLE FileHandle,
810 ULONG RestoreFlags)
812 FIXME("(%p,%p,0x%08x) stub\n",
813 KeyHandle, FileHandle, RestoreFlags);
814 return STATUS_SUCCESS;
816 /******************************************************************************
817 * NtSaveKey [NTDLL.@]
818 * ZwSaveKey [NTDLL.@]
820 NTSTATUS WINAPI NtSaveKey(IN HANDLE KeyHandle, IN HANDLE FileHandle)
822 NTSTATUS ret;
824 TRACE("(%p,%p)\n", KeyHandle, FileHandle);
826 SERVER_START_REQ( save_registry )
828 req->hkey = wine_server_obj_handle( KeyHandle );
829 req->file = wine_server_obj_handle( FileHandle );
830 ret = wine_server_call( req );
832 SERVER_END_REQ;
834 return ret;
836 /******************************************************************************
837 * NtSetInformationKey [NTDLL.@]
838 * ZwSetInformationKey [NTDLL.@]
840 NTSTATUS WINAPI NtSetInformationKey(
841 IN HANDLE KeyHandle,
842 IN const int KeyInformationClass,
843 IN PVOID KeyInformation,
844 IN ULONG KeyInformationLength)
846 FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
847 KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
848 return STATUS_SUCCESS;
852 /******************************************************************************
853 * NtSetValueKey [NTDLL.@]
854 * ZwSetValueKey [NTDLL.@]
856 * NOTES
857 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
858 * NT does definitely care (aj)
860 NTSTATUS WINAPI NtSetValueKey( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
861 ULONG type, const void *data, ULONG count )
863 NTSTATUS ret;
865 TRACE( "(%p,%s,%d,%p,%d)\n", hkey, debugstr_us(name), type, data, count );
867 if (name->Length > MAX_VALUE_LENGTH) return STATUS_INVALID_PARAMETER;
869 SERVER_START_REQ( set_key_value )
871 req->hkey = wine_server_obj_handle( hkey );
872 req->type = type;
873 req->namelen = name->Length;
874 wine_server_add_data( req, name->Buffer, name->Length );
875 wine_server_add_data( req, data, count );
876 ret = wine_server_call( req );
878 SERVER_END_REQ;
879 return ret;
882 /******************************************************************************
883 * RtlpNtSetValueKey [NTDLL.@]
886 NTSTATUS WINAPI RtlpNtSetValueKey( HANDLE hkey, ULONG type, const void *data,
887 ULONG count )
889 UNICODE_STRING name;
891 name.Length = 0;
892 return NtSetValueKey( hkey, &name, 0, type, data, count );
895 /******************************************************************************
896 * NtUnloadKey [NTDLL.@]
897 * ZwUnloadKey [NTDLL.@]
899 NTSTATUS WINAPI NtUnloadKey(IN POBJECT_ATTRIBUTES attr)
901 NTSTATUS ret;
903 TRACE("(%p)\n", attr);
905 SERVER_START_REQ( unload_registry )
907 req->hkey = wine_server_obj_handle( attr->RootDirectory );
908 ret = wine_server_call(req);
910 SERVER_END_REQ;
912 return ret;
915 /******************************************************************************
916 * RtlFormatCurrentUserKeyPath [NTDLL.@]
919 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
921 static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
922 char buffer[sizeof(TOKEN_USER) + sizeof(SID) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES];
923 DWORD len = sizeof(buffer);
924 NTSTATUS status;
926 status = NtQueryInformationToken(GetCurrentThreadEffectiveToken(), TokenUser, buffer, len, &len);
927 if (status == STATUS_SUCCESS)
929 KeyPath->MaximumLength = 0;
930 status = RtlConvertSidToUnicodeString(KeyPath, ((TOKEN_USER *)buffer)->User.Sid, FALSE);
931 if (status == STATUS_BUFFER_OVERFLOW)
933 PWCHAR buf = RtlAllocateHeap(GetProcessHeap(), 0,
934 sizeof(pathW) + KeyPath->Length + sizeof(WCHAR));
935 if (buf)
937 memcpy(buf, pathW, sizeof(pathW));
938 KeyPath->MaximumLength = KeyPath->Length + sizeof(WCHAR);
939 KeyPath->Buffer = (PWCHAR)((LPBYTE)buf + sizeof(pathW));
940 status = RtlConvertSidToUnicodeString(KeyPath,
941 ((TOKEN_USER *)buffer)->User.Sid, FALSE);
942 KeyPath->Buffer = buf;
943 KeyPath->Length += sizeof(pathW);
944 KeyPath->MaximumLength += sizeof(pathW);
946 else
947 status = STATUS_NO_MEMORY;
950 return status;
953 /******************************************************************************
954 * RtlOpenCurrentUser [NTDLL.@]
956 * NOTES
957 * If we return just HKEY_CURRENT_USER the advapi tries to find a remote
958 * registry (odd handle) and fails.
960 NTSTATUS WINAPI RtlOpenCurrentUser(
961 IN ACCESS_MASK DesiredAccess, /* [in] */
962 OUT PHANDLE KeyHandle) /* [out] handle of HKEY_CURRENT_USER */
964 OBJECT_ATTRIBUTES ObjectAttributes;
965 UNICODE_STRING ObjectName;
966 NTSTATUS ret;
968 TRACE("(0x%08x, %p)\n",DesiredAccess, KeyHandle);
970 if ((ret = RtlFormatCurrentUserKeyPath(&ObjectName))) return ret;
971 InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
972 ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
973 RtlFreeUnicodeString(&ObjectName);
974 return ret;
978 static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
979 PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
981 PUNICODE_STRING str;
982 UNICODE_STRING src, dst;
983 LONG *bin;
984 ULONG offset;
985 PWSTR wstr;
986 DWORD res;
987 NTSTATUS status = STATUS_SUCCESS;
988 ULONG len;
989 LPWSTR String;
990 ULONG count = 0;
992 if (pInfo == NULL)
994 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
995 return STATUS_INVALID_PARAMETER;
996 else
998 status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
999 pQuery->DefaultLength, pContext, pQuery->EntryContext);
1001 return status;
1003 len = pInfo->DataLength;
1005 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
1007 str = pQuery->EntryContext;
1009 switch(pInfo->Type)
1011 case REG_EXPAND_SZ:
1012 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
1014 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1015 res = 0;
1016 dst.MaximumLength = 0;
1017 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1018 dst.Length = 0;
1019 dst.MaximumLength = res;
1020 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1021 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1022 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1023 dst.Length, pContext, pQuery->EntryContext);
1024 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1027 case REG_SZ:
1028 case REG_LINK:
1029 if (str->Buffer == NULL)
1030 RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1031 else
1032 RtlAppendUnicodeToString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1033 break;
1035 case REG_MULTI_SZ:
1036 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
1037 return STATUS_INVALID_PARAMETER;
1039 if (str->Buffer == NULL)
1041 str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1042 str->MaximumLength = len;
1044 len = min(len, str->MaximumLength);
1045 memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
1046 str->Length = len;
1047 break;
1049 default:
1050 bin = pQuery->EntryContext;
1051 if (pInfo->DataLength <= sizeof(ULONG))
1052 memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
1053 pInfo->DataLength);
1054 else
1056 if (bin[0] <= sizeof(ULONG))
1058 memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
1059 min(-bin[0], pInfo->DataLength));
1061 else
1063 len = min(bin[0], pInfo->DataLength);
1064 bin[1] = len;
1065 bin[2] = pInfo->Type;
1066 memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
1069 break;
1072 else
1074 if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
1075 (pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
1077 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type,
1078 ((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
1079 pContext, pQuery->EntryContext);
1081 else if (pInfo->Type == REG_EXPAND_SZ)
1083 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1084 res = 0;
1085 dst.MaximumLength = 0;
1086 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1087 dst.Length = 0;
1088 dst.MaximumLength = res;
1089 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1090 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1091 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1092 dst.Length, pContext, pQuery->EntryContext);
1093 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1095 else /* REG_MULTI_SZ */
1097 if(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
1099 for (offset = 0; offset <= pInfo->DataLength; offset += len + sizeof(WCHAR))
1101 wstr = (WCHAR*)(((CHAR*)pInfo) + offset);
1102 len = strlenW(wstr) * sizeof(WCHAR);
1103 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, wstr, len,
1104 pContext, pQuery->EntryContext);
1105 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1106 return status;
1109 else
1111 while(count<=pInfo->DataLength)
1113 String = (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset)+count;
1114 count+=strlenW(String)+1;
1115 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1116 res = 0;
1117 dst.MaximumLength = 0;
1118 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1119 dst.Length = 0;
1120 dst.MaximumLength = res;
1121 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1122 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1123 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1124 dst.Length, pContext, pQuery->EntryContext);
1125 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1126 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1127 return status;
1132 return status;
1136 static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
1138 UNICODE_STRING KeyString;
1139 OBJECT_ATTRIBUTES regkey;
1140 PCWSTR base;
1141 INT len;
1142 NTSTATUS status;
1144 static const WCHAR empty[] = {0};
1145 static const WCHAR control[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1146 '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1147 'C','o','n','t','r','o','l','\\',0};
1149 static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1150 'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1152 static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1153 'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1154 'S','e','r','v','i','c','e','s','\\',0};
1156 static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1157 'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1159 static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1160 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1161 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1163 switch (RelativeTo & 0xff)
1165 case RTL_REGISTRY_ABSOLUTE:
1166 base = empty;
1167 break;
1169 case RTL_REGISTRY_CONTROL:
1170 base = control;
1171 break;
1173 case RTL_REGISTRY_DEVICEMAP:
1174 base = devicemap;
1175 break;
1177 case RTL_REGISTRY_SERVICES:
1178 base = services;
1179 break;
1181 case RTL_REGISTRY_USER:
1182 base = user;
1183 break;
1185 case RTL_REGISTRY_WINDOWS_NT:
1186 base = windows_nt;
1187 break;
1189 default:
1190 return STATUS_INVALID_PARAMETER;
1193 len = (strlenW(base) + strlenW(Path) + 1) * sizeof(WCHAR);
1194 KeyString.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1195 if (KeyString.Buffer == NULL)
1196 return STATUS_NO_MEMORY;
1198 strcpyW(KeyString.Buffer, base);
1199 strcatW(KeyString.Buffer, Path);
1200 KeyString.Length = len - sizeof(WCHAR);
1201 KeyString.MaximumLength = len;
1202 InitializeObjectAttributes(&regkey, &KeyString, OBJ_CASE_INSENSITIVE, NULL, NULL);
1203 status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
1204 RtlFreeHeap(GetProcessHeap(), 0, KeyString.Buffer);
1205 return status;
1208 /*************************************************************************
1209 * RtlQueryRegistryValues [NTDLL.@]
1211 * Query multiple registry values with a single call.
1213 * PARAMS
1214 * RelativeTo [I] Registry path that Path refers to
1215 * Path [I] Path to key
1216 * QueryTable [I] Table of key values to query
1217 * Context [I] Parameter to pass to the application defined QueryRoutine function
1218 * Environment [I] Optional parameter to use when performing expansion
1220 * RETURNS
1221 * STATUS_SUCCESS or an appropriate NTSTATUS error code.
1223 NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
1224 IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
1225 IN PVOID Environment OPTIONAL)
1227 UNICODE_STRING Value;
1228 HANDLE handle, topkey;
1229 PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
1230 ULONG len, buflen = 0;
1231 NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
1232 INT i;
1234 TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
1236 if(Path == NULL)
1237 return STATUS_INVALID_PARAMETER;
1239 /* get a valid handle */
1240 if (RelativeTo & RTL_REGISTRY_HANDLE)
1241 topkey = handle = (HANDLE)Path;
1242 else
1244 status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
1245 handle = topkey;
1247 if(status != STATUS_SUCCESS)
1248 return status;
1250 /* Process query table entries */
1251 for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
1253 if (QueryTable->Flags &
1254 (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
1256 /* topkey must be kept open just in case we will reuse it later */
1257 if (handle != topkey)
1258 NtClose(handle);
1260 if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
1262 handle = 0;
1263 status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
1264 if(status != STATUS_SUCCESS)
1266 ret = status;
1267 goto out;
1270 else
1271 handle = topkey;
1274 if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
1276 QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
1277 Context, QueryTable->EntryContext);
1278 continue;
1281 if (!handle)
1283 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1285 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1286 goto out;
1288 continue;
1291 if (QueryTable->Name == NULL)
1293 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
1295 ret = STATUS_INVALID_PARAMETER;
1296 goto out;
1299 /* Report all subkeys */
1300 for (i = 0;; ++i)
1302 status = NtEnumerateValueKey(handle, i,
1303 KeyValueFullInformation, pInfo, buflen, &len);
1304 if (status == STATUS_NO_MORE_ENTRIES)
1305 break;
1306 if (status == STATUS_BUFFER_OVERFLOW ||
1307 status == STATUS_BUFFER_TOO_SMALL)
1309 buflen = len;
1310 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1311 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1312 NtEnumerateValueKey(handle, i, KeyValueFullInformation,
1313 pInfo, buflen, &len);
1316 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1317 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1319 ret = status;
1320 goto out;
1322 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1324 RtlInitUnicodeString(&Value, pInfo->Name);
1325 NtDeleteValueKey(handle, &Value);
1329 if (i == 0 && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
1331 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1332 goto out;
1335 else
1337 RtlInitUnicodeString(&Value, QueryTable->Name);
1338 status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
1339 pInfo, buflen, &len);
1340 if (status == STATUS_BUFFER_OVERFLOW ||
1341 status == STATUS_BUFFER_TOO_SMALL)
1343 buflen = len;
1344 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1345 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1346 status = NtQueryValueKey(handle, &Value,
1347 KeyValueFullInformation, pInfo, buflen, &len);
1349 if (status != STATUS_SUCCESS)
1351 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1353 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1354 goto out;
1356 status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
1357 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1359 ret = status;
1360 goto out;
1363 else
1365 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1366 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1368 ret = status;
1369 goto out;
1371 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1372 NtDeleteValueKey(handle, &Value);
1377 out:
1378 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1379 if (handle != topkey)
1380 NtClose(handle);
1381 NtClose(topkey);
1382 return ret;
1385 /*************************************************************************
1386 * RtlCheckRegistryKey [NTDLL.@]
1388 * Query multiple registry values with a single call.
1390 * PARAMS
1391 * RelativeTo [I] Registry path that Path refers to
1392 * Path [I] Path to key
1394 * RETURNS
1395 * STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1397 NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
1399 HANDLE handle;
1400 NTSTATUS status;
1402 TRACE("(%d, %s)\n", RelativeTo, debugstr_w(Path));
1404 if((!RelativeTo) && Path == NULL)
1405 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1406 if(RelativeTo & RTL_REGISTRY_HANDLE)
1407 return STATUS_SUCCESS;
1409 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1410 if (handle) NtClose(handle);
1411 if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
1412 return status;
1415 /*************************************************************************
1416 * RtlDeleteRegistryValue [NTDLL.@]
1418 * Query multiple registry values with a single call.
1420 * PARAMS
1421 * RelativeTo [I] Registry path that Path refers to
1422 * Path [I] Path to key
1423 * ValueName [I] Name of the value to delete
1425 * RETURNS
1426 * STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1428 NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
1430 NTSTATUS status;
1431 HANDLE handle;
1432 UNICODE_STRING Value;
1434 TRACE("(%d, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
1436 RtlInitUnicodeString(&Value, ValueName);
1437 if(RelativeTo == RTL_REGISTRY_HANDLE)
1439 return NtDeleteValueKey((HANDLE)Path, &Value);
1441 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1442 if (status) return status;
1443 status = NtDeleteValueKey(handle, &Value);
1444 NtClose(handle);
1445 return status;
1448 /*************************************************************************
1449 * RtlWriteRegistryValue [NTDLL.@]
1451 * Sets the registry value with provided data.
1453 * PARAMS
1454 * RelativeTo [I] Registry path that path parameter refers to
1455 * path [I] Path to the key (or handle - see RTL_GetKeyHandle)
1456 * name [I] Name of the registry value to set
1457 * type [I] Type of the registry key to set
1458 * data [I] Pointer to the user data to be set
1459 * length [I] Length of the user data pointed by data
1461 * RETURNS
1462 * STATUS_SUCCESS if the specified key is successfully set,
1463 * or an NTSTATUS error code.
1465 NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
1466 ULONG type, PVOID data, ULONG length )
1468 HANDLE hkey;
1469 NTSTATUS status;
1470 UNICODE_STRING str;
1472 TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
1473 type, data, length );
1475 RtlInitUnicodeString( &str, name );
1477 if (RelativeTo == RTL_REGISTRY_HANDLE)
1478 return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
1480 status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
1481 if (status != STATUS_SUCCESS) return status;
1483 status = NtSetValueKey( hkey, &str, 0, type, data, length );
1484 NtClose( hkey );
1486 return status;
1489 /*************************************************************************
1490 * NtQueryLicenseValue [NTDLL.@]
1492 * NOTES
1493 * On Windows all license properties are stored in a single key, but
1494 * unless there is some app which explicitly depends on that, there is
1495 * no good reason to reproduce that.
1497 NTSTATUS WINAPI NtQueryLicenseValue( const UNICODE_STRING *name, ULONG *result_type,
1498 PVOID data, ULONG length, ULONG *result_len )
1500 static const WCHAR LicenseInformationW[] = {'M','a','c','h','i','n','e','\\',
1501 'S','o','f','t','w','a','r','e','\\',
1502 'W','i','n','e','\\','L','i','c','e','n','s','e',
1503 'I','n','f','o','r','m','a','t','i','o','n',0};
1504 KEY_VALUE_PARTIAL_INFORMATION *info;
1505 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
1506 DWORD info_length, count;
1507 OBJECT_ATTRIBUTES attr;
1508 UNICODE_STRING keyW;
1509 HANDLE hkey;
1511 if (!name || !name->Buffer || !name->Length || !result_len)
1512 return STATUS_INVALID_PARAMETER;
1514 info_length = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + length;
1515 info = RtlAllocateHeap( GetProcessHeap(), 0, info_length );
1516 if (!info) return STATUS_NO_MEMORY;
1518 attr.Length = sizeof(attr);
1519 attr.RootDirectory = 0;
1520 attr.ObjectName = &keyW;
1521 attr.Attributes = 0;
1522 attr.SecurityDescriptor = NULL;
1523 attr.SecurityQualityOfService = NULL;
1524 RtlInitUnicodeString( &keyW, LicenseInformationW );
1526 /* @@ Wine registry key: HKLM\Software\Wine\LicenseInformation */
1527 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
1529 status = NtQueryValueKey( hkey, name, KeyValuePartialInformation,
1530 info, info_length, &count );
1531 if (!status || status == STATUS_BUFFER_OVERFLOW)
1533 if (result_type)
1534 *result_type = info->Type;
1536 *result_len = info->DataLength;
1538 if (status == STATUS_BUFFER_OVERFLOW)
1539 status = STATUS_BUFFER_TOO_SMALL;
1540 else
1541 memcpy( data, info->Data, info->DataLength );
1543 NtClose( hkey );
1546 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1547 FIXME( "License key %s not found\n", debugstr_w(name->Buffer) );
1549 RtlFreeHeap( GetProcessHeap(), 0, info );
1550 return status;