| /* | |
| * Registry functions | |
| * | |
| * Copyright (C) 1999 Juergen Schmied | |
| * Copyright (C) 2000 Alexandre Julliard | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| * | |
| * NOTES: | |
| * HKEY_LOCAL_MACHINE \\REGISTRY\\MACHINE | |
| * HKEY_USERS \\REGISTRY\\USER | |
| * HKEY_CURRENT_CONFIG \\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT | |
| * HKEY_CLASSES \\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES | |
| */ | |
| #include "config.h" | |
| #include "wine/port.h" | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include "winerror.h" | |
| #include "wine/unicode.h" | |
| #include "wine/library.h" | |
| #include "wine/server.h" | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winreg.h" | |
| #include "winternl.h" | |
| #include "ntdll_misc.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(reg); | |
| /* maximum length of a key/value name in bytes (without terminating null) */ | |
| #define MAX_NAME_LENGTH ((MAX_PATH-1) * sizeof(WCHAR)) | |
| /****************************************************************************** | |
| * NtCreateKey [NTDLL.@] | |
| * ZwCreateKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtCreateKey( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, | |
| ULONG TitleIndex, const UNICODE_STRING *class, ULONG options, | |
| PULONG dispos ) | |
| { | |
| NTSTATUS ret; | |
| TRACE( "(%p,%s,%s,%lx,%lx,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName), | |
| debugstr_us(class), options, access, retkey ); | |
| if (attr->ObjectName->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW; | |
| if (!retkey) return STATUS_INVALID_PARAMETER; | |
| SERVER_START_REQ( create_key ) | |
| { | |
| req->parent = attr->RootDirectory; | |
| req->access = access; | |
| req->options = options; | |
| req->modif = 0; | |
| req->namelen = attr->ObjectName->Length; | |
| wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length ); | |
| if (class) wine_server_add_data( req, class->Buffer, class->Length ); | |
| if (!(ret = wine_server_call( req ))) | |
| { | |
| *retkey = reply->hkey; | |
| if (dispos) *dispos = reply->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY; | |
| } | |
| } | |
| SERVER_END_REQ; | |
| TRACE("<- %p\n", *retkey); | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * RtlpNtCreateKey [NTDLL.@] | |
| * | |
| * See NtCreateKey. | |
| */ | |
| NTSTATUS WINAPI RtlpNtCreateKey( PHKEY retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr, | |
| ULONG TitleIndex, const UNICODE_STRING *class, ULONG options, | |
| PULONG dispos ) | |
| { | |
| if (attr) | |
| attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE); | |
| return NtCreateKey(retkey, access, attr, 0, NULL, 0, dispos); | |
| } | |
| /****************************************************************************** | |
| * NtOpenKey [NTDLL.@] | |
| * ZwOpenKey [NTDLL.@] | |
| * | |
| * OUT PHKEY retkey (returns 0 when failure) | |
| * IN ACCESS_MASK access | |
| * IN POBJECT_ATTRIBUTES attr | |
| */ | |
| NTSTATUS WINAPI NtOpenKey( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) | |
| { | |
| NTSTATUS ret; | |
| DWORD len = attr->ObjectName->Length; | |
| TRACE( "(%p,%s,%lx,%p)\n", attr->RootDirectory, | |
| debugstr_us(attr->ObjectName), access, retkey ); | |
| if (len > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW; | |
| if (!retkey) return STATUS_INVALID_PARAMETER; | |
| SERVER_START_REQ( open_key ) | |
| { | |
| req->parent = attr->RootDirectory; | |
| req->access = access; | |
| wine_server_add_data( req, attr->ObjectName->Buffer, len ); | |
| ret = wine_server_call( req ); | |
| *retkey = reply->hkey; | |
| } | |
| SERVER_END_REQ; | |
| TRACE("<- %p\n", *retkey); | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * RtlpNtOpenKey [NTDLL.@] | |
| * | |
| * See NtOpenKey. | |
| */ | |
| NTSTATUS WINAPI RtlpNtOpenKey( PHKEY retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) | |
| { | |
| if (attr) | |
| attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE); | |
| return NtOpenKey(retkey, access, attr); | |
| } | |
| /****************************************************************************** | |
| * NtDeleteKey [NTDLL.@] | |
| * ZwDeleteKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtDeleteKey( HKEY hkey ) | |
| { | |
| NTSTATUS ret; | |
| TRACE( "(%p)\n", hkey ); | |
| SERVER_START_REQ( delete_key ) | |
| { | |
| req->hkey = hkey; | |
| ret = wine_server_call( req ); | |
| } | |
| SERVER_END_REQ; | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * RtlpNtMakeTemporaryKey [NTDLL.@] | |
| * | |
| * See NtDeleteKey. | |
| */ | |
| NTSTATUS WINAPI RtlpNtMakeTemporaryKey( HKEY hkey ) | |
| { | |
| return NtDeleteKey(hkey); | |
| } | |
| /****************************************************************************** | |
| * NtDeleteValueKey [NTDLL.@] | |
| * ZwDeleteValueKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtDeleteValueKey( HKEY hkey, const UNICODE_STRING *name ) | |
| { | |
| NTSTATUS ret; | |
| TRACE( "(%p,%s)\n", hkey, debugstr_us(name) ); | |
| if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW; | |
| SERVER_START_REQ( delete_key_value ) | |
| { | |
| req->hkey = hkey; | |
| wine_server_add_data( req, name->Buffer, name->Length ); | |
| ret = wine_server_call( req ); | |
| } | |
| SERVER_END_REQ; | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * enumerate_key | |
| * | |
| * Implementation of NtQueryKey and NtEnumerateKey | |
| */ | |
| static NTSTATUS enumerate_key( HKEY handle, int index, KEY_INFORMATION_CLASS info_class, | |
| void *info, DWORD length, DWORD *result_len ) | |
| { | |
| NTSTATUS ret; | |
| void *data_ptr; | |
| size_t fixed_size; | |
| switch(info_class) | |
| { | |
| case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break; | |
| case KeyFullInformation: data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break; | |
| case KeyNodeInformation: data_ptr = ((KEY_NODE_INFORMATION *)info)->Name; break; | |
| default: | |
| FIXME( "Information class %d not implemented\n", info_class ); | |
| return STATUS_INVALID_PARAMETER; | |
| } | |
| fixed_size = (char *)data_ptr - (char *)info; | |
| SERVER_START_REQ( enum_key ) | |
| { | |
| req->hkey = handle; | |
| req->index = index; | |
| req->info_class = info_class; | |
| if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size ); | |
| if (!(ret = wine_server_call( req ))) | |
| { | |
| LARGE_INTEGER modif; | |
| RtlSecondsSince1970ToTime( reply->modif, &modif ); | |
| switch(info_class) | |
| { | |
| case KeyBasicInformation: | |
| { | |
| KEY_BASIC_INFORMATION keyinfo; | |
| fixed_size = (char *)keyinfo.Name - (char *)&keyinfo; | |
| keyinfo.LastWriteTime = modif; | |
| keyinfo.TitleIndex = 0; | |
| keyinfo.NameLength = reply->namelen; | |
| memcpy( info, &keyinfo, min( length, fixed_size ) ); | |
| } | |
| break; | |
| case KeyFullInformation: | |
| { | |
| KEY_FULL_INFORMATION keyinfo; | |
| fixed_size = (char *)keyinfo.Class - (char *)&keyinfo; | |
| keyinfo.LastWriteTime = modif; | |
| keyinfo.TitleIndex = 0; | |
| keyinfo.ClassLength = wine_server_reply_size(reply); | |
| keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1; | |
| keyinfo.SubKeys = reply->subkeys; | |
| keyinfo.MaxNameLen = reply->max_subkey; | |
| keyinfo.MaxClassLen = reply->max_class; | |
| keyinfo.Values = reply->values; | |
| keyinfo.MaxValueNameLen = reply->max_value; | |
| keyinfo.MaxValueDataLen = reply->max_data; | |
| memcpy( info, &keyinfo, min( length, fixed_size ) ); | |
| } | |
| break; | |
| case KeyNodeInformation: | |
| { | |
| KEY_NODE_INFORMATION keyinfo; | |
| fixed_size = (char *)keyinfo.Name - (char *)&keyinfo; | |
| keyinfo.LastWriteTime = modif; | |
| keyinfo.TitleIndex = 0; | |
| keyinfo.ClassLength = max( 0, wine_server_reply_size(reply) - reply->namelen ); | |
| keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size + reply->namelen : -1; | |
| keyinfo.NameLength = reply->namelen; | |
| memcpy( info, &keyinfo, min( length, fixed_size ) ); | |
| } | |
| break; | |
| } | |
| *result_len = fixed_size + reply->total; | |
| if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW; | |
| } | |
| } | |
| SERVER_END_REQ; | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * NtEnumerateKey [NTDLL.@] | |
| * ZwEnumerateKey [NTDLL.@] | |
| * | |
| * NOTES | |
| * the name copied into the buffer is NOT 0-terminated | |
| */ | |
| NTSTATUS WINAPI NtEnumerateKey( HKEY handle, ULONG index, KEY_INFORMATION_CLASS info_class, | |
| void *info, DWORD length, DWORD *result_len ) | |
| { | |
| /* -1 means query key, so avoid it here */ | |
| if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES; | |
| return enumerate_key( handle, index, info_class, info, length, result_len ); | |
| } | |
| /****************************************************************************** | |
| * RtlpNtEnumerateSubKey [NTDLL.@] | |
| * | |
| */ | |
| NTSTATUS WINAPI RtlpNtEnumerateSubKey( HKEY handle, UNICODE_STRING *out, ULONG index ) | |
| { | |
| KEY_BASIC_INFORMATION *info; | |
| DWORD dwLen, dwResultLen; | |
| NTSTATUS ret; | |
| if (out->Length) | |
| { | |
| dwLen = out->Length + sizeof(KEY_BASIC_INFORMATION); | |
| info = (KEY_BASIC_INFORMATION*)RtlAllocateHeap( GetProcessHeap(), 0, dwLen ); | |
| if (!info) | |
| return STATUS_NO_MEMORY; | |
| } | |
| else | |
| { | |
| dwLen = 0; | |
| info = NULL; | |
| } | |
| ret = NtEnumerateKey( handle, index, KeyBasicInformation, info, dwLen, &dwResultLen ); | |
| dwResultLen -= sizeof(KEY_BASIC_INFORMATION); | |
| if (ret == STATUS_BUFFER_OVERFLOW) | |
| out->Length = dwResultLen; | |
| else if (!ret) | |
| { | |
| if (out->Length < info->NameLength) | |
| { | |
| out->Length = dwResultLen; | |
| ret = STATUS_BUFFER_OVERFLOW; | |
| } | |
| else | |
| { | |
| out->Length = info->NameLength; | |
| memcpy(out->Buffer, info->Name, info->NameLength); | |
| } | |
| } | |
| if (info) | |
| RtlFreeHeap( GetProcessHeap(), 0, info ); | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * NtQueryKey [NTDLL.@] | |
| * ZwQueryKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtQueryKey( HKEY handle, KEY_INFORMATION_CLASS info_class, | |
| void *info, DWORD length, DWORD *result_len ) | |
| { | |
| return enumerate_key( handle, -1, info_class, info, length, result_len ); | |
| } | |
| /* fill the key value info structure for a specific info class */ | |
| static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info, | |
| DWORD length, int type, int name_len, int data_len ) | |
| { | |
| switch(info_class) | |
| { | |
| case KeyValueBasicInformation: | |
| { | |
| KEY_VALUE_BASIC_INFORMATION keyinfo; | |
| keyinfo.TitleIndex = 0; | |
| keyinfo.Type = type; | |
| keyinfo.NameLength = name_len; | |
| length = min( length, (char *)keyinfo.Name - (char *)&keyinfo ); | |
| memcpy( info, &keyinfo, length ); | |
| break; | |
| } | |
| case KeyValueFullInformation: | |
| { | |
| KEY_VALUE_FULL_INFORMATION keyinfo; | |
| keyinfo.TitleIndex = 0; | |
| keyinfo.Type = type; | |
| keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len; | |
| keyinfo.DataLength = data_len; | |
| keyinfo.NameLength = name_len; | |
| length = min( length, (char *)keyinfo.Name - (char *)&keyinfo ); | |
| memcpy( info, &keyinfo, length ); | |
| break; | |
| } | |
| case KeyValuePartialInformation: | |
| { | |
| KEY_VALUE_PARTIAL_INFORMATION keyinfo; | |
| keyinfo.TitleIndex = 0; | |
| keyinfo.Type = type; | |
| keyinfo.DataLength = data_len; | |
| length = min( length, (char *)keyinfo.Data - (char *)&keyinfo ); | |
| memcpy( info, &keyinfo, length ); | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| /****************************************************************************** | |
| * NtEnumerateValueKey [NTDLL.@] | |
| * ZwEnumerateValueKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtEnumerateValueKey( HKEY handle, ULONG index, | |
| KEY_VALUE_INFORMATION_CLASS info_class, | |
| void *info, DWORD length, DWORD *result_len ) | |
| { | |
| NTSTATUS ret; | |
| void *ptr; | |
| size_t fixed_size; | |
| TRACE( "(%p,%lu,%d,%p,%ld)\n", handle, index, info_class, info, length ); | |
| /* compute the length we want to retrieve */ | |
| switch(info_class) | |
| { | |
| case KeyValueBasicInformation: ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break; | |
| case KeyValueFullInformation: ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break; | |
| case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break; | |
| default: | |
| FIXME( "Information class %d not implemented\n", info_class ); | |
| return STATUS_INVALID_PARAMETER; | |
| } | |
| fixed_size = (char *)ptr - (char *)info; | |
| SERVER_START_REQ( enum_key_value ) | |
| { | |
| req->hkey = handle; | |
| req->index = index; | |
| req->info_class = info_class; | |
| if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size ); | |
| if (!(ret = wine_server_call( req ))) | |
| { | |
| copy_key_value_info( info_class, info, length, reply->type, reply->namelen, | |
| wine_server_reply_size(reply) - reply->namelen ); | |
| *result_len = fixed_size + reply->total; | |
| if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW; | |
| } | |
| } | |
| SERVER_END_REQ; | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * NtQueryValueKey [NTDLL.@] | |
| * ZwQueryValueKey [NTDLL.@] | |
| * | |
| * NOTES | |
| * the name in the KeyValueInformation is never set | |
| */ | |
| NTSTATUS WINAPI NtQueryValueKey( HKEY handle, const UNICODE_STRING *name, | |
| KEY_VALUE_INFORMATION_CLASS info_class, | |
| void *info, DWORD length, DWORD *result_len ) | |
| { | |
| NTSTATUS ret; | |
| UCHAR *data_ptr; | |
| unsigned int fixed_size = 0; | |
| TRACE( "(%p,%s,%d,%p,%ld)\n", handle, debugstr_us(name), info_class, info, length ); | |
| if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW; | |
| /* compute the length we want to retrieve */ | |
| switch(info_class) | |
| { | |
| case KeyValueBasicInformation: | |
| fixed_size = (char *)((KEY_VALUE_BASIC_INFORMATION *)info)->Name - (char *)info; | |
| data_ptr = NULL; | |
| break; | |
| case KeyValueFullInformation: | |
| data_ptr = (UCHAR *)((KEY_VALUE_FULL_INFORMATION *)info)->Name; | |
| fixed_size = (char *)data_ptr - (char *)info; | |
| break; | |
| case KeyValuePartialInformation: | |
| data_ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; | |
| fixed_size = (char *)data_ptr - (char *)info; | |
| break; | |
| default: | |
| FIXME( "Information class %d not implemented\n", info_class ); | |
| return STATUS_INVALID_PARAMETER; | |
| } | |
| SERVER_START_REQ( get_key_value ) | |
| { | |
| req->hkey = handle; | |
| wine_server_add_data( req, name->Buffer, name->Length ); | |
| if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size ); | |
| if (!(ret = wine_server_call( req ))) | |
| { | |
| copy_key_value_info( info_class, info, length, reply->type, | |
| 0, wine_server_reply_size(reply) ); | |
| *result_len = fixed_size + reply->total; | |
| if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW; | |
| } | |
| } | |
| SERVER_END_REQ; | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * RtlpNtQueryValueKey [NTDLL.@] | |
| * | |
| */ | |
| NTSTATUS WINAPI RtlpNtQueryValueKey( HKEY handle, ULONG *result_type, PBYTE dest, | |
| DWORD *result_len ) | |
| { | |
| KEY_VALUE_PARTIAL_INFORMATION *info; | |
| UNICODE_STRING name; | |
| NTSTATUS ret; | |
| DWORD dwResultLen; | |
| DWORD dwLen = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + result_len ? *result_len : 0; | |
| info = (KEY_VALUE_PARTIAL_INFORMATION*)RtlAllocateHeap( GetProcessHeap(), 0, dwLen ); | |
| if (!info) | |
| return STATUS_NO_MEMORY; | |
| name.Length = 0; | |
| ret = NtQueryValueKey( handle, &name, KeyValuePartialInformation, info, dwLen, &dwResultLen ); | |
| if (!ret || ret == STATUS_BUFFER_OVERFLOW) | |
| { | |
| if (result_len) | |
| *result_len = info->DataLength; | |
| if (result_type) | |
| *result_type = info->Type; | |
| if (ret != STATUS_BUFFER_OVERFLOW) | |
| memcpy( dest, info->Data, info->DataLength ); | |
| } | |
| RtlFreeHeap( GetProcessHeap(), 0, info ); | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * NtFlushKey [NTDLL.@] | |
| * ZwFlushKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtFlushKey(HKEY key) | |
| { | |
| NTSTATUS ret; | |
| TRACE("key=%p\n", key); | |
| SERVER_START_REQ( flush_key ) | |
| { | |
| req->hkey = key; | |
| ret = wine_server_call( req ); | |
| } | |
| SERVER_END_REQ; | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * NtLoadKey [NTDLL.@] | |
| * ZwLoadKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, const OBJECT_ATTRIBUTES *file ) | |
| { | |
| FIXME("stub!\n"); | |
| dump_ObjectAttributes(attr); | |
| dump_ObjectAttributes(file); | |
| return STATUS_SUCCESS; | |
| } | |
| /****************************************************************************** | |
| * NtNotifyChangeKey [NTDLL.@] | |
| * ZwNotifyChangeKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtNotifyChangeKey( | |
| IN HKEY KeyHandle, | |
| IN HANDLE Event, | |
| IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, | |
| IN PVOID ApcContext OPTIONAL, | |
| OUT PIO_STATUS_BLOCK IoStatusBlock, | |
| IN ULONG CompletionFilter, | |
| IN BOOLEAN Asynchroneous, | |
| OUT PVOID ChangeBuffer, | |
| IN ULONG Length, | |
| IN BOOLEAN WatchSubtree) | |
| { | |
| FIXME("(%p,%p,%p,%p,%p,0x%08lx, 0x%08x,%p,0x%08lx,0x%08x) stub!\n", | |
| KeyHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter, | |
| Asynchroneous, ChangeBuffer, Length, WatchSubtree); | |
| return STATUS_SUCCESS; | |
| } | |
| /****************************************************************************** | |
| * NtQueryMultipleValueKey [NTDLL] | |
| * ZwQueryMultipleValueKey | |
| */ | |
| NTSTATUS WINAPI NtQueryMultipleValueKey( | |
| HKEY KeyHandle, | |
| PVALENTW ListOfValuesToQuery, | |
| ULONG NumberOfItems, | |
| PVOID MultipleValueInformation, | |
| ULONG Length, | |
| PULONG ReturnLength) | |
| { | |
| FIXME("(%p,%p,0x%08lx,%p,0x%08lx,%p) stub!\n", | |
| KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation, | |
| Length,ReturnLength); | |
| return STATUS_SUCCESS; | |
| } | |
| /****************************************************************************** | |
| * NtReplaceKey [NTDLL.@] | |
| * ZwReplaceKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtReplaceKey( | |
| IN POBJECT_ATTRIBUTES ObjectAttributes, | |
| IN HKEY Key, | |
| IN POBJECT_ATTRIBUTES ReplacedObjectAttributes) | |
| { | |
| FIXME("(%p),stub!\n", Key); | |
| dump_ObjectAttributes(ObjectAttributes); | |
| dump_ObjectAttributes(ReplacedObjectAttributes); | |
| return STATUS_SUCCESS; | |
| } | |
| /****************************************************************************** | |
| * NtRestoreKey [NTDLL.@] | |
| * ZwRestoreKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtRestoreKey( | |
| HKEY KeyHandle, | |
| HANDLE FileHandle, | |
| ULONG RestoreFlags) | |
| { | |
| FIXME("(%p,%p,0x%08lx) stub\n", | |
| KeyHandle, FileHandle, RestoreFlags); | |
| return STATUS_SUCCESS; | |
| } | |
| /****************************************************************************** | |
| * NtSaveKey [NTDLL.@] | |
| * ZwSaveKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtSaveKey( | |
| IN HKEY KeyHandle, | |
| IN HANDLE FileHandle) | |
| { | |
| FIXME("(%p,%p) stub\n", | |
| KeyHandle, FileHandle); | |
| return STATUS_SUCCESS; | |
| } | |
| /****************************************************************************** | |
| * NtSetInformationKey [NTDLL.@] | |
| * ZwSetInformationKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtSetInformationKey( | |
| IN HKEY KeyHandle, | |
| IN const int KeyInformationClass, | |
| IN PVOID KeyInformation, | |
| IN ULONG KeyInformationLength) | |
| { | |
| FIXME("(%p,0x%08x,%p,0x%08lx) stub\n", | |
| KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength); | |
| return STATUS_SUCCESS; | |
| } | |
| /****************************************************************************** | |
| * NtSetValueKey [NTDLL.@] | |
| * ZwSetValueKey [NTDLL.@] | |
| * | |
| * NOTES | |
| * win95 does not care about count for REG_SZ and finds out the len by itself (js) | |
| * NT does definitely care (aj) | |
| */ | |
| NTSTATUS WINAPI NtSetValueKey( HKEY hkey, const UNICODE_STRING *name, ULONG TitleIndex, | |
| ULONG type, const void *data, ULONG count ) | |
| { | |
| NTSTATUS ret; | |
| TRACE( "(%p,%s,%ld,%p,%ld)\n", hkey, debugstr_us(name), type, data, count ); | |
| if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW; | |
| SERVER_START_REQ( set_key_value ) | |
| { | |
| req->hkey = hkey; | |
| req->type = type; | |
| req->namelen = name->Length; | |
| wine_server_add_data( req, name->Buffer, name->Length ); | |
| wine_server_add_data( req, data, count ); | |
| ret = wine_server_call( req ); | |
| } | |
| SERVER_END_REQ; | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * RtlpNtSetValueKey [NTDLL.@] | |
| * | |
| */ | |
| NTSTATUS WINAPI RtlpNtSetValueKey( HKEY hkey, ULONG type, const void *data, | |
| ULONG count ) | |
| { | |
| UNICODE_STRING name; | |
| name.Length = 0; | |
| return NtSetValueKey( hkey, &name, 0, type, data, count ); | |
| } | |
| /****************************************************************************** | |
| * NtUnloadKey [NTDLL.@] | |
| * ZwUnloadKey [NTDLL.@] | |
| */ | |
| NTSTATUS WINAPI NtUnloadKey( | |
| IN HKEY KeyHandle) | |
| { | |
| FIXME("(%p) stub\n", | |
| KeyHandle); | |
| return STATUS_SUCCESS; | |
| } | |
| /****************************************************************************** | |
| * RtlFormatCurrentUserKeyPath [NTDLL.@] | |
| * | |
| * NOTE: under NT the user name part of the path is an SID. | |
| */ | |
| NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath) | |
| { | |
| static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'}; | |
| const char *user = wine_get_user_name(); | |
| int len = ntdll_umbstowcs( 0, user, strlen(user)+1, NULL, 0 ); | |
| KeyPath->MaximumLength = sizeof(pathW) + len * sizeof(WCHAR); | |
| KeyPath->Length = KeyPath->MaximumLength - sizeof(WCHAR); | |
| if (!(KeyPath->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, KeyPath->MaximumLength ))) | |
| return STATUS_NO_MEMORY; | |
| memcpy( KeyPath->Buffer, pathW, sizeof(pathW) ); | |
| ntdll_umbstowcs( 0, user, strlen(user)+1, KeyPath->Buffer + sizeof(pathW)/sizeof(WCHAR), len ); | |
| return STATUS_SUCCESS; | |
| } | |
| /****************************************************************************** | |
| * RtlOpenCurrentUser [NTDLL.@] | |
| * | |
| * if we return just HKEY_CURRENT_USER the advapi tries to find a remote | |
| * registry (odd handle) and fails | |
| * | |
| */ | |
| DWORD WINAPI RtlOpenCurrentUser( | |
| IN ACCESS_MASK DesiredAccess, /* [in] */ | |
| OUT PHKEY KeyHandle) /* [out] handle of HKEY_CURRENT_USER */ | |
| { | |
| OBJECT_ATTRIBUTES ObjectAttributes; | |
| UNICODE_STRING ObjectName; | |
| NTSTATUS ret; | |
| TRACE("(0x%08lx, %p) stub\n",DesiredAccess, KeyHandle); | |
| RtlFormatCurrentUserKeyPath(&ObjectName); | |
| InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL); | |
| ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL); | |
| RtlFreeUnicodeString(&ObjectName); | |
| return ret; | |
| } |