include: Add constants for CryptProtectMemory/CryptUnprotectMemory.
[wine.git] / dlls / ntdll / reg.c
blobe151e913d683b8983829a56d5436bf504cacf2be
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 * NtNotifyChangeMultipleKeys [NTDLL.@]
686 * ZwNotifyChangeMultipleKeys [NTDLL.@]
688 NTSTATUS WINAPI NtNotifyChangeMultipleKeys(
689 HANDLE KeyHandle,
690 ULONG Count,
691 OBJECT_ATTRIBUTES *SubordinateObjects,
692 HANDLE Event,
693 PIO_APC_ROUTINE ApcRoutine,
694 PVOID ApcContext,
695 PIO_STATUS_BLOCK IoStatusBlock,
696 ULONG CompletionFilter,
697 BOOLEAN WatchSubtree,
698 PVOID ChangeBuffer,
699 ULONG Length,
700 BOOLEAN Asynchronous)
702 NTSTATUS ret;
704 TRACE("(%p,%u,%p,%p,%p,%p,%p,0x%08x, 0x%08x,%p,0x%08x,0x%08x)\n",
705 KeyHandle, Count, SubordinateObjects, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
706 Asynchronous, ChangeBuffer, Length, WatchSubtree);
708 if (Count || SubordinateObjects || ApcRoutine || ApcContext || ChangeBuffer || Length)
709 FIXME("Unimplemented optional parameter\n");
711 if (!Asynchronous)
713 OBJECT_ATTRIBUTES attr;
714 InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
715 ret = NtCreateEvent( &Event, EVENT_ALL_ACCESS, &attr, SynchronizationEvent, FALSE );
716 if (ret != STATUS_SUCCESS)
717 return ret;
720 SERVER_START_REQ( set_registry_notification )
722 req->hkey = wine_server_obj_handle( KeyHandle );
723 req->event = wine_server_obj_handle( Event );
724 req->subtree = WatchSubtree;
725 req->filter = CompletionFilter;
726 ret = wine_server_call( req );
728 SERVER_END_REQ;
730 if (!Asynchronous)
732 if (ret == STATUS_PENDING)
733 ret = NtWaitForSingleObject( Event, FALSE, NULL );
734 NtClose( Event );
737 return ret;
740 /******************************************************************************
741 * NtNotifyChangeKey [NTDLL.@]
742 * ZwNotifyChangeKey [NTDLL.@]
744 NTSTATUS WINAPI NtNotifyChangeKey(
745 IN HANDLE KeyHandle,
746 IN HANDLE Event,
747 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
748 IN PVOID ApcContext OPTIONAL,
749 OUT PIO_STATUS_BLOCK IoStatusBlock,
750 IN ULONG CompletionFilter,
751 IN BOOLEAN WatchSubtree,
752 OUT PVOID ChangeBuffer,
753 IN ULONG Length,
754 IN BOOLEAN Asynchronous)
756 return NtNotifyChangeMultipleKeys(KeyHandle, 0, NULL, Event, ApcRoutine, ApcContext,
757 IoStatusBlock, CompletionFilter, WatchSubtree,
758 ChangeBuffer, Length, Asynchronous);
761 /******************************************************************************
762 * NtQueryMultipleValueKey [NTDLL]
763 * ZwQueryMultipleValueKey
766 NTSTATUS WINAPI NtQueryMultipleValueKey(
767 HANDLE KeyHandle,
768 PKEY_MULTIPLE_VALUE_INFORMATION ListOfValuesToQuery,
769 ULONG NumberOfItems,
770 PVOID MultipleValueInformation,
771 ULONG Length,
772 PULONG ReturnLength)
774 FIXME("(%p,%p,0x%08x,%p,0x%08x,%p) stub!\n",
775 KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
776 Length,ReturnLength);
777 return STATUS_SUCCESS;
780 /******************************************************************************
781 * NtReplaceKey [NTDLL.@]
782 * ZwReplaceKey [NTDLL.@]
784 NTSTATUS WINAPI NtReplaceKey(
785 IN POBJECT_ATTRIBUTES ObjectAttributes,
786 IN HANDLE Key,
787 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
789 FIXME("(%s,%p,%s),stub!\n", debugstr_ObjectAttributes(ObjectAttributes), Key,
790 debugstr_ObjectAttributes(ReplacedObjectAttributes) );
791 return STATUS_SUCCESS;
793 /******************************************************************************
794 * NtRestoreKey [NTDLL.@]
795 * ZwRestoreKey [NTDLL.@]
797 NTSTATUS WINAPI NtRestoreKey(
798 HANDLE KeyHandle,
799 HANDLE FileHandle,
800 ULONG RestoreFlags)
802 FIXME("(%p,%p,0x%08x) stub\n",
803 KeyHandle, FileHandle, RestoreFlags);
804 return STATUS_SUCCESS;
806 /******************************************************************************
807 * NtSaveKey [NTDLL.@]
808 * ZwSaveKey [NTDLL.@]
810 NTSTATUS WINAPI NtSaveKey(IN HANDLE KeyHandle, IN HANDLE FileHandle)
812 NTSTATUS ret;
814 TRACE("(%p,%p)\n", KeyHandle, FileHandle);
816 SERVER_START_REQ( save_registry )
818 req->hkey = wine_server_obj_handle( KeyHandle );
819 req->file = wine_server_obj_handle( FileHandle );
820 ret = wine_server_call( req );
822 SERVER_END_REQ;
824 return ret;
826 /******************************************************************************
827 * NtSetInformationKey [NTDLL.@]
828 * ZwSetInformationKey [NTDLL.@]
830 NTSTATUS WINAPI NtSetInformationKey(
831 IN HANDLE KeyHandle,
832 IN const int KeyInformationClass,
833 IN PVOID KeyInformation,
834 IN ULONG KeyInformationLength)
836 FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
837 KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
838 return STATUS_SUCCESS;
842 /******************************************************************************
843 * NtSetValueKey [NTDLL.@]
844 * ZwSetValueKey [NTDLL.@]
846 * NOTES
847 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
848 * NT does definitely care (aj)
850 NTSTATUS WINAPI NtSetValueKey( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
851 ULONG type, const void *data, ULONG count )
853 NTSTATUS ret;
855 TRACE( "(%p,%s,%d,%p,%d)\n", hkey, debugstr_us(name), type, data, count );
857 if (name->Length > MAX_VALUE_LENGTH) return STATUS_INVALID_PARAMETER;
859 SERVER_START_REQ( set_key_value )
861 req->hkey = wine_server_obj_handle( hkey );
862 req->type = type;
863 req->namelen = name->Length;
864 wine_server_add_data( req, name->Buffer, name->Length );
865 wine_server_add_data( req, data, count );
866 ret = wine_server_call( req );
868 SERVER_END_REQ;
869 return ret;
872 /******************************************************************************
873 * RtlpNtSetValueKey [NTDLL.@]
876 NTSTATUS WINAPI RtlpNtSetValueKey( HANDLE hkey, ULONG type, const void *data,
877 ULONG count )
879 UNICODE_STRING name;
881 name.Length = 0;
882 return NtSetValueKey( hkey, &name, 0, type, data, count );
885 /******************************************************************************
886 * NtUnloadKey [NTDLL.@]
887 * ZwUnloadKey [NTDLL.@]
889 NTSTATUS WINAPI NtUnloadKey(IN POBJECT_ATTRIBUTES attr)
891 NTSTATUS ret;
893 TRACE("(%p)\n", attr);
895 SERVER_START_REQ( unload_registry )
897 req->hkey = wine_server_obj_handle( attr->RootDirectory );
898 ret = wine_server_call(req);
900 SERVER_END_REQ;
902 return ret;
905 /******************************************************************************
906 * RtlFormatCurrentUserKeyPath [NTDLL.@]
909 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
911 static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
912 char buffer[sizeof(TOKEN_USER) + sizeof(SID) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES];
913 DWORD len = sizeof(buffer);
914 NTSTATUS status;
916 status = NtQueryInformationToken(GetCurrentThreadEffectiveToken(), TokenUser, buffer, len, &len);
917 if (status == STATUS_SUCCESS)
919 KeyPath->MaximumLength = 0;
920 status = RtlConvertSidToUnicodeString(KeyPath, ((TOKEN_USER *)buffer)->User.Sid, FALSE);
921 if (status == STATUS_BUFFER_OVERFLOW)
923 PWCHAR buf = RtlAllocateHeap(GetProcessHeap(), 0,
924 sizeof(pathW) + KeyPath->Length + sizeof(WCHAR));
925 if (buf)
927 memcpy(buf, pathW, sizeof(pathW));
928 KeyPath->MaximumLength = KeyPath->Length + sizeof(WCHAR);
929 KeyPath->Buffer = (PWCHAR)((LPBYTE)buf + sizeof(pathW));
930 status = RtlConvertSidToUnicodeString(KeyPath,
931 ((TOKEN_USER *)buffer)->User.Sid, FALSE);
932 KeyPath->Buffer = buf;
933 KeyPath->Length += sizeof(pathW);
934 KeyPath->MaximumLength += sizeof(pathW);
936 else
937 status = STATUS_NO_MEMORY;
940 return status;
943 /******************************************************************************
944 * RtlOpenCurrentUser [NTDLL.@]
946 * NOTES
947 * If we return just HKEY_CURRENT_USER the advapi tries to find a remote
948 * registry (odd handle) and fails.
950 NTSTATUS WINAPI RtlOpenCurrentUser(
951 IN ACCESS_MASK DesiredAccess, /* [in] */
952 OUT PHANDLE KeyHandle) /* [out] handle of HKEY_CURRENT_USER */
954 OBJECT_ATTRIBUTES ObjectAttributes;
955 UNICODE_STRING ObjectName;
956 NTSTATUS ret;
958 TRACE("(0x%08x, %p)\n",DesiredAccess, KeyHandle);
960 if ((ret = RtlFormatCurrentUserKeyPath(&ObjectName))) return ret;
961 InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
962 ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
963 RtlFreeUnicodeString(&ObjectName);
964 return ret;
968 static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
969 PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
971 PUNICODE_STRING str;
972 UNICODE_STRING src, dst;
973 LONG *bin;
974 ULONG offset;
975 PWSTR wstr;
976 DWORD res;
977 NTSTATUS status = STATUS_SUCCESS;
978 ULONG len;
979 LPWSTR String;
980 ULONG count = 0;
982 if (pInfo == NULL)
984 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
985 return STATUS_INVALID_PARAMETER;
986 else
988 status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
989 pQuery->DefaultLength, pContext, pQuery->EntryContext);
991 return status;
993 len = pInfo->DataLength;
995 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
997 str = pQuery->EntryContext;
999 switch(pInfo->Type)
1001 case REG_EXPAND_SZ:
1002 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
1004 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1005 res = 0;
1006 dst.MaximumLength = 0;
1007 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1008 dst.Length = 0;
1009 dst.MaximumLength = res;
1010 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1011 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1012 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1013 dst.Length, pContext, pQuery->EntryContext);
1014 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1017 case REG_SZ:
1018 case REG_LINK:
1019 if (str->Buffer == NULL)
1020 RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1021 else
1022 RtlAppendUnicodeToString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1023 break;
1025 case REG_MULTI_SZ:
1026 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
1027 return STATUS_INVALID_PARAMETER;
1029 if (str->Buffer == NULL)
1031 str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1032 str->MaximumLength = len;
1034 len = min(len, str->MaximumLength);
1035 memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
1036 str->Length = len;
1037 break;
1039 default:
1040 bin = pQuery->EntryContext;
1041 if (pInfo->DataLength <= sizeof(ULONG))
1042 memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
1043 pInfo->DataLength);
1044 else
1046 if (bin[0] <= sizeof(ULONG))
1048 memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
1049 min(-bin[0], pInfo->DataLength));
1051 else
1053 len = min(bin[0], pInfo->DataLength);
1054 bin[1] = len;
1055 bin[2] = pInfo->Type;
1056 memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
1059 break;
1062 else
1064 if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
1065 (pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
1067 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type,
1068 ((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
1069 pContext, pQuery->EntryContext);
1071 else if (pInfo->Type == REG_EXPAND_SZ)
1073 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1074 res = 0;
1075 dst.MaximumLength = 0;
1076 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1077 dst.Length = 0;
1078 dst.MaximumLength = res;
1079 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1080 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1081 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1082 dst.Length, pContext, pQuery->EntryContext);
1083 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1085 else /* REG_MULTI_SZ */
1087 if(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
1089 for (offset = 0; offset <= pInfo->DataLength; offset += len + sizeof(WCHAR))
1091 wstr = (WCHAR*)(((CHAR*)pInfo) + offset);
1092 len = strlenW(wstr) * sizeof(WCHAR);
1093 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, wstr, len,
1094 pContext, pQuery->EntryContext);
1095 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1096 return status;
1099 else
1101 while(count<=pInfo->DataLength)
1103 String = (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset)+count;
1104 count+=strlenW(String)+1;
1105 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1106 res = 0;
1107 dst.MaximumLength = 0;
1108 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1109 dst.Length = 0;
1110 dst.MaximumLength = res;
1111 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1112 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1113 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1114 dst.Length, pContext, pQuery->EntryContext);
1115 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1116 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1117 return status;
1122 return status;
1126 static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
1128 UNICODE_STRING KeyString;
1129 OBJECT_ATTRIBUTES regkey;
1130 PCWSTR base;
1131 INT len;
1132 NTSTATUS status;
1134 static const WCHAR empty[] = {0};
1135 static const WCHAR control[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1136 '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1137 'C','o','n','t','r','o','l','\\',0};
1139 static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1140 'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1142 static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1143 'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1144 'S','e','r','v','i','c','e','s','\\',0};
1146 static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1147 'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1149 static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1150 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1151 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1153 switch (RelativeTo & 0xff)
1155 case RTL_REGISTRY_ABSOLUTE:
1156 base = empty;
1157 break;
1159 case RTL_REGISTRY_CONTROL:
1160 base = control;
1161 break;
1163 case RTL_REGISTRY_DEVICEMAP:
1164 base = devicemap;
1165 break;
1167 case RTL_REGISTRY_SERVICES:
1168 base = services;
1169 break;
1171 case RTL_REGISTRY_USER:
1172 base = user;
1173 break;
1175 case RTL_REGISTRY_WINDOWS_NT:
1176 base = windows_nt;
1177 break;
1179 default:
1180 return STATUS_INVALID_PARAMETER;
1183 len = (strlenW(base) + strlenW(Path) + 1) * sizeof(WCHAR);
1184 KeyString.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1185 if (KeyString.Buffer == NULL)
1186 return STATUS_NO_MEMORY;
1188 strcpyW(KeyString.Buffer, base);
1189 strcatW(KeyString.Buffer, Path);
1190 KeyString.Length = len - sizeof(WCHAR);
1191 KeyString.MaximumLength = len;
1192 InitializeObjectAttributes(&regkey, &KeyString, OBJ_CASE_INSENSITIVE, NULL, NULL);
1193 status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
1194 RtlFreeHeap(GetProcessHeap(), 0, KeyString.Buffer);
1195 return status;
1198 /*************************************************************************
1199 * RtlQueryRegistryValues [NTDLL.@]
1201 * Query multiple registry values with a single call.
1203 * PARAMS
1204 * RelativeTo [I] Registry path that Path refers to
1205 * Path [I] Path to key
1206 * QueryTable [I] Table of key values to query
1207 * Context [I] Parameter to pass to the application defined QueryRoutine function
1208 * Environment [I] Optional parameter to use when performing expansion
1210 * RETURNS
1211 * STATUS_SUCCESS or an appropriate NTSTATUS error code.
1213 NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
1214 IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
1215 IN PVOID Environment OPTIONAL)
1217 UNICODE_STRING Value;
1218 HANDLE handle, topkey;
1219 PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
1220 ULONG len, buflen = 0;
1221 NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
1222 INT i;
1224 TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
1226 if(Path == NULL)
1227 return STATUS_INVALID_PARAMETER;
1229 /* get a valid handle */
1230 if (RelativeTo & RTL_REGISTRY_HANDLE)
1231 topkey = handle = (HANDLE)Path;
1232 else
1234 status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
1235 handle = topkey;
1237 if(status != STATUS_SUCCESS)
1238 return status;
1240 /* Process query table entries */
1241 for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
1243 if (QueryTable->Flags &
1244 (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
1246 /* topkey must be kept open just in case we will reuse it later */
1247 if (handle != topkey)
1248 NtClose(handle);
1250 if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
1252 handle = 0;
1253 status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
1254 if(status != STATUS_SUCCESS)
1256 ret = status;
1257 goto out;
1260 else
1261 handle = topkey;
1264 if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
1266 QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
1267 Context, QueryTable->EntryContext);
1268 continue;
1271 if (!handle)
1273 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1275 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1276 goto out;
1278 continue;
1281 if (QueryTable->Name == NULL)
1283 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
1285 ret = STATUS_INVALID_PARAMETER;
1286 goto out;
1289 /* Report all subkeys */
1290 for (i = 0;; ++i)
1292 status = NtEnumerateValueKey(handle, i,
1293 KeyValueFullInformation, pInfo, buflen, &len);
1294 if (status == STATUS_NO_MORE_ENTRIES)
1295 break;
1296 if (status == STATUS_BUFFER_OVERFLOW ||
1297 status == STATUS_BUFFER_TOO_SMALL)
1299 buflen = len;
1300 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1301 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1302 NtEnumerateValueKey(handle, i, KeyValueFullInformation,
1303 pInfo, buflen, &len);
1306 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1307 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1309 ret = status;
1310 goto out;
1312 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1314 RtlInitUnicodeString(&Value, pInfo->Name);
1315 NtDeleteValueKey(handle, &Value);
1319 if (i == 0 && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
1321 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1322 goto out;
1325 else
1327 RtlInitUnicodeString(&Value, QueryTable->Name);
1328 status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
1329 pInfo, buflen, &len);
1330 if (status == STATUS_BUFFER_OVERFLOW ||
1331 status == STATUS_BUFFER_TOO_SMALL)
1333 buflen = len;
1334 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1335 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1336 status = NtQueryValueKey(handle, &Value,
1337 KeyValueFullInformation, pInfo, buflen, &len);
1339 if (status != STATUS_SUCCESS)
1341 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1343 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1344 goto out;
1346 status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
1347 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1349 ret = status;
1350 goto out;
1353 else
1355 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1356 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1358 ret = status;
1359 goto out;
1361 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1362 NtDeleteValueKey(handle, &Value);
1367 out:
1368 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1369 if (handle != topkey)
1370 NtClose(handle);
1371 NtClose(topkey);
1372 return ret;
1375 /*************************************************************************
1376 * RtlCheckRegistryKey [NTDLL.@]
1378 * Query multiple registry values with a single call.
1380 * PARAMS
1381 * RelativeTo [I] Registry path that Path refers to
1382 * Path [I] Path to key
1384 * RETURNS
1385 * STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1387 NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
1389 HANDLE handle;
1390 NTSTATUS status;
1392 TRACE("(%d, %s)\n", RelativeTo, debugstr_w(Path));
1394 if((!RelativeTo) && Path == NULL)
1395 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1396 if(RelativeTo & RTL_REGISTRY_HANDLE)
1397 return STATUS_SUCCESS;
1399 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1400 if (handle) NtClose(handle);
1401 if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
1402 return status;
1405 /*************************************************************************
1406 * RtlDeleteRegistryValue [NTDLL.@]
1408 * Query multiple registry values with a single call.
1410 * PARAMS
1411 * RelativeTo [I] Registry path that Path refers to
1412 * Path [I] Path to key
1413 * ValueName [I] Name of the value to delete
1415 * RETURNS
1416 * STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1418 NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
1420 NTSTATUS status;
1421 HANDLE handle;
1422 UNICODE_STRING Value;
1424 TRACE("(%d, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
1426 RtlInitUnicodeString(&Value, ValueName);
1427 if(RelativeTo == RTL_REGISTRY_HANDLE)
1429 return NtDeleteValueKey((HANDLE)Path, &Value);
1431 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1432 if (status) return status;
1433 status = NtDeleteValueKey(handle, &Value);
1434 NtClose(handle);
1435 return status;
1438 /*************************************************************************
1439 * RtlWriteRegistryValue [NTDLL.@]
1441 * Sets the registry value with provided data.
1443 * PARAMS
1444 * RelativeTo [I] Registry path that path parameter refers to
1445 * path [I] Path to the key (or handle - see RTL_GetKeyHandle)
1446 * name [I] Name of the registry value to set
1447 * type [I] Type of the registry key to set
1448 * data [I] Pointer to the user data to be set
1449 * length [I] Length of the user data pointed by data
1451 * RETURNS
1452 * STATUS_SUCCESS if the specified key is successfully set,
1453 * or an NTSTATUS error code.
1455 NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
1456 ULONG type, PVOID data, ULONG length )
1458 HANDLE hkey;
1459 NTSTATUS status;
1460 UNICODE_STRING str;
1462 TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
1463 type, data, length );
1465 RtlInitUnicodeString( &str, name );
1467 if (RelativeTo == RTL_REGISTRY_HANDLE)
1468 return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
1470 status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
1471 if (status != STATUS_SUCCESS) return status;
1473 status = NtSetValueKey( hkey, &str, 0, type, data, length );
1474 NtClose( hkey );
1476 return status;
1479 /*************************************************************************
1480 * NtQueryLicenseValue [NTDLL.@]
1482 * NOTES
1483 * On Windows all license properties are stored in a single key, but
1484 * unless there is some app which explicitly depends on that, there is
1485 * no good reason to reproduce that.
1487 NTSTATUS WINAPI NtQueryLicenseValue( const UNICODE_STRING *name, ULONG *result_type,
1488 PVOID data, ULONG length, ULONG *result_len )
1490 static const WCHAR LicenseInformationW[] = {'M','a','c','h','i','n','e','\\',
1491 'S','o','f','t','w','a','r','e','\\',
1492 'W','i','n','e','\\','L','i','c','e','n','s','e',
1493 'I','n','f','o','r','m','a','t','i','o','n',0};
1494 KEY_VALUE_PARTIAL_INFORMATION *info;
1495 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
1496 DWORD info_length, count;
1497 OBJECT_ATTRIBUTES attr;
1498 UNICODE_STRING keyW;
1499 HANDLE hkey;
1501 if (!name || !name->Buffer || !name->Length || !result_len)
1502 return STATUS_INVALID_PARAMETER;
1504 info_length = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + length;
1505 info = RtlAllocateHeap( GetProcessHeap(), 0, info_length );
1506 if (!info) return STATUS_NO_MEMORY;
1508 attr.Length = sizeof(attr);
1509 attr.RootDirectory = 0;
1510 attr.ObjectName = &keyW;
1511 attr.Attributes = 0;
1512 attr.SecurityDescriptor = NULL;
1513 attr.SecurityQualityOfService = NULL;
1514 RtlInitUnicodeString( &keyW, LicenseInformationW );
1516 /* @@ Wine registry key: HKLM\Software\Wine\LicenseInformation */
1517 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
1519 status = NtQueryValueKey( hkey, name, KeyValuePartialInformation,
1520 info, info_length, &count );
1521 if (!status || status == STATUS_BUFFER_OVERFLOW)
1523 if (result_type)
1524 *result_type = info->Type;
1526 *result_len = info->DataLength;
1528 if (status == STATUS_BUFFER_OVERFLOW)
1529 status = STATUS_BUFFER_TOO_SMALL;
1530 else
1531 memcpy( data, info->Data, info->DataLength );
1533 NtClose( hkey );
1536 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1537 FIXME( "License key %s not found\n", debugstr_w(name->Buffer) );
1539 RtlFreeHeap( GetProcessHeap(), 0, info );
1540 return status;