ntdll: Pass SYNCHRONIZE flag in NtOpenFile and NtCreateFile calls.
[wine.git] / dlls / ntdll / reg.c
blob61564091c4b3534f9497201f0598691d39c70d11
1 /*
2 * Registry functions
4 * Copyright (C) 1999 Juergen Schmied
5 * Copyright (C) 2000 Alexandre Julliard
6 * Copyright 2005 Ivan Leo Puoti, Laurent Pinchart
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * NOTES:
23 * HKEY_LOCAL_MACHINE \\REGISTRY\\MACHINE
24 * HKEY_USERS \\REGISTRY\\USER
25 * HKEY_CURRENT_CONFIG \\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT
26 * HKEY_CLASSES \\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES
29 #include "config.h"
30 #include "wine/port.h"
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <string.h>
36 #include "ntstatus.h"
37 #define WIN32_NO_STATUS
38 #include "wine/library.h"
39 #include "ntdll_misc.h"
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(reg);
45 /* maximum length of a value name in bytes (without terminating null) */
46 #define MAX_VALUE_LENGTH (16383 * sizeof(WCHAR))
48 /******************************************************************************
49 * NtCreateKey [NTDLL.@]
50 * ZwCreateKey [NTDLL.@]
52 NTSTATUS WINAPI NtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
53 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
54 PULONG dispos )
56 NTSTATUS ret;
57 data_size_t len;
58 struct object_attributes *objattr;
60 if (!retkey || !attr) return STATUS_ACCESS_VIOLATION;
61 if (attr->Length > sizeof(OBJECT_ATTRIBUTES)) return STATUS_INVALID_PARAMETER;
63 TRACE( "(%p,%s,%s,%x,%x,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
64 debugstr_us(class), options, access, retkey );
66 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
68 SERVER_START_REQ( create_key )
70 req->access = access;
71 req->options = options;
72 wine_server_add_data( req, objattr, len );
73 if (class) wine_server_add_data( req, class->Buffer, class->Length );
74 if (!(ret = wine_server_call( req )))
76 *retkey = wine_server_ptr_handle( reply->hkey );
77 if (dispos) *dispos = reply->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
80 SERVER_END_REQ;
82 TRACE("<- %p\n", *retkey);
83 RtlFreeHeap( GetProcessHeap(), 0, objattr );
84 return ret;
87 NTSTATUS WINAPI NtCreateKeyTransacted( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
88 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
89 HANDLE transacted, ULONG *dispos )
91 FIXME( "(%p,%s,%s,%x,%x,%p,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
92 debugstr_us(class), options, access, transacted, retkey );
93 return STATUS_NOT_IMPLEMENTED;
96 NTSTATUS WINAPI NtRenameKey( HANDLE handle, UNICODE_STRING *name )
98 FIXME( "(%p %s)\n", handle, debugstr_us(name) );
99 return STATUS_NOT_IMPLEMENTED;
102 /******************************************************************************
103 * RtlpNtCreateKey [NTDLL.@]
105 * See NtCreateKey.
107 NTSTATUS WINAPI RtlpNtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
108 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
109 PULONG dispos )
111 OBJECT_ATTRIBUTES oa;
113 if (attr)
115 oa = *attr;
116 oa.Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
117 attr = &oa;
120 return NtCreateKey(retkey, access, attr, 0, NULL, 0, dispos);
123 /******************************************************************************
124 * NtOpenKeyEx [NTDLL.@]
125 * ZwOpenKeyEx [NTDLL.@]
127 NTSTATUS WINAPI NtOpenKeyEx( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, ULONG options )
129 NTSTATUS ret;
131 if (!retkey || !attr || !attr->ObjectName) return STATUS_ACCESS_VIOLATION;
132 if ((ret = validate_open_object_attributes( attr ))) return ret;
134 TRACE( "(%p,%s,%x,%p)\n", attr->RootDirectory,
135 debugstr_us(attr->ObjectName), access, retkey );
136 if (options)
137 FIXME("options %x not implemented\n", options);
139 SERVER_START_REQ( open_key )
141 req->parent = wine_server_obj_handle( attr->RootDirectory );
142 req->access = access;
143 req->attributes = attr->Attributes;
144 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
145 ret = wine_server_call( req );
146 *retkey = wine_server_ptr_handle( reply->hkey );
148 SERVER_END_REQ;
149 TRACE("<- %p\n", *retkey);
150 return ret;
153 /******************************************************************************
154 * NtOpenKey [NTDLL.@]
155 * ZwOpenKey [NTDLL.@]
157 * OUT HANDLE retkey (returns 0 when failure)
158 * IN ACCESS_MASK access
159 * IN POBJECT_ATTRIBUTES attr
161 NTSTATUS WINAPI NtOpenKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
163 return NtOpenKeyEx( retkey, access, attr, 0 );
166 NTSTATUS WINAPI NtOpenKeyTransactedEx( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
167 ULONG options, HANDLE transaction )
169 FIXME( "(%p %x %p %x %p)\n", retkey, access, attr, options, transaction );
170 return STATUS_NOT_IMPLEMENTED;
173 NTSTATUS WINAPI NtOpenKeyTransacted( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
174 HANDLE transaction )
176 return NtOpenKeyTransactedEx( retkey, access, attr, 0, transaction );
179 /******************************************************************************
180 * RtlpNtOpenKey [NTDLL.@]
182 * See NtOpenKey.
184 NTSTATUS WINAPI RtlpNtOpenKey( PHANDLE retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
186 if (attr)
187 attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
188 return NtOpenKey(retkey, access, attr);
191 /******************************************************************************
192 * NtDeleteKey [NTDLL.@]
193 * ZwDeleteKey [NTDLL.@]
195 NTSTATUS WINAPI NtDeleteKey( HANDLE hkey )
197 NTSTATUS ret;
199 TRACE( "(%p)\n", hkey );
201 SERVER_START_REQ( delete_key )
203 req->hkey = wine_server_obj_handle( hkey );
204 ret = wine_server_call( req );
206 SERVER_END_REQ;
207 return ret;
210 /******************************************************************************
211 * RtlpNtMakeTemporaryKey [NTDLL.@]
213 * See NtDeleteKey.
215 NTSTATUS WINAPI RtlpNtMakeTemporaryKey( HANDLE hkey )
217 return NtDeleteKey(hkey);
220 /******************************************************************************
221 * NtDeleteValueKey [NTDLL.@]
222 * ZwDeleteValueKey [NTDLL.@]
224 NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name )
226 NTSTATUS ret;
228 TRACE( "(%p,%s)\n", hkey, debugstr_us(name) );
229 if (name->Length > MAX_VALUE_LENGTH) return STATUS_OBJECT_NAME_NOT_FOUND;
231 SERVER_START_REQ( delete_key_value )
233 req->hkey = wine_server_obj_handle( hkey );
234 wine_server_add_data( req, name->Buffer, name->Length );
235 ret = wine_server_call( req );
237 SERVER_END_REQ;
238 return ret;
242 /******************************************************************************
243 * enumerate_key
245 * Implementation of NtQueryKey and NtEnumerateKey
247 static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS info_class,
248 void *info, DWORD length, DWORD *result_len )
251 NTSTATUS ret;
252 void *data_ptr;
253 size_t fixed_size;
255 switch(info_class)
257 case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break;
258 case KeyFullInformation: data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
259 case KeyNodeInformation: data_ptr = ((KEY_NODE_INFORMATION *)info)->Name; break;
260 case KeyNameInformation: data_ptr = ((KEY_NAME_INFORMATION *)info)->Name; break;
261 case KeyCachedInformation: data_ptr = ((KEY_CACHED_INFORMATION *)info)+1; break;
262 default:
263 FIXME( "Information class %d not implemented\n", info_class );
264 return STATUS_INVALID_PARAMETER;
266 fixed_size = (char *)data_ptr - (char *)info;
268 SERVER_START_REQ( enum_key )
270 req->hkey = wine_server_obj_handle( handle );
271 req->index = index;
272 req->info_class = info_class;
273 if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
274 if (!(ret = wine_server_call( req )))
276 switch(info_class)
278 case KeyBasicInformation:
280 KEY_BASIC_INFORMATION keyinfo;
281 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
282 keyinfo.LastWriteTime.QuadPart = reply->modif;
283 keyinfo.TitleIndex = 0;
284 keyinfo.NameLength = reply->namelen;
285 memcpy( info, &keyinfo, min( length, fixed_size ) );
287 break;
288 case KeyFullInformation:
290 KEY_FULL_INFORMATION keyinfo;
291 fixed_size = (char *)keyinfo.Class - (char *)&keyinfo;
292 keyinfo.LastWriteTime.QuadPart = reply->modif;
293 keyinfo.TitleIndex = 0;
294 keyinfo.ClassLength = wine_server_reply_size(reply);
295 keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
296 keyinfo.SubKeys = reply->subkeys;
297 keyinfo.MaxNameLen = reply->max_subkey;
298 keyinfo.MaxClassLen = reply->max_class;
299 keyinfo.Values = reply->values;
300 keyinfo.MaxValueNameLen = reply->max_value;
301 keyinfo.MaxValueDataLen = reply->max_data;
302 memcpy( info, &keyinfo, min( length, fixed_size ) );
304 break;
305 case KeyNodeInformation:
307 KEY_NODE_INFORMATION keyinfo;
308 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
309 keyinfo.LastWriteTime.QuadPart = reply->modif;
310 keyinfo.TitleIndex = 0;
311 if (reply->namelen < wine_server_reply_size(reply))
313 keyinfo.ClassLength = wine_server_reply_size(reply) - reply->namelen;
314 keyinfo.ClassOffset = fixed_size + reply->namelen;
316 else
318 keyinfo.ClassLength = 0;
319 keyinfo.ClassOffset = -1;
321 keyinfo.NameLength = reply->namelen;
322 memcpy( info, &keyinfo, min( length, fixed_size ) );
324 break;
325 case KeyNameInformation:
327 KEY_NAME_INFORMATION keyinfo;
328 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
329 keyinfo.NameLength = reply->namelen;
330 memcpy( info, &keyinfo, min( length, fixed_size ) );
332 break;
333 case KeyCachedInformation:
335 KEY_CACHED_INFORMATION keyinfo;
336 fixed_size = sizeof(keyinfo);
337 keyinfo.LastWriteTime.QuadPart = reply->modif;
338 keyinfo.TitleIndex = 0;
339 keyinfo.SubKeys = reply->subkeys;
340 keyinfo.MaxNameLen = reply->max_subkey;
341 keyinfo.Values = reply->values;
342 keyinfo.MaxValueNameLen = reply->max_value;
343 keyinfo.MaxValueDataLen = reply->max_data;
344 keyinfo.NameLength = reply->namelen;
345 memcpy( info, &keyinfo, min( length, fixed_size ) );
347 break;
348 default:
349 break;
351 *result_len = fixed_size + reply->total;
352 if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
355 SERVER_END_REQ;
356 return ret;
361 /******************************************************************************
362 * NtEnumerateKey [NTDLL.@]
363 * ZwEnumerateKey [NTDLL.@]
365 * NOTES
366 * the name copied into the buffer is NOT 0-terminated
368 NTSTATUS WINAPI NtEnumerateKey( HANDLE handle, ULONG index, KEY_INFORMATION_CLASS info_class,
369 void *info, DWORD length, DWORD *result_len )
371 /* -1 means query key, so avoid it here */
372 if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
373 return enumerate_key( handle, index, info_class, info, length, result_len );
377 /******************************************************************************
378 * RtlpNtEnumerateSubKey [NTDLL.@]
381 NTSTATUS WINAPI RtlpNtEnumerateSubKey( HANDLE handle, UNICODE_STRING *out, ULONG index )
383 KEY_BASIC_INFORMATION *info;
384 DWORD dwLen, dwResultLen;
385 NTSTATUS ret;
387 if (out->Length)
389 dwLen = out->Length + sizeof(KEY_BASIC_INFORMATION);
390 info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
391 if (!info)
392 return STATUS_NO_MEMORY;
394 else
396 dwLen = 0;
397 info = NULL;
400 ret = NtEnumerateKey( handle, index, KeyBasicInformation, info, dwLen, &dwResultLen );
401 dwResultLen -= sizeof(KEY_BASIC_INFORMATION);
403 if (ret == STATUS_BUFFER_OVERFLOW)
404 out->Length = dwResultLen;
405 else if (!ret)
407 if (out->Length < info->NameLength)
409 out->Length = dwResultLen;
410 ret = STATUS_BUFFER_OVERFLOW;
412 else
414 out->Length = info->NameLength;
415 memcpy(out->Buffer, info->Name, info->NameLength);
419 RtlFreeHeap( GetProcessHeap(), 0, info );
420 return ret;
423 /******************************************************************************
424 * NtQueryKey [NTDLL.@]
425 * ZwQueryKey [NTDLL.@]
427 NTSTATUS WINAPI NtQueryKey( HANDLE handle, KEY_INFORMATION_CLASS info_class,
428 void *info, DWORD length, DWORD *result_len )
430 return enumerate_key( handle, -1, info_class, info, length, result_len );
434 /* fill the key value info structure for a specific info class */
435 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info,
436 DWORD length, int type, int name_len, int data_len )
438 switch(info_class)
440 case KeyValueBasicInformation:
442 KEY_VALUE_BASIC_INFORMATION keyinfo;
443 keyinfo.TitleIndex = 0;
444 keyinfo.Type = type;
445 keyinfo.NameLength = name_len;
446 length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
447 memcpy( info, &keyinfo, length );
448 break;
450 case KeyValueFullInformation:
452 KEY_VALUE_FULL_INFORMATION keyinfo;
453 keyinfo.TitleIndex = 0;
454 keyinfo.Type = type;
455 keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len;
456 keyinfo.DataLength = data_len;
457 keyinfo.NameLength = name_len;
458 length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
459 memcpy( info, &keyinfo, length );
460 break;
462 case KeyValuePartialInformation:
464 KEY_VALUE_PARTIAL_INFORMATION keyinfo;
465 keyinfo.TitleIndex = 0;
466 keyinfo.Type = type;
467 keyinfo.DataLength = data_len;
468 length = min( length, (char *)keyinfo.Data - (char *)&keyinfo );
469 memcpy( info, &keyinfo, length );
470 break;
472 default:
473 break;
478 /******************************************************************************
479 * NtEnumerateValueKey [NTDLL.@]
480 * ZwEnumerateValueKey [NTDLL.@]
482 NTSTATUS WINAPI NtEnumerateValueKey( HANDLE handle, ULONG index,
483 KEY_VALUE_INFORMATION_CLASS info_class,
484 void *info, DWORD length, DWORD *result_len )
486 NTSTATUS ret;
487 void *ptr;
488 size_t fixed_size;
490 TRACE( "(%p,%u,%d,%p,%d)\n", handle, index, info_class, info, length );
492 /* compute the length we want to retrieve */
493 switch(info_class)
495 case KeyValueBasicInformation: ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break;
496 case KeyValueFullInformation: ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break;
497 case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break;
498 default:
499 FIXME( "Information class %d not implemented\n", info_class );
500 return STATUS_INVALID_PARAMETER;
502 fixed_size = (char *)ptr - (char *)info;
504 SERVER_START_REQ( enum_key_value )
506 req->hkey = wine_server_obj_handle( handle );
507 req->index = index;
508 req->info_class = info_class;
509 if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size );
510 if (!(ret = wine_server_call( req )))
512 copy_key_value_info( info_class, info, length, reply->type, reply->namelen,
513 wine_server_reply_size(reply) - reply->namelen );
514 *result_len = fixed_size + reply->total;
515 if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
518 SERVER_END_REQ;
519 return ret;
523 /******************************************************************************
524 * NtQueryValueKey [NTDLL.@]
525 * ZwQueryValueKey [NTDLL.@]
527 * NOTES
528 * the name in the KeyValueInformation is never set
530 NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name,
531 KEY_VALUE_INFORMATION_CLASS info_class,
532 void *info, DWORD length, DWORD *result_len )
534 NTSTATUS ret;
535 UCHAR *data_ptr;
536 unsigned int fixed_size, min_size;
538 TRACE( "(%p,%s,%d,%p,%d)\n", handle, debugstr_us(name), info_class, info, length );
540 if (name->Length > MAX_VALUE_LENGTH) return STATUS_OBJECT_NAME_NOT_FOUND;
542 /* compute the length we want to retrieve */
543 switch(info_class)
545 case KeyValueBasicInformation:
547 KEY_VALUE_BASIC_INFORMATION *basic_info = info;
548 min_size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);
549 fixed_size = min_size + name->Length;
550 if (min_size < length)
551 memcpy(basic_info->Name, name->Buffer, min(length - min_size, name->Length));
552 data_ptr = NULL;
553 break;
555 case KeyValueFullInformation:
557 KEY_VALUE_FULL_INFORMATION *full_info = info;
558 min_size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
559 fixed_size = min_size + name->Length;
560 if (min_size < length)
561 memcpy(full_info->Name, name->Buffer, min(length - min_size, name->Length));
562 data_ptr = (UCHAR *)full_info->Name + name->Length;
563 break;
565 case KeyValuePartialInformation:
566 min_size = fixed_size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
567 data_ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data;
568 break;
569 default:
570 FIXME( "Information class %d not implemented\n", info_class );
571 return STATUS_INVALID_PARAMETER;
574 SERVER_START_REQ( get_key_value )
576 req->hkey = wine_server_obj_handle( handle );
577 wine_server_add_data( req, name->Buffer, name->Length );
578 if (length > fixed_size && data_ptr) wine_server_set_reply( req, data_ptr, length - fixed_size );
579 if (!(ret = wine_server_call( req )))
581 copy_key_value_info( info_class, info, length, reply->type,
582 name->Length, reply->total );
583 *result_len = fixed_size + (info_class == KeyValueBasicInformation ? 0 : reply->total);
584 if (length < min_size) ret = STATUS_BUFFER_TOO_SMALL;
585 else if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
588 SERVER_END_REQ;
589 return ret;
592 /******************************************************************************
593 * RtlpNtQueryValueKey [NTDLL.@]
596 NTSTATUS WINAPI RtlpNtQueryValueKey( HANDLE handle, ULONG *result_type, PBYTE dest,
597 DWORD *result_len, void *unknown )
599 KEY_VALUE_PARTIAL_INFORMATION *info;
600 UNICODE_STRING name;
601 NTSTATUS ret;
602 DWORD dwResultLen;
603 DWORD dwLen = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + (result_len ? *result_len : 0);
605 info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
606 if (!info)
607 return STATUS_NO_MEMORY;
609 name.Length = 0;
610 ret = NtQueryValueKey( handle, &name, KeyValuePartialInformation, info, dwLen, &dwResultLen );
612 if (!ret || ret == STATUS_BUFFER_OVERFLOW)
614 if (result_len)
615 *result_len = info->DataLength;
617 if (result_type)
618 *result_type = info->Type;
620 if (ret != STATUS_BUFFER_OVERFLOW)
621 memcpy( dest, info->Data, info->DataLength );
624 RtlFreeHeap( GetProcessHeap(), 0, info );
625 return ret;
628 /******************************************************************************
629 * NtFlushKey [NTDLL.@]
630 * ZwFlushKey [NTDLL.@]
632 NTSTATUS WINAPI NtFlushKey(HANDLE key)
634 NTSTATUS ret;
636 TRACE("key=%p\n", key);
638 SERVER_START_REQ( flush_key )
640 req->hkey = wine_server_obj_handle( key );
641 ret = wine_server_call( req );
643 SERVER_END_REQ;
645 return ret;
648 /******************************************************************************
649 * NtLoadKey [NTDLL.@]
650 * ZwLoadKey [NTDLL.@]
652 NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file )
654 NTSTATUS ret;
655 HANDLE hive;
656 IO_STATUS_BLOCK io;
657 data_size_t len;
658 struct object_attributes *objattr;
660 TRACE("(%p,%p)\n", attr, file);
662 ret = NtCreateFile(&hive, GENERIC_READ | SYNCHRONIZE, file, &io, NULL, FILE_ATTRIBUTE_NORMAL, 0,
663 FILE_OPEN, 0, NULL, 0);
664 if (ret) return ret;
666 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
668 SERVER_START_REQ( load_registry )
670 req->file = wine_server_obj_handle( hive );
671 wine_server_add_data( req, objattr, len );
672 ret = wine_server_call( req );
674 SERVER_END_REQ;
676 NtClose(hive);
677 RtlFreeHeap( GetProcessHeap(), 0, objattr );
678 return ret;
681 /******************************************************************************
682 * NtNotifyChangeMultipleKeys [NTDLL.@]
683 * ZwNotifyChangeMultipleKeys [NTDLL.@]
685 NTSTATUS WINAPI NtNotifyChangeMultipleKeys(
686 HANDLE KeyHandle,
687 ULONG Count,
688 OBJECT_ATTRIBUTES *SubordinateObjects,
689 HANDLE Event,
690 PIO_APC_ROUTINE ApcRoutine,
691 PVOID ApcContext,
692 PIO_STATUS_BLOCK IoStatusBlock,
693 ULONG CompletionFilter,
694 BOOLEAN WatchSubtree,
695 PVOID ChangeBuffer,
696 ULONG Length,
697 BOOLEAN Asynchronous)
699 NTSTATUS ret;
701 TRACE("(%p,%u,%p,%p,%p,%p,%p,0x%08x, 0x%08x,%p,0x%08x,0x%08x)\n",
702 KeyHandle, Count, SubordinateObjects, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
703 Asynchronous, ChangeBuffer, Length, WatchSubtree);
705 if (Count || SubordinateObjects || ApcRoutine || ApcContext || ChangeBuffer || Length)
706 FIXME("Unimplemented optional parameter\n");
708 if (!Asynchronous)
710 OBJECT_ATTRIBUTES attr;
711 InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
712 ret = NtCreateEvent( &Event, EVENT_ALL_ACCESS, &attr, SynchronizationEvent, FALSE );
713 if (ret != STATUS_SUCCESS)
714 return ret;
717 SERVER_START_REQ( set_registry_notification )
719 req->hkey = wine_server_obj_handle( KeyHandle );
720 req->event = wine_server_obj_handle( Event );
721 req->subtree = WatchSubtree;
722 req->filter = CompletionFilter;
723 ret = wine_server_call( req );
725 SERVER_END_REQ;
727 if (!Asynchronous)
729 if (ret == STATUS_PENDING)
730 ret = NtWaitForSingleObject( Event, FALSE, NULL );
731 NtClose( Event );
734 return ret;
737 /******************************************************************************
738 * NtNotifyChangeKey [NTDLL.@]
739 * ZwNotifyChangeKey [NTDLL.@]
741 NTSTATUS WINAPI NtNotifyChangeKey(
742 IN HANDLE KeyHandle,
743 IN HANDLE Event,
744 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
745 IN PVOID ApcContext OPTIONAL,
746 OUT PIO_STATUS_BLOCK IoStatusBlock,
747 IN ULONG CompletionFilter,
748 IN BOOLEAN WatchSubtree,
749 OUT PVOID ChangeBuffer,
750 IN ULONG Length,
751 IN BOOLEAN Asynchronous)
753 return NtNotifyChangeMultipleKeys(KeyHandle, 0, NULL, Event, ApcRoutine, ApcContext,
754 IoStatusBlock, CompletionFilter, WatchSubtree,
755 ChangeBuffer, Length, Asynchronous);
758 /******************************************************************************
759 * NtQueryMultipleValueKey [NTDLL]
760 * ZwQueryMultipleValueKey
763 NTSTATUS WINAPI NtQueryMultipleValueKey(
764 HANDLE KeyHandle,
765 PKEY_MULTIPLE_VALUE_INFORMATION ListOfValuesToQuery,
766 ULONG NumberOfItems,
767 PVOID MultipleValueInformation,
768 ULONG Length,
769 PULONG ReturnLength)
771 FIXME("(%p,%p,0x%08x,%p,0x%08x,%p) stub!\n",
772 KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
773 Length,ReturnLength);
774 return STATUS_SUCCESS;
777 /******************************************************************************
778 * NtReplaceKey [NTDLL.@]
779 * ZwReplaceKey [NTDLL.@]
781 NTSTATUS WINAPI NtReplaceKey(
782 IN POBJECT_ATTRIBUTES ObjectAttributes,
783 IN HANDLE Key,
784 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
786 FIXME("(%s,%p,%s),stub!\n", debugstr_ObjectAttributes(ObjectAttributes), Key,
787 debugstr_ObjectAttributes(ReplacedObjectAttributes) );
788 return STATUS_SUCCESS;
790 /******************************************************************************
791 * NtRestoreKey [NTDLL.@]
792 * ZwRestoreKey [NTDLL.@]
794 NTSTATUS WINAPI NtRestoreKey(
795 HANDLE KeyHandle,
796 HANDLE FileHandle,
797 ULONG RestoreFlags)
799 FIXME("(%p,%p,0x%08x) stub\n",
800 KeyHandle, FileHandle, RestoreFlags);
801 return STATUS_SUCCESS;
803 /******************************************************************************
804 * NtSaveKey [NTDLL.@]
805 * ZwSaveKey [NTDLL.@]
807 NTSTATUS WINAPI NtSaveKey(IN HANDLE KeyHandle, IN HANDLE FileHandle)
809 NTSTATUS ret;
811 TRACE("(%p,%p)\n", KeyHandle, FileHandle);
813 SERVER_START_REQ( save_registry )
815 req->hkey = wine_server_obj_handle( KeyHandle );
816 req->file = wine_server_obj_handle( FileHandle );
817 ret = wine_server_call( req );
819 SERVER_END_REQ;
821 return ret;
823 /******************************************************************************
824 * NtSetInformationKey [NTDLL.@]
825 * ZwSetInformationKey [NTDLL.@]
827 NTSTATUS WINAPI NtSetInformationKey(
828 IN HANDLE KeyHandle,
829 IN const int KeyInformationClass,
830 IN PVOID KeyInformation,
831 IN ULONG KeyInformationLength)
833 FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
834 KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
835 return STATUS_SUCCESS;
839 /******************************************************************************
840 * NtSetValueKey [NTDLL.@]
841 * ZwSetValueKey [NTDLL.@]
843 * NOTES
844 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
845 * NT does definitely care (aj)
847 NTSTATUS WINAPI NtSetValueKey( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
848 ULONG type, const void *data, ULONG count )
850 NTSTATUS ret;
852 TRACE( "(%p,%s,%d,%p,%d)\n", hkey, debugstr_us(name), type, data, count );
854 if (name->Length > MAX_VALUE_LENGTH) return STATUS_INVALID_PARAMETER;
856 SERVER_START_REQ( set_key_value )
858 req->hkey = wine_server_obj_handle( hkey );
859 req->type = type;
860 req->namelen = name->Length;
861 wine_server_add_data( req, name->Buffer, name->Length );
862 wine_server_add_data( req, data, count );
863 ret = wine_server_call( req );
865 SERVER_END_REQ;
866 return ret;
869 /******************************************************************************
870 * RtlpNtSetValueKey [NTDLL.@]
873 NTSTATUS WINAPI RtlpNtSetValueKey( HANDLE hkey, ULONG type, const void *data,
874 ULONG count )
876 UNICODE_STRING name;
878 name.Length = 0;
879 return NtSetValueKey( hkey, &name, 0, type, data, count );
882 /******************************************************************************
883 * NtUnloadKey [NTDLL.@]
884 * ZwUnloadKey [NTDLL.@]
886 NTSTATUS WINAPI NtUnloadKey(IN POBJECT_ATTRIBUTES attr)
888 NTSTATUS ret;
890 TRACE("(%p)\n", attr);
892 SERVER_START_REQ( unload_registry )
894 req->hkey = wine_server_obj_handle( attr->RootDirectory );
895 ret = wine_server_call(req);
897 SERVER_END_REQ;
899 return ret;
902 /******************************************************************************
903 * RtlFormatCurrentUserKeyPath [NTDLL.@]
906 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
908 static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
909 HANDLE token;
910 NTSTATUS status;
912 status = NtOpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &token);
913 if (status == STATUS_NO_TOKEN)
914 status = NtOpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token);
915 if (status == STATUS_SUCCESS)
917 char buffer[sizeof(TOKEN_USER) + sizeof(SID) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES];
918 DWORD len = sizeof(buffer);
920 status = NtQueryInformationToken(token, TokenUser, buffer, len, &len);
921 if (status == STATUS_SUCCESS)
923 KeyPath->MaximumLength = 0;
924 status = RtlConvertSidToUnicodeString(KeyPath, ((TOKEN_USER *)buffer)->User.Sid, FALSE);
925 if (status == STATUS_BUFFER_OVERFLOW)
927 PWCHAR buf = RtlAllocateHeap(GetProcessHeap(), 0,
928 sizeof(pathW) + KeyPath->Length + sizeof(WCHAR));
929 if (buf)
931 memcpy(buf, pathW, sizeof(pathW));
932 KeyPath->MaximumLength = KeyPath->Length + sizeof(WCHAR);
933 KeyPath->Buffer = (PWCHAR)((LPBYTE)buf + sizeof(pathW));
934 status = RtlConvertSidToUnicodeString(KeyPath,
935 ((TOKEN_USER *)buffer)->User.Sid, FALSE);
936 KeyPath->Buffer = buf;
937 KeyPath->Length += sizeof(pathW);
938 KeyPath->MaximumLength += sizeof(pathW);
940 else
941 status = STATUS_NO_MEMORY;
944 NtClose(token);
946 return status;
949 /******************************************************************************
950 * RtlOpenCurrentUser [NTDLL.@]
952 * NOTES
953 * If we return just HKEY_CURRENT_USER the advapi tries to find a remote
954 * registry (odd handle) and fails.
956 NTSTATUS WINAPI RtlOpenCurrentUser(
957 IN ACCESS_MASK DesiredAccess, /* [in] */
958 OUT PHANDLE KeyHandle) /* [out] handle of HKEY_CURRENT_USER */
960 OBJECT_ATTRIBUTES ObjectAttributes;
961 UNICODE_STRING ObjectName;
962 NTSTATUS ret;
964 TRACE("(0x%08x, %p)\n",DesiredAccess, KeyHandle);
966 if ((ret = RtlFormatCurrentUserKeyPath(&ObjectName))) return ret;
967 InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
968 ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
969 RtlFreeUnicodeString(&ObjectName);
970 return ret;
974 static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
975 PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
977 PUNICODE_STRING str;
978 UNICODE_STRING src, dst;
979 LONG *bin;
980 ULONG offset;
981 PWSTR wstr;
982 DWORD res;
983 NTSTATUS status = STATUS_SUCCESS;
984 ULONG len;
985 LPWSTR String;
986 ULONG count = 0;
988 if (pInfo == NULL)
990 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
991 return STATUS_INVALID_PARAMETER;
992 else
994 status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
995 pQuery->DefaultLength, pContext, pQuery->EntryContext);
997 return status;
999 len = pInfo->DataLength;
1001 if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
1003 str = pQuery->EntryContext;
1005 switch(pInfo->Type)
1007 case REG_EXPAND_SZ:
1008 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
1010 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1011 res = 0;
1012 dst.MaximumLength = 0;
1013 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1014 dst.Length = 0;
1015 dst.MaximumLength = res;
1016 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1017 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1018 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1019 dst.Length, pContext, pQuery->EntryContext);
1020 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1023 case REG_SZ:
1024 case REG_LINK:
1025 if (str->Buffer == NULL)
1026 RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1027 else
1028 RtlAppendUnicodeToString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1029 break;
1031 case REG_MULTI_SZ:
1032 if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
1033 return STATUS_INVALID_PARAMETER;
1035 if (str->Buffer == NULL)
1037 str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1038 str->MaximumLength = len;
1040 len = min(len, str->MaximumLength);
1041 memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
1042 str->Length = len;
1043 break;
1045 default:
1046 bin = pQuery->EntryContext;
1047 if (pInfo->DataLength <= sizeof(ULONG))
1048 memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
1049 pInfo->DataLength);
1050 else
1052 if (bin[0] <= sizeof(ULONG))
1054 memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
1055 min(-bin[0], pInfo->DataLength));
1057 else
1059 len = min(bin[0], pInfo->DataLength);
1060 bin[1] = len;
1061 bin[2] = pInfo->Type;
1062 memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
1065 break;
1068 else
1070 if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
1071 (pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
1073 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type,
1074 ((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
1075 pContext, pQuery->EntryContext);
1077 else if (pInfo->Type == REG_EXPAND_SZ)
1079 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1080 res = 0;
1081 dst.MaximumLength = 0;
1082 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1083 dst.Length = 0;
1084 dst.MaximumLength = res;
1085 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1086 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1087 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1088 dst.Length, pContext, pQuery->EntryContext);
1089 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1091 else /* REG_MULTI_SZ */
1093 if(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
1095 for (offset = 0; offset <= pInfo->DataLength; offset += len + sizeof(WCHAR))
1097 wstr = (WCHAR*)(((CHAR*)pInfo) + offset);
1098 len = strlenW(wstr) * sizeof(WCHAR);
1099 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, wstr, len,
1100 pContext, pQuery->EntryContext);
1101 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1102 return status;
1105 else
1107 while(count<=pInfo->DataLength)
1109 String = (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset)+count;
1110 count+=strlenW(String)+1;
1111 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1112 res = 0;
1113 dst.MaximumLength = 0;
1114 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1115 dst.Length = 0;
1116 dst.MaximumLength = res;
1117 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1118 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1119 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1120 dst.Length, pContext, pQuery->EntryContext);
1121 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1122 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1123 return status;
1128 return status;
1132 static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
1134 UNICODE_STRING KeyString;
1135 OBJECT_ATTRIBUTES regkey;
1136 PCWSTR base;
1137 INT len;
1138 NTSTATUS status;
1140 static const WCHAR empty[] = {0};
1141 static const WCHAR control[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1142 '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1143 'C','o','n','t','r','o','l','\\',0};
1145 static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1146 'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1148 static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1149 'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1150 'S','e','r','v','i','c','e','s','\\',0};
1152 static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1153 'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1155 static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1156 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1157 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1159 switch (RelativeTo & 0xff)
1161 case RTL_REGISTRY_ABSOLUTE:
1162 base = empty;
1163 break;
1165 case RTL_REGISTRY_CONTROL:
1166 base = control;
1167 break;
1169 case RTL_REGISTRY_DEVICEMAP:
1170 base = devicemap;
1171 break;
1173 case RTL_REGISTRY_SERVICES:
1174 base = services;
1175 break;
1177 case RTL_REGISTRY_USER:
1178 base = user;
1179 break;
1181 case RTL_REGISTRY_WINDOWS_NT:
1182 base = windows_nt;
1183 break;
1185 default:
1186 return STATUS_INVALID_PARAMETER;
1189 len = (strlenW(base) + strlenW(Path) + 1) * sizeof(WCHAR);
1190 KeyString.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1191 if (KeyString.Buffer == NULL)
1192 return STATUS_NO_MEMORY;
1194 strcpyW(KeyString.Buffer, base);
1195 strcatW(KeyString.Buffer, Path);
1196 KeyString.Length = len - sizeof(WCHAR);
1197 KeyString.MaximumLength = len;
1198 InitializeObjectAttributes(&regkey, &KeyString, OBJ_CASE_INSENSITIVE, NULL, NULL);
1199 status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
1200 RtlFreeHeap(GetProcessHeap(), 0, KeyString.Buffer);
1201 return status;
1204 /*************************************************************************
1205 * RtlQueryRegistryValues [NTDLL.@]
1207 * Query multiple registry values with a signle call.
1209 * PARAMS
1210 * RelativeTo [I] Registry path that Path refers to
1211 * Path [I] Path to key
1212 * QueryTable [I] Table of key values to query
1213 * Context [I] Parameter to pass to the application defined QueryRoutine function
1214 * Environment [I] Optional parameter to use when performing expansion
1216 * RETURNS
1217 * STATUS_SUCCESS or an appropriate NTSTATUS error code.
1219 NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
1220 IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
1221 IN PVOID Environment OPTIONAL)
1223 UNICODE_STRING Value;
1224 HANDLE handle, topkey;
1225 PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
1226 ULONG len, buflen = 0;
1227 NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
1228 INT i;
1230 TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
1232 if(Path == NULL)
1233 return STATUS_INVALID_PARAMETER;
1235 /* get a valid handle */
1236 if (RelativeTo & RTL_REGISTRY_HANDLE)
1237 topkey = handle = (HANDLE)Path;
1238 else
1240 status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
1241 handle = topkey;
1243 if(status != STATUS_SUCCESS)
1244 return status;
1246 /* Process query table entries */
1247 for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
1249 if (QueryTable->Flags &
1250 (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
1252 /* topkey must be kept open just in case we will reuse it later */
1253 if (handle != topkey)
1254 NtClose(handle);
1256 if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
1258 handle = 0;
1259 status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
1260 if(status != STATUS_SUCCESS)
1262 ret = status;
1263 goto out;
1266 else
1267 handle = topkey;
1270 if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
1272 QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
1273 Context, QueryTable->EntryContext);
1274 continue;
1277 if (!handle)
1279 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1281 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1282 goto out;
1284 continue;
1287 if (QueryTable->Name == NULL)
1289 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
1291 ret = STATUS_INVALID_PARAMETER;
1292 goto out;
1295 /* Report all subkeys */
1296 for (i = 0;; ++i)
1298 status = NtEnumerateValueKey(handle, i,
1299 KeyValueFullInformation, pInfo, buflen, &len);
1300 if (status == STATUS_NO_MORE_ENTRIES)
1301 break;
1302 if (status == STATUS_BUFFER_OVERFLOW ||
1303 status == STATUS_BUFFER_TOO_SMALL)
1305 buflen = len;
1306 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1307 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1308 NtEnumerateValueKey(handle, i, KeyValueFullInformation,
1309 pInfo, buflen, &len);
1312 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1313 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1315 ret = status;
1316 goto out;
1318 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1320 RtlInitUnicodeString(&Value, pInfo->Name);
1321 NtDeleteValueKey(handle, &Value);
1325 if (i == 0 && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
1327 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1328 goto out;
1331 else
1333 RtlInitUnicodeString(&Value, QueryTable->Name);
1334 status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
1335 pInfo, buflen, &len);
1336 if (status == STATUS_BUFFER_OVERFLOW ||
1337 status == STATUS_BUFFER_TOO_SMALL)
1339 buflen = len;
1340 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1341 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1342 status = NtQueryValueKey(handle, &Value,
1343 KeyValueFullInformation, pInfo, buflen, &len);
1345 if (status != STATUS_SUCCESS)
1347 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1349 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1350 goto out;
1352 status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
1353 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1355 ret = status;
1356 goto out;
1359 else
1361 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1362 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1364 ret = status;
1365 goto out;
1367 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1368 NtDeleteValueKey(handle, &Value);
1373 out:
1374 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1375 if (handle != topkey)
1376 NtClose(handle);
1377 NtClose(topkey);
1378 return ret;
1381 /*************************************************************************
1382 * RtlCheckRegistryKey [NTDLL.@]
1384 * Query multiple registry values with a signle call.
1386 * PARAMS
1387 * RelativeTo [I] Registry path that Path refers to
1388 * Path [I] Path to key
1390 * RETURNS
1391 * STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1393 NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
1395 HANDLE handle;
1396 NTSTATUS status;
1398 TRACE("(%d, %s)\n", RelativeTo, debugstr_w(Path));
1400 if((!RelativeTo) && Path == NULL)
1401 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1402 if(RelativeTo & RTL_REGISTRY_HANDLE)
1403 return STATUS_SUCCESS;
1405 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1406 if (handle) NtClose(handle);
1407 if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
1408 return status;
1411 /*************************************************************************
1412 * RtlDeleteRegistryValue [NTDLL.@]
1414 * Query multiple registry values with a signle call.
1416 * PARAMS
1417 * RelativeTo [I] Registry path that Path refers to
1418 * Path [I] Path to key
1419 * ValueName [I] Name of the value to delete
1421 * RETURNS
1422 * STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1424 NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
1426 NTSTATUS status;
1427 HANDLE handle;
1428 UNICODE_STRING Value;
1430 TRACE("(%d, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
1432 RtlInitUnicodeString(&Value, ValueName);
1433 if(RelativeTo == RTL_REGISTRY_HANDLE)
1435 return NtDeleteValueKey((HANDLE)Path, &Value);
1437 status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1438 if (status) return status;
1439 status = NtDeleteValueKey(handle, &Value);
1440 NtClose(handle);
1441 return status;
1444 /*************************************************************************
1445 * RtlWriteRegistryValue [NTDLL.@]
1447 * Sets the registry value with provided data.
1449 * PARAMS
1450 * RelativeTo [I] Registry path that path parameter refers to
1451 * path [I] Path to the key (or handle - see RTL_GetKeyHandle)
1452 * name [I] Name of the registry value to set
1453 * type [I] Type of the registry key to set
1454 * data [I] Pointer to the user data to be set
1455 * length [I] Length of the user data pointed by data
1457 * RETURNS
1458 * STATUS_SUCCESS if the specified key is successfully set,
1459 * or an NTSTATUS error code.
1461 NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
1462 ULONG type, PVOID data, ULONG length )
1464 HANDLE hkey;
1465 NTSTATUS status;
1466 UNICODE_STRING str;
1468 TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
1469 type, data, length );
1471 RtlInitUnicodeString( &str, name );
1473 if (RelativeTo == RTL_REGISTRY_HANDLE)
1474 return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
1476 status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
1477 if (status != STATUS_SUCCESS) return status;
1479 status = NtSetValueKey( hkey, &str, 0, type, data, length );
1480 NtClose( hkey );
1482 return status;
1485 /*************************************************************************
1486 * NtQueryLicenseValue [NTDLL.@]
1488 * NOTES
1489 * On Windows all license properties are stored in a single key, but
1490 * unless there is some app which explicitly depends on that, there is
1491 * no good reason to reproduce that.
1493 NTSTATUS WINAPI NtQueryLicenseValue( const UNICODE_STRING *name, ULONG *result_type,
1494 PVOID data, ULONG length, ULONG *result_len )
1496 static const WCHAR LicenseInformationW[] = {'M','a','c','h','i','n','e','\\',
1497 'S','o','f','t','w','a','r','e','\\',
1498 'W','i','n','e','\\','L','i','c','e','n','s','e',
1499 'I','n','f','o','r','m','a','t','i','o','n',0};
1500 KEY_VALUE_PARTIAL_INFORMATION *info;
1501 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
1502 DWORD info_length, count;
1503 OBJECT_ATTRIBUTES attr;
1504 UNICODE_STRING keyW;
1505 HANDLE hkey;
1507 if (!name || !name->Buffer || !name->Length || !result_len)
1508 return STATUS_INVALID_PARAMETER;
1510 info_length = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + length;
1511 info = RtlAllocateHeap( GetProcessHeap(), 0, info_length );
1512 if (!info) return STATUS_NO_MEMORY;
1514 attr.Length = sizeof(attr);
1515 attr.RootDirectory = 0;
1516 attr.ObjectName = &keyW;
1517 attr.Attributes = 0;
1518 attr.SecurityDescriptor = NULL;
1519 attr.SecurityQualityOfService = NULL;
1520 RtlInitUnicodeString( &keyW, LicenseInformationW );
1522 /* @@ Wine registry key: HKLM\Software\Wine\LicenseInformation */
1523 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
1525 status = NtQueryValueKey( hkey, name, KeyValuePartialInformation,
1526 info, info_length, &count );
1527 if (!status || status == STATUS_BUFFER_OVERFLOW)
1529 if (result_type)
1530 *result_type = info->Type;
1532 *result_len = info->DataLength;
1534 if (status == STATUS_BUFFER_OVERFLOW)
1535 status = STATUS_BUFFER_TOO_SMALL;
1536 else
1537 memcpy( data, info->Data, info->DataLength );
1539 NtClose( hkey );
1542 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1543 FIXME( "License key %s not found\n", debugstr_w(name->Buffer) );
1545 RtlFreeHeap( GetProcessHeap(), 0, info );
1546 return status;