iexplore: Add 'HKCR\Applications\iexplore.exe\shell\open\command' key.
[wine.git] / dlls / ntdll / reg.c
blobbe95a2a2f62ab38e59ada1771226b3a5d628da3c
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 key name in bytes (without terminating null) */
46 #define MAX_NAME_LENGTH (255 * sizeof(WCHAR))
47 /* maximum length of a value name in bytes (without terminating null) */
48 #define MAX_VALUE_LENGTH (16383 * sizeof(WCHAR))
50 /******************************************************************************
51 * NtCreateKey [NTDLL.@]
52 * ZwCreateKey [NTDLL.@]
54 NTSTATUS WINAPI NtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
55 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
56 PULONG dispos )
58 NTSTATUS ret;
60 if (!retkey || !attr) return STATUS_ACCESS_VIOLATION;
61 if (attr->Length > sizeof(OBJECT_ATTRIBUTES)) return STATUS_INVALID_PARAMETER;
62 if (attr->ObjectName->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
64 TRACE( "(%p,%s,%s,%x,%x,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
65 debugstr_us(class), options, access, retkey );
67 SERVER_START_REQ( create_key )
69 req->parent = wine_server_obj_handle( attr->RootDirectory );
70 req->access = access;
71 req->attributes = attr->Attributes;
72 req->options = options;
73 req->namelen = attr->ObjectName->Length;
74 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
75 if (class) wine_server_add_data( req, class->Buffer, class->Length );
76 if (!(ret = wine_server_call( req )))
78 *retkey = wine_server_ptr_handle( reply->hkey );
79 if (dispos) *dispos = reply->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
82 SERVER_END_REQ;
83 TRACE("<- %p\n", *retkey);
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;
130 DWORD len;
132 if (!retkey || !attr) return STATUS_ACCESS_VIOLATION;
133 if (attr->Length > sizeof(OBJECT_ATTRIBUTES)) return STATUS_INVALID_PARAMETER;
134 len = attr->ObjectName->Length;
135 TRACE( "(%p,%s,%x,%p)\n", attr->RootDirectory,
136 debugstr_us(attr->ObjectName), access, retkey );
137 if (options)
138 FIXME("options %x not implemented\n", options);
140 if (len > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
142 SERVER_START_REQ( open_key )
144 req->parent = wine_server_obj_handle( attr->RootDirectory );
145 req->access = access;
146 req->attributes = attr->Attributes;
147 wine_server_add_data( req, attr->ObjectName->Buffer, len );
148 ret = wine_server_call( req );
149 *retkey = wine_server_ptr_handle( reply->hkey );
151 SERVER_END_REQ;
152 TRACE("<- %p\n", *retkey);
153 return ret;
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 NtOpenKeyEx( retkey, access, attr, 0 );
169 NTSTATUS WINAPI NtOpenKeyTransactedEx( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
170 ULONG options, HANDLE transaction )
172 FIXME( "(%p %x %p %x %p)\n", retkey, access, attr, options, transaction );
173 return STATUS_NOT_IMPLEMENTED;
176 NTSTATUS WINAPI NtOpenKeyTransacted( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
177 HANDLE transaction )
179 return NtOpenKeyTransactedEx( retkey, access, attr, 0, transaction );
182 /******************************************************************************
183 * RtlpNtOpenKey [NTDLL.@]
185 * See NtOpenKey.
187 NTSTATUS WINAPI RtlpNtOpenKey( PHANDLE retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
189 if (attr)
190 attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
191 return NtOpenKey(retkey, access, attr);
194 /******************************************************************************
195 * NtDeleteKey [NTDLL.@]
196 * ZwDeleteKey [NTDLL.@]
198 NTSTATUS WINAPI NtDeleteKey( HANDLE hkey )
200 NTSTATUS ret;
202 TRACE( "(%p)\n", hkey );
204 SERVER_START_REQ( delete_key )
206 req->hkey = wine_server_obj_handle( hkey );
207 ret = wine_server_call( req );
209 SERVER_END_REQ;
210 return ret;
213 /******************************************************************************
214 * RtlpNtMakeTemporaryKey [NTDLL.@]
216 * See NtDeleteKey.
218 NTSTATUS WINAPI RtlpNtMakeTemporaryKey( HANDLE hkey )
220 return NtDeleteKey(hkey);
223 /******************************************************************************
224 * NtDeleteValueKey [NTDLL.@]
225 * ZwDeleteValueKey [NTDLL.@]
227 NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name )
229 NTSTATUS ret;
231 TRACE( "(%p,%s)\n", hkey, debugstr_us(name) );
232 if (name->Length > MAX_VALUE_LENGTH) return STATUS_OBJECT_NAME_NOT_FOUND;
234 SERVER_START_REQ( delete_key_value )
236 req->hkey = wine_server_obj_handle( hkey );
237 wine_server_add_data( req, name->Buffer, name->Length );
238 ret = wine_server_call( req );
240 SERVER_END_REQ;
241 return ret;
245 /******************************************************************************
246 * enumerate_key
248 * Implementation of NtQueryKey and NtEnumerateKey
250 static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS info_class,
251 void *info, DWORD length, DWORD *result_len )
254 NTSTATUS ret;
255 void *data_ptr;
256 size_t fixed_size;
258 switch(info_class)
260 case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break;
261 case KeyFullInformation: data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
262 case KeyNodeInformation: data_ptr = ((KEY_NODE_INFORMATION *)info)->Name; break;
263 case KeyNameInformation: data_ptr = ((KEY_NAME_INFORMATION *)info)->Name; break;
264 case KeyCachedInformation: data_ptr = ((KEY_CACHED_INFORMATION *)info)+1; break;
265 default:
266 FIXME( "Information class %d not implemented\n", info_class );
267 return STATUS_INVALID_PARAMETER;
269 fixed_size = (char *)data_ptr - (char *)info;
271 SERVER_START_REQ( enum_key )
273 req->hkey = wine_server_obj_handle( handle );
274 req->index = index;
275 req->info_class = info_class;
276 if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
277 if (!(ret = wine_server_call( req )))
279 switch(info_class)
281 case KeyBasicInformation:
283 KEY_BASIC_INFORMATION keyinfo;
284 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
285 keyinfo.LastWriteTime.QuadPart = reply->modif;
286 keyinfo.TitleIndex = 0;
287 keyinfo.NameLength = reply->namelen;
288 memcpy( info, &keyinfo, min( length, fixed_size ) );
290 break;
291 case KeyFullInformation:
293 KEY_FULL_INFORMATION keyinfo;
294 fixed_size = (char *)keyinfo.Class - (char *)&keyinfo;
295 keyinfo.LastWriteTime.QuadPart = reply->modif;
296 keyinfo.TitleIndex = 0;
297 keyinfo.ClassLength = wine_server_reply_size(reply);
298 keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
299 keyinfo.SubKeys = reply->subkeys;
300 keyinfo.MaxNameLen = reply->max_subkey;
301 keyinfo.MaxClassLen = reply->max_class;
302 keyinfo.Values = reply->values;
303 keyinfo.MaxValueNameLen = reply->max_value;
304 keyinfo.MaxValueDataLen = reply->max_data;
305 memcpy( info, &keyinfo, min( length, fixed_size ) );
307 break;
308 case KeyNodeInformation:
310 KEY_NODE_INFORMATION keyinfo;
311 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
312 keyinfo.LastWriteTime.QuadPart = reply->modif;
313 keyinfo.TitleIndex = 0;
314 if (reply->namelen < wine_server_reply_size(reply))
316 keyinfo.ClassLength = wine_server_reply_size(reply) - reply->namelen;
317 keyinfo.ClassOffset = fixed_size + reply->namelen;
319 else
321 keyinfo.ClassLength = 0;
322 keyinfo.ClassOffset = -1;
324 keyinfo.NameLength = reply->namelen;
325 memcpy( info, &keyinfo, min( length, fixed_size ) );
327 break;
328 case KeyNameInformation:
330 KEY_NAME_INFORMATION keyinfo;
331 fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
332 keyinfo.NameLength = reply->namelen;
333 memcpy( info, &keyinfo, min( length, fixed_size ) );
335 break;
336 case KeyCachedInformation:
338 KEY_CACHED_INFORMATION keyinfo;
339 fixed_size = sizeof(keyinfo);
340 keyinfo.LastWriteTime.QuadPart = reply->modif;
341 keyinfo.TitleIndex = 0;
342 keyinfo.SubKeys = reply->subkeys;
343 keyinfo.MaxNameLen = reply->max_subkey;
344 keyinfo.Values = reply->values;
345 keyinfo.MaxValueNameLen = reply->max_value;
346 keyinfo.MaxValueDataLen = reply->max_data;
347 keyinfo.NameLength = reply->namelen;
348 memcpy( info, &keyinfo, min( length, fixed_size ) );
350 break;
351 default:
352 break;
354 *result_len = fixed_size + reply->total;
355 if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
358 SERVER_END_REQ;
359 return ret;
364 /******************************************************************************
365 * NtEnumerateKey [NTDLL.@]
366 * ZwEnumerateKey [NTDLL.@]
368 * NOTES
369 * the name copied into the buffer is NOT 0-terminated
371 NTSTATUS WINAPI NtEnumerateKey( HANDLE handle, ULONG index, KEY_INFORMATION_CLASS info_class,
372 void *info, DWORD length, DWORD *result_len )
374 /* -1 means query key, so avoid it here */
375 if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
376 return enumerate_key( handle, index, info_class, info, length, result_len );
380 /******************************************************************************
381 * RtlpNtEnumerateSubKey [NTDLL.@]
384 NTSTATUS WINAPI RtlpNtEnumerateSubKey( HANDLE handle, UNICODE_STRING *out, ULONG index )
386 KEY_BASIC_INFORMATION *info;
387 DWORD dwLen, dwResultLen;
388 NTSTATUS ret;
390 if (out->Length)
392 dwLen = out->Length + sizeof(KEY_BASIC_INFORMATION);
393 info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
394 if (!info)
395 return STATUS_NO_MEMORY;
397 else
399 dwLen = 0;
400 info = NULL;
403 ret = NtEnumerateKey( handle, index, KeyBasicInformation, info, dwLen, &dwResultLen );
404 dwResultLen -= sizeof(KEY_BASIC_INFORMATION);
406 if (ret == STATUS_BUFFER_OVERFLOW)
407 out->Length = dwResultLen;
408 else if (!ret)
410 if (out->Length < info->NameLength)
412 out->Length = dwResultLen;
413 ret = STATUS_BUFFER_OVERFLOW;
415 else
417 out->Length = info->NameLength;
418 memcpy(out->Buffer, info->Name, info->NameLength);
422 RtlFreeHeap( GetProcessHeap(), 0, info );
423 return ret;
426 /******************************************************************************
427 * NtQueryKey [NTDLL.@]
428 * ZwQueryKey [NTDLL.@]
430 NTSTATUS WINAPI NtQueryKey( HANDLE handle, KEY_INFORMATION_CLASS info_class,
431 void *info, DWORD length, DWORD *result_len )
433 return enumerate_key( handle, -1, info_class, info, length, result_len );
437 /* fill the key value info structure for a specific info class */
438 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info,
439 DWORD length, int type, int name_len, int data_len )
441 switch(info_class)
443 case KeyValueBasicInformation:
445 KEY_VALUE_BASIC_INFORMATION keyinfo;
446 keyinfo.TitleIndex = 0;
447 keyinfo.Type = type;
448 keyinfo.NameLength = name_len;
449 length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
450 memcpy( info, &keyinfo, length );
451 break;
453 case KeyValueFullInformation:
455 KEY_VALUE_FULL_INFORMATION keyinfo;
456 keyinfo.TitleIndex = 0;
457 keyinfo.Type = type;
458 keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len;
459 keyinfo.DataLength = data_len;
460 keyinfo.NameLength = name_len;
461 length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
462 memcpy( info, &keyinfo, length );
463 break;
465 case KeyValuePartialInformation:
467 KEY_VALUE_PARTIAL_INFORMATION keyinfo;
468 keyinfo.TitleIndex = 0;
469 keyinfo.Type = type;
470 keyinfo.DataLength = data_len;
471 length = min( length, (char *)keyinfo.Data - (char *)&keyinfo );
472 memcpy( info, &keyinfo, length );
473 break;
475 default:
476 break;
481 /******************************************************************************
482 * NtEnumerateValueKey [NTDLL.@]
483 * ZwEnumerateValueKey [NTDLL.@]
485 NTSTATUS WINAPI NtEnumerateValueKey( HANDLE handle, ULONG index,
486 KEY_VALUE_INFORMATION_CLASS info_class,
487 void *info, DWORD length, DWORD *result_len )
489 NTSTATUS ret;
490 void *ptr;
491 size_t fixed_size;
493 TRACE( "(%p,%u,%d,%p,%d)\n", handle, index, info_class, info, length );
495 /* compute the length we want to retrieve */
496 switch(info_class)
498 case KeyValueBasicInformation: ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break;
499 case KeyValueFullInformation: ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break;
500 case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break;
501 default:
502 FIXME( "Information class %d not implemented\n", info_class );
503 return STATUS_INVALID_PARAMETER;
505 fixed_size = (char *)ptr - (char *)info;
507 SERVER_START_REQ( enum_key_value )
509 req->hkey = wine_server_obj_handle( handle );
510 req->index = index;
511 req->info_class = info_class;
512 if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size );
513 if (!(ret = wine_server_call( req )))
515 copy_key_value_info( info_class, info, length, reply->type, reply->namelen,
516 wine_server_reply_size(reply) - reply->namelen );
517 *result_len = fixed_size + reply->total;
518 if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
521 SERVER_END_REQ;
522 return ret;
526 /******************************************************************************
527 * NtQueryValueKey [NTDLL.@]
528 * ZwQueryValueKey [NTDLL.@]
530 * NOTES
531 * the name in the KeyValueInformation is never set
533 NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name,
534 KEY_VALUE_INFORMATION_CLASS info_class,
535 void *info, DWORD length, DWORD *result_len )
537 NTSTATUS ret;
538 UCHAR *data_ptr;
539 unsigned int fixed_size = 0, min_size = 0;
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;
661 TRACE("(%p,%p)\n", attr, file);
663 ret = NtCreateFile(&hive, GENERIC_READ, file, &io, NULL, FILE_ATTRIBUTE_NORMAL, 0,
664 FILE_OPEN, 0, NULL, 0);
665 if (ret) return ret;
667 SERVER_START_REQ( load_registry )
669 req->hkey = wine_server_obj_handle( attr->RootDirectory );
670 req->file = wine_server_obj_handle( hive );
671 wine_server_add_data(req, attr->ObjectName->Buffer, attr->ObjectName->Length);
672 ret = wine_server_call( req );
674 SERVER_END_REQ;
676 NtClose(hive);
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;