usp10/tests: A spelling fix in an ok() message.
[wine.git] / dlls / ntdll / reg.c
blob845e2e030d2c5c024e4c58b22fc439d2d3bba255
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 DECLSPEC_HOTPATCH 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_KeyHandleCreateObject(ULONG RelativeTo, PCWSTR Path, POBJECT_ATTRIBUTES regkey, PUNICODE_STRING str)
1138 PCWSTR base;
1139 INT len;
1141 static const WCHAR empty[] = {0};
1142 static const WCHAR control[] = {'\\','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 'C','o','n','t','r','o','l','\\',0};
1146 static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1147 'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1149 static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1150 'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1151 'S','e','r','v','i','c','e','s','\\',0};
1153 static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1154 'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1156 static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1157 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1158 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1160 switch (RelativeTo & 0xff)
1162 case RTL_REGISTRY_ABSOLUTE:
1163 base = empty;
1164 break;
1166 case RTL_REGISTRY_CONTROL:
1167 base = control;
1168 break;
1170 case RTL_REGISTRY_DEVICEMAP:
1171 base = devicemap;
1172 break;
1174 case RTL_REGISTRY_SERVICES:
1175 base = services;
1176 break;
1178 case RTL_REGISTRY_USER:
1179 base = user;
1180 break;
1182 case RTL_REGISTRY_WINDOWS_NT:
1183 base = windows_nt;
1184 break;
1186 default:
1187 return STATUS_INVALID_PARAMETER;
1190 len = (strlenW(base) + strlenW(Path) + 1) * sizeof(WCHAR);
1191 str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1192 if (str->Buffer == NULL)
1193 return STATUS_NO_MEMORY;
1195 strcpyW(str->Buffer, base);
1196 strcatW(str->Buffer, Path);
1197 str->Length = len - sizeof(WCHAR);
1198 str->MaximumLength = len;
1199 InitializeObjectAttributes(regkey, str, OBJ_CASE_INSENSITIVE, NULL, NULL);
1200 return STATUS_SUCCESS;
1203 static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
1205 OBJECT_ATTRIBUTES regkey;
1206 UNICODE_STRING string;
1207 NTSTATUS status;
1209 status = RTL_KeyHandleCreateObject(RelativeTo, Path, &regkey, &string);
1210 if(status != STATUS_SUCCESS)
1211 return status;
1213 status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
1214 RtlFreeUnicodeString( &string );
1215 return status;
1218 /*************************************************************************
1219 * RtlQueryRegistryValues [NTDLL.@]
1221 * Query multiple registry values with a single call.
1223 * PARAMS
1224 * RelativeTo [I] Registry path that Path refers to
1225 * Path [I] Path to key
1226 * QueryTable [I] Table of key values to query
1227 * Context [I] Parameter to pass to the application defined QueryRoutine function
1228 * Environment [I] Optional parameter to use when performing expansion
1230 * RETURNS
1231 * STATUS_SUCCESS or an appropriate NTSTATUS error code.
1233 NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
1234 IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
1235 IN PVOID Environment OPTIONAL)
1237 UNICODE_STRING Value;
1238 HANDLE handle, topkey;
1239 PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
1240 ULONG len, buflen = 0;
1241 NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
1242 INT i;
1244 TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
1246 if(Path == NULL)
1247 return STATUS_INVALID_PARAMETER;
1249 /* get a valid handle */
1250 if (RelativeTo & RTL_REGISTRY_HANDLE)
1251 topkey = handle = (HANDLE)Path;
1252 else
1254 status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
1255 handle = topkey;
1257 if(status != STATUS_SUCCESS)
1258 return status;
1260 /* Process query table entries */
1261 for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
1263 if (QueryTable->Flags &
1264 (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
1266 /* topkey must be kept open just in case we will reuse it later */
1267 if (handle != topkey)
1268 NtClose(handle);
1270 if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
1272 handle = 0;
1273 status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
1274 if(status != STATUS_SUCCESS)
1276 ret = status;
1277 goto out;
1280 else
1281 handle = topkey;
1284 if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
1286 QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
1287 Context, QueryTable->EntryContext);
1288 continue;
1291 if (!handle)
1293 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1295 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1296 goto out;
1298 continue;
1301 if (QueryTable->Name == NULL)
1303 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
1305 ret = STATUS_INVALID_PARAMETER;
1306 goto out;
1309 /* Report all subkeys */
1310 for (i = 0;; ++i)
1312 status = NtEnumerateValueKey(handle, i,
1313 KeyValueFullInformation, pInfo, buflen, &len);
1314 if (status == STATUS_NO_MORE_ENTRIES)
1315 break;
1316 if (status == STATUS_BUFFER_OVERFLOW ||
1317 status == STATUS_BUFFER_TOO_SMALL)
1319 buflen = len;
1320 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1321 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1322 NtEnumerateValueKey(handle, i, KeyValueFullInformation,
1323 pInfo, buflen, &len);
1326 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1327 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1329 ret = status;
1330 goto out;
1332 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1334 RtlInitUnicodeString(&Value, pInfo->Name);
1335 NtDeleteValueKey(handle, &Value);
1339 if (i == 0 && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
1341 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1342 goto out;
1345 else
1347 RtlInitUnicodeString(&Value, QueryTable->Name);
1348 status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
1349 pInfo, buflen, &len);
1350 if (status == STATUS_BUFFER_OVERFLOW ||
1351 status == STATUS_BUFFER_TOO_SMALL)
1353 buflen = len;
1354 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1355 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1356 status = NtQueryValueKey(handle, &Value,
1357 KeyValueFullInformation, pInfo, buflen, &len);
1359 if (status != STATUS_SUCCESS)
1361 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1363 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1364 goto out;
1366 status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
1367 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1369 ret = status;
1370 goto out;
1373 else
1375 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1376 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1378 ret = status;
1379 goto out;
1381 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1382 NtDeleteValueKey(handle, &Value);
1387 out:
1388 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1389 if (handle != topkey)
1390 NtClose(handle);
1391 NtClose(topkey);
1392 return ret;
1395 /*************************************************************************
1396 * RtlCheckRegistryKey [NTDLL.@]
1398 * Query multiple registry values with a single call.
1400 * PARAMS
1401 * RelativeTo [I] Registry path that Path refers to
1402 * Path [I] Path to key
1404 * RETURNS
1405 * STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1407 NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
1409 HANDLE handle;
1410 NTSTATUS status;
1412 TRACE("(%d, %s)\n", RelativeTo, debugstr_w(Path));
1414 if(!RelativeTo && (Path == NULL || Path[0] == 0))
1415 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1416 if(RelativeTo & RTL_REGISTRY_HANDLE)
1417 return STATUS_SUCCESS;
1418 if((RelativeTo <= RTL_REGISTRY_USER) && (Path == NULL || Path[0] == 0))
1419 return STATUS_SUCCESS;
1421 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1422 if (handle) NtClose(handle);
1423 if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
1424 return status;
1427 /*************************************************************************
1428 * RtlCreateRegistryKey [NTDLL.@]
1430 * Add a key to the registry given by absolute or relative path
1432 * PARAMS
1433 * RelativeTo [I] Registry path that Path refers to
1434 * path [I] Path to key
1436 * RETURNS
1437 * STATUS_SUCCESS or an appropriate NTSTATUS error code.
1439 NTSTATUS WINAPI RtlCreateRegistryKey(ULONG RelativeTo, PWSTR path)
1441 OBJECT_ATTRIBUTES regkey;
1442 UNICODE_STRING string;
1443 HANDLE handle;
1444 NTSTATUS status;
1446 RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
1448 if (!RelativeTo && (path == NULL || path[0] == 0))
1449 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1450 if (RelativeTo <= RTL_REGISTRY_USER && (path == NULL || path[0] == 0))
1451 return STATUS_SUCCESS;
1452 status = RTL_KeyHandleCreateObject(RelativeTo, path, &regkey, &string);
1453 if(status != STATUS_SUCCESS)
1454 return status;
1456 status = NtCreateKey(&handle, KEY_ALL_ACCESS, &regkey, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
1457 if (handle) NtClose(handle);
1458 RtlFreeUnicodeString( &string );
1459 return status;
1462 /*************************************************************************
1463 * RtlDeleteRegistryValue [NTDLL.@]
1465 * Query multiple registry values with a single call.
1467 * PARAMS
1468 * RelativeTo [I] Registry path that Path refers to
1469 * Path [I] Path to key
1470 * ValueName [I] Name of the value to delete
1472 * RETURNS
1473 * STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1475 NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
1477 NTSTATUS status;
1478 HANDLE handle;
1479 UNICODE_STRING Value;
1481 TRACE("(%d, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
1483 RtlInitUnicodeString(&Value, ValueName);
1484 if(RelativeTo == RTL_REGISTRY_HANDLE)
1486 return NtDeleteValueKey((HANDLE)Path, &Value);
1488 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1489 if (status) return status;
1490 status = NtDeleteValueKey(handle, &Value);
1491 NtClose(handle);
1492 return status;
1495 /*************************************************************************
1496 * RtlWriteRegistryValue [NTDLL.@]
1498 * Sets the registry value with provided data.
1500 * PARAMS
1501 * RelativeTo [I] Registry path that path parameter refers to
1502 * path [I] Path to the key (or handle - see RTL_GetKeyHandle)
1503 * name [I] Name of the registry value to set
1504 * type [I] Type of the registry key to set
1505 * data [I] Pointer to the user data to be set
1506 * length [I] Length of the user data pointed by data
1508 * RETURNS
1509 * STATUS_SUCCESS if the specified key is successfully set,
1510 * or an NTSTATUS error code.
1512 NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
1513 ULONG type, PVOID data, ULONG length )
1515 HANDLE hkey;
1516 NTSTATUS status;
1517 UNICODE_STRING str;
1519 TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
1520 type, data, length );
1522 RtlInitUnicodeString( &str, name );
1524 if (RelativeTo == RTL_REGISTRY_HANDLE)
1525 return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
1527 status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
1528 if (status != STATUS_SUCCESS) return status;
1530 status = NtSetValueKey( hkey, &str, 0, type, data, length );
1531 NtClose( hkey );
1533 return status;
1536 /*************************************************************************
1537 * NtQueryLicenseValue [NTDLL.@]
1539 * NOTES
1540 * On Windows all license properties are stored in a single key, but
1541 * unless there is some app which explicitly depends on that, there is
1542 * no good reason to reproduce that.
1544 NTSTATUS WINAPI NtQueryLicenseValue( const UNICODE_STRING *name, ULONG *result_type,
1545 PVOID data, ULONG length, ULONG *result_len )
1547 static const WCHAR LicenseInformationW[] = {'M','a','c','h','i','n','e','\\',
1548 'S','o','f','t','w','a','r','e','\\',
1549 'W','i','n','e','\\','L','i','c','e','n','s','e',
1550 'I','n','f','o','r','m','a','t','i','o','n',0};
1551 KEY_VALUE_PARTIAL_INFORMATION *info;
1552 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
1553 DWORD info_length, count;
1554 OBJECT_ATTRIBUTES attr;
1555 UNICODE_STRING keyW;
1556 HANDLE hkey;
1558 if (!name || !name->Buffer || !name->Length || !result_len)
1559 return STATUS_INVALID_PARAMETER;
1561 info_length = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + length;
1562 info = RtlAllocateHeap( GetProcessHeap(), 0, info_length );
1563 if (!info) return STATUS_NO_MEMORY;
1565 attr.Length = sizeof(attr);
1566 attr.RootDirectory = 0;
1567 attr.ObjectName = &keyW;
1568 attr.Attributes = 0;
1569 attr.SecurityDescriptor = NULL;
1570 attr.SecurityQualityOfService = NULL;
1571 RtlInitUnicodeString( &keyW, LicenseInformationW );
1573 /* @@ Wine registry key: HKLM\Software\Wine\LicenseInformation */
1574 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
1576 status = NtQueryValueKey( hkey, name, KeyValuePartialInformation,
1577 info, info_length, &count );
1578 if (!status || status == STATUS_BUFFER_OVERFLOW)
1580 if (result_type)
1581 *result_type = info->Type;
1583 *result_len = info->DataLength;
1585 if (status == STATUS_BUFFER_OVERFLOW)
1586 status = STATUS_BUFFER_TOO_SMALL;
1587 else
1588 memcpy( data, info->Data, info->DataLength );
1590 NtClose( hkey );
1593 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1594 FIXME( "License key %s not found\n", debugstr_w(name->Buffer) );
1596 RtlFreeHeap( GetProcessHeap(), 0, info );
1597 return status;