760 lines
24 KiB
C
760 lines
24 KiB
C
/*
|
|
* Registry functions
|
|
*
|
|
* Copyright (C) 1999 Juergen Schmied
|
|
* Copyright (C) 2000 Alexandre Julliard
|
|
*
|
|
* 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 "debugtools.h"
|
|
#include "winreg.h"
|
|
#include "winerror.h"
|
|
#include "wine/unicode.h"
|
|
#include "server.h"
|
|
#include "ntddk.h"
|
|
#include "ntdll_misc.h"
|
|
|
|
DEFAULT_DEBUG_CHANNEL(reg);
|
|
|
|
static const WCHAR root_name[] = { '\\','R','e','g','i','s','t','r','y','\\',0 };
|
|
static const UNICODE_STRING root_path =
|
|
{
|
|
sizeof(root_name)-sizeof(WCHAR), /* Length */
|
|
sizeof(root_name), /* MaximumLength */
|
|
(LPWSTR)root_name /* Buffer */
|
|
};
|
|
|
|
/* maximum length of a key/value name in bytes (without terminating null) */
|
|
#define MAX_NAME_LENGTH ((MAX_PATH-1) * sizeof(WCHAR))
|
|
|
|
|
|
/* copy a key name into the request buffer */
|
|
static inline NTSTATUS copy_nameU( LPWSTR Dest, const UNICODE_STRING *name, UINT max )
|
|
{
|
|
if (name->Length >= max) return STATUS_BUFFER_OVERFLOW;
|
|
if (name->Length) memcpy( Dest, name->Buffer, name->Length );
|
|
Dest[name->Length / sizeof(WCHAR)] = 0;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* NtCreateKey [NTDLL]
|
|
* ZwCreateKey
|
|
*/
|
|
NTSTATUS WINAPI NtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
|
|
ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
|
|
PULONG dispos )
|
|
{
|
|
NTSTATUS ret;
|
|
DWORD len = attr->ObjectName->Length;
|
|
|
|
TRACE( "(0x%x,%s,%s,%lx,%lx,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
|
|
debugstr_us(class), options, access, retkey );
|
|
|
|
if (len > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
|
|
len += sizeof(WCHAR); /* for storing name length */
|
|
if (class)
|
|
{
|
|
len += class->Length;
|
|
if (len > REQUEST_MAX_VAR_SIZE) return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
if (!retkey) return STATUS_INVALID_PARAMETER;
|
|
|
|
SERVER_START_REQ
|
|
{
|
|
struct create_key_request *req = server_alloc_req( sizeof(*req), len );
|
|
WCHAR *data = server_data_ptr(req);
|
|
|
|
req->parent = attr->RootDirectory;
|
|
req->access = access;
|
|
req->options = options;
|
|
req->modif = 0;
|
|
|
|
*data++ = attr->ObjectName->Length;
|
|
memcpy( data, attr->ObjectName->Buffer, attr->ObjectName->Length );
|
|
if (class) memcpy( (char *)data + attr->ObjectName->Length, class->Buffer, class->Length );
|
|
if (!(ret = server_call_noerr( REQ_CREATE_KEY )))
|
|
{
|
|
*retkey = req->hkey;
|
|
if (dispos) *dispos = req->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
|
|
}
|
|
}
|
|
SERVER_END_REQ;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* NtOpenKey [NTDLL.129]
|
|
* ZwOpenKey
|
|
* OUT PHANDLE retkey (returns 0 when failure)
|
|
* IN ACCESS_MASK access
|
|
* IN POBJECT_ATTRIBUTES attr
|
|
*/
|
|
NTSTATUS WINAPI NtOpenKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
|
|
{
|
|
NTSTATUS ret;
|
|
DWORD len = attr->ObjectName->Length;
|
|
|
|
TRACE( "(0x%x,%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;
|
|
*retkey = 0;
|
|
|
|
SERVER_START_REQ
|
|
{
|
|
struct open_key_request *req = server_alloc_req( sizeof(*req), len );
|
|
req->parent = attr->RootDirectory;
|
|
req->access = access;
|
|
memcpy( server_data_ptr(req), attr->ObjectName->Buffer, len );
|
|
if (!(ret = server_call_noerr( REQ_OPEN_KEY ))) *retkey = req->hkey;
|
|
}
|
|
SERVER_END_REQ;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* NtDeleteKey [NTDLL]
|
|
* ZwDeleteKey
|
|
*/
|
|
NTSTATUS WINAPI NtDeleteKey( HANDLE hkey )
|
|
{
|
|
NTSTATUS ret;
|
|
|
|
TRACE( "(%x)\n", hkey );
|
|
|
|
SERVER_START_REQ
|
|
{
|
|
struct delete_key_request *req = server_alloc_req( sizeof(*req), 0 );
|
|
req->hkey = hkey;
|
|
ret = server_call_noerr( REQ_DELETE_KEY );
|
|
}
|
|
SERVER_END_REQ;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* NtDeleteValueKey [NTDLL]
|
|
* ZwDeleteValueKey
|
|
*/
|
|
NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name )
|
|
{
|
|
NTSTATUS ret;
|
|
|
|
TRACE( "(0x%x,%s)\n", hkey, debugstr_us(name) );
|
|
if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
|
|
|
|
SERVER_START_REQ
|
|
{
|
|
struct delete_key_value_request *req = server_alloc_req( sizeof(*req), name->Length );
|
|
|
|
req->hkey = hkey;
|
|
memcpy( server_data_ptr(req), name->Buffer, name->Length );
|
|
ret = server_call_noerr( REQ_DELETE_KEY_VALUE );
|
|
}
|
|
SERVER_END_REQ;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* fill_key_info
|
|
*
|
|
* Helper function for NtQueryKey and NtEnumerateKey
|
|
*/
|
|
static NTSTATUS fill_key_info( KEY_INFORMATION_CLASS info_class, void *info, DWORD length,
|
|
DWORD *result_len, const struct enum_key_request *req )
|
|
{
|
|
WCHAR *name_ptr = server_data_ptr(req);
|
|
int name_size = *name_ptr++;
|
|
WCHAR *class_ptr = (WCHAR *)((char *)name_ptr + name_size);
|
|
int class_size = server_data_size(req) - sizeof(WCHAR) - name_size;
|
|
int fixed_size;
|
|
FILETIME modif;
|
|
|
|
RtlSecondsSince1970ToTime( req->modif, &modif );
|
|
|
|
switch(info_class)
|
|
{
|
|
case KeyBasicInformation:
|
|
{
|
|
KEY_BASIC_INFORMATION keyinfo;
|
|
fixed_size = sizeof(keyinfo) - sizeof(keyinfo.Name);
|
|
keyinfo.LastWriteTime = modif;
|
|
keyinfo.TitleIndex = 0;
|
|
keyinfo.NameLength = name_size;
|
|
memcpy( info, &keyinfo, min( length, fixed_size ) );
|
|
class_size = 0;
|
|
}
|
|
break;
|
|
case KeyFullInformation:
|
|
{
|
|
KEY_FULL_INFORMATION keyinfo;
|
|
fixed_size = sizeof(keyinfo) - sizeof(keyinfo.Class);
|
|
keyinfo.LastWriteTime = modif;
|
|
keyinfo.TitleIndex = 0;
|
|
keyinfo.ClassLength = class_size;
|
|
keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
|
|
keyinfo.SubKeys = req->subkeys;
|
|
keyinfo.MaxNameLen = req->max_subkey;
|
|
keyinfo.MaxClassLen = req->max_class;
|
|
keyinfo.Values = req->values;
|
|
keyinfo.MaxValueNameLen = req->max_value;
|
|
keyinfo.MaxValueDataLen = req->max_data;
|
|
memcpy( info, &keyinfo, min( length, fixed_size ) );
|
|
name_size = 0;
|
|
}
|
|
break;
|
|
case KeyNodeInformation:
|
|
{
|
|
KEY_NODE_INFORMATION keyinfo;
|
|
fixed_size = sizeof(keyinfo) - sizeof(keyinfo.Name);
|
|
keyinfo.LastWriteTime = modif;
|
|
keyinfo.TitleIndex = 0;
|
|
keyinfo.ClassLength = class_size;
|
|
keyinfo.ClassOffset = fixed_size + name_size;
|
|
if (!keyinfo.ClassLength || keyinfo.ClassOffset > length) keyinfo.ClassOffset = -1;
|
|
keyinfo.NameLength = name_size;
|
|
memcpy( info, &keyinfo, min( length, fixed_size ) );
|
|
}
|
|
break;
|
|
default:
|
|
FIXME("Information class not implemented\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
*result_len = fixed_size + name_size + class_size;
|
|
if (length <= fixed_size) return STATUS_BUFFER_OVERFLOW;
|
|
length -= fixed_size;
|
|
|
|
/* copy the name */
|
|
if (name_size)
|
|
{
|
|
memcpy( (char *)info + fixed_size, name_ptr, min(length,name_size) );
|
|
if (length < name_size) return STATUS_BUFFER_OVERFLOW;
|
|
length -= name_size;
|
|
}
|
|
|
|
/* copy the class */
|
|
if (class_size)
|
|
{
|
|
memcpy( (char *)info + fixed_size + name_size, class_ptr, min(length,class_size) );
|
|
if (length < class_size) return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
* NtEnumerateKey [NTDLL]
|
|
* ZwEnumerateKey
|
|
*
|
|
* NOTES
|
|
* the name copied into the buffer is NOT 0-terminated
|
|
*/
|
|
NTSTATUS WINAPI NtEnumerateKey( HANDLE handle, ULONG index, KEY_INFORMATION_CLASS info_class,
|
|
void *info, DWORD length, DWORD *result_len )
|
|
{
|
|
NTSTATUS ret;
|
|
|
|
/* -1 means query key, so avoid it here */
|
|
if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
|
|
|
|
SERVER_START_REQ
|
|
{
|
|
struct enum_key_request *req = server_alloc_req( sizeof(*req), REQUEST_MAX_VAR_SIZE );
|
|
req->hkey = handle;
|
|
req->index = index;
|
|
req->full = (info_class == KeyFullInformation);
|
|
if (!(ret = server_call_noerr( REQ_ENUM_KEY )))
|
|
{
|
|
ret = fill_key_info( info_class, info, length, result_len, req );
|
|
}
|
|
}
|
|
SERVER_END_REQ;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* NtQueryKey [NTDLL]
|
|
* ZwQueryKey
|
|
*/
|
|
NTSTATUS WINAPI NtQueryKey( HANDLE handle, KEY_INFORMATION_CLASS info_class,
|
|
void *info, DWORD length, DWORD *result_len )
|
|
{
|
|
NTSTATUS ret;
|
|
|
|
SERVER_START_REQ
|
|
{
|
|
struct enum_key_request *req = server_alloc_req( sizeof(*req), REQUEST_MAX_VAR_SIZE );
|
|
req->hkey = handle;
|
|
req->index = -1;
|
|
req->full = (info_class == KeyFullInformation);
|
|
if (!(ret = server_call_noerr( REQ_ENUM_KEY )))
|
|
{
|
|
ret = fill_key_info( info_class, info, length, result_len, req );
|
|
}
|
|
}
|
|
SERVER_END_REQ;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* 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, sizeof(keyinfo) - sizeof(keyinfo.Name) );
|
|
memcpy( info, &keyinfo, length );
|
|
break;
|
|
}
|
|
case KeyValueFullInformation:
|
|
{
|
|
KEY_VALUE_FULL_INFORMATION keyinfo;
|
|
keyinfo.TitleIndex = 0;
|
|
keyinfo.Type = type;
|
|
keyinfo.DataOffset = sizeof(keyinfo) - sizeof(keyinfo.Name) + name_len;
|
|
keyinfo.DataLength = data_len;
|
|
keyinfo.NameLength = name_len;
|
|
length = min( length, sizeof(keyinfo) - sizeof(keyinfo.Name) );
|
|
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, sizeof(keyinfo) - sizeof(keyinfo.Data) );
|
|
memcpy( info, &keyinfo, length );
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* NtEnumerateValueKey [NTDLL]
|
|
* ZwEnumerateValueKey
|
|
*/
|
|
NTSTATUS WINAPI NtEnumerateValueKey( HANDLE handle, ULONG index,
|
|
KEY_VALUE_INFORMATION_CLASS info_class,
|
|
void *info, DWORD length, DWORD *result_len )
|
|
{
|
|
NTSTATUS ret;
|
|
char *data_ptr, *name_ptr;
|
|
int fixed_size = 0, name_len = 0, data_len = 0, offset = 0, type = 0, total_len = 0;
|
|
|
|
TRACE( "(0x%x,%lu,%d,%p,%ld)\n", handle, index, info_class, info, length );
|
|
|
|
/* compute the length we want to retrieve */
|
|
switch(info_class)
|
|
{
|
|
case KeyValueBasicInformation:
|
|
fixed_size = sizeof(KEY_VALUE_BASIC_INFORMATION) - sizeof(WCHAR);
|
|
name_ptr = (char *)info + fixed_size;
|
|
data_ptr = NULL;
|
|
break;
|
|
case KeyValueFullInformation:
|
|
fixed_size = sizeof(KEY_VALUE_FULL_INFORMATION) - sizeof(WCHAR);
|
|
name_ptr = data_ptr = (char *)info + fixed_size;
|
|
break;
|
|
case KeyValuePartialInformation:
|
|
fixed_size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) - sizeof(UCHAR);
|
|
name_ptr = NULL;
|
|
data_ptr = (char *)info + fixed_size;
|
|
break;
|
|
default:
|
|
FIXME( "Information class %d not implemented\n", info_class );
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (length > fixed_size) data_len = length - fixed_size;
|
|
|
|
do
|
|
{
|
|
size_t reqlen = data_len + sizeof(WCHAR);
|
|
if (name_ptr && !offset) reqlen += MAX_PATH*sizeof(WCHAR);
|
|
reqlen = min( reqlen, REQUEST_MAX_VAR_SIZE );
|
|
|
|
SERVER_START_REQ
|
|
{
|
|
struct enum_key_value_request *req = server_alloc_req( sizeof(*req), reqlen );
|
|
|
|
req->hkey = handle;
|
|
req->index = index;
|
|
req->offset = offset;
|
|
|
|
if (!(ret = server_call_noerr( REQ_ENUM_KEY_VALUE )))
|
|
{
|
|
size_t size = server_data_size(req) - sizeof(WCHAR);
|
|
WCHAR *name = server_data_ptr(req);
|
|
if (!offset) /* name is only present on the first request */
|
|
{
|
|
name_len = *name++;
|
|
size -= name_len;
|
|
if (name_ptr)
|
|
{
|
|
if (name_len > data_len) /* overflow */
|
|
{
|
|
memcpy( name_ptr, name, data_len );
|
|
data_len = 0;
|
|
ret = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
memcpy( name_ptr, name, name_len );
|
|
data_len -= name_len;
|
|
if (data_ptr) data_ptr += name_len;
|
|
}
|
|
}
|
|
name += name_len / sizeof(WCHAR);
|
|
}
|
|
else name++; /* skip 0 length */
|
|
|
|
if (data_ptr)
|
|
{
|
|
size = min( size, data_len );
|
|
memcpy( data_ptr + offset, name, size );
|
|
offset += size;
|
|
data_len -= size;
|
|
}
|
|
type = req->type;
|
|
total_len = req->len;
|
|
}
|
|
}
|
|
SERVER_END_REQ;
|
|
if (ret) return ret;
|
|
} while (data_len && data_ptr && offset < total_len);
|
|
|
|
*result_len = total_len + fixed_size + (name_ptr ? name_len : 0);
|
|
|
|
if (data_ptr && offset < total_len) ret = STATUS_BUFFER_OVERFLOW;
|
|
if (length < fixed_size) ret = STATUS_BUFFER_OVERFLOW;
|
|
|
|
copy_key_value_info( info_class, info, length, type, name_len, total_len );
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* NtQueryValueKey [NTDLL]
|
|
* ZwQueryValueKey
|
|
*
|
|
* NOTES
|
|
* the name in the KeyValueInformation is never set
|
|
*/
|
|
NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name,
|
|
KEY_VALUE_INFORMATION_CLASS info_class,
|
|
void *info, DWORD length, DWORD *result_len )
|
|
{
|
|
NTSTATUS ret;
|
|
char *data_ptr;
|
|
int fixed_size = 0, data_len = 0, offset = 0, type = 0, total_len = 0;
|
|
|
|
TRACE( "(0x%x,%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 = sizeof(KEY_VALUE_BASIC_INFORMATION) - sizeof(WCHAR);
|
|
data_ptr = NULL;
|
|
break;
|
|
case KeyValueFullInformation:
|
|
fixed_size = sizeof(KEY_VALUE_FULL_INFORMATION) - sizeof(WCHAR);
|
|
data_ptr = (char *)info + fixed_size;
|
|
break;
|
|
case KeyValuePartialInformation:
|
|
fixed_size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) - sizeof(UCHAR);
|
|
data_ptr = (char *)info + fixed_size;
|
|
break;
|
|
default:
|
|
FIXME( "Information class %d not implemented\n", info_class );
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (data_ptr && length > fixed_size) data_len = length - fixed_size;
|
|
|
|
do
|
|
{
|
|
size_t reqlen = min( data_len, REQUEST_MAX_VAR_SIZE );
|
|
reqlen = max( reqlen, name->Length + sizeof(WCHAR) );
|
|
|
|
SERVER_START_REQ
|
|
{
|
|
struct get_key_value_request *req = server_alloc_req( sizeof(*req), reqlen );
|
|
WCHAR *nameptr = server_data_ptr(req);
|
|
|
|
req->hkey = handle;
|
|
req->offset = offset;
|
|
*nameptr++ = name->Length;
|
|
memcpy( nameptr, name->Buffer, name->Length );
|
|
|
|
if (!(ret = server_call_noerr( REQ_GET_KEY_VALUE )))
|
|
{
|
|
size_t size = min( server_data_size(req), data_len );
|
|
type = req->type;
|
|
total_len = req->len;
|
|
if (size)
|
|
{
|
|
memcpy( data_ptr + offset, server_data_ptr(req), size );
|
|
offset += size;
|
|
data_len -= size;
|
|
}
|
|
}
|
|
}
|
|
SERVER_END_REQ;
|
|
if (ret) return ret;
|
|
} while (data_len && offset < total_len);
|
|
|
|
*result_len = total_len + fixed_size;
|
|
|
|
if (offset < total_len) ret = STATUS_BUFFER_OVERFLOW;
|
|
if (length < fixed_size) ret = STATUS_BUFFER_OVERFLOW;
|
|
|
|
copy_key_value_info( info_class, info, length, type, 0, total_len );
|
|
return ret;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* NtFlushKey [NTDLL]
|
|
* ZwFlushKey
|
|
*/
|
|
NTSTATUS WINAPI NtFlushKey(HANDLE KeyHandle)
|
|
{
|
|
FIXME("(0x%08x) stub!\n",
|
|
KeyHandle);
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* NtLoadKey [NTDLL]
|
|
* ZwLoadKey
|
|
*/
|
|
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
|
|
*/
|
|
NTSTATUS WINAPI NtNotifyChangeKey(
|
|
IN HANDLE 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("(0x%08x,0x%08x,%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(
|
|
HANDLE KeyHandle,
|
|
PVALENTW ListOfValuesToQuery,
|
|
ULONG NumberOfItems,
|
|
PVOID MultipleValueInformation,
|
|
ULONG Length,
|
|
PULONG ReturnLength)
|
|
{
|
|
FIXME("(0x%08x,%p,0x%08lx,%p,0x%08lx,%p) stub!\n",
|
|
KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
|
|
Length,ReturnLength);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* NtReplaceKey [NTDLL]
|
|
* ZwReplaceKey
|
|
*/
|
|
NTSTATUS WINAPI NtReplaceKey(
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN HANDLE Key,
|
|
IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
|
|
{
|
|
FIXME("(0x%08x),stub!\n", Key);
|
|
dump_ObjectAttributes(ObjectAttributes);
|
|
dump_ObjectAttributes(ReplacedObjectAttributes);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
/******************************************************************************
|
|
* NtRestoreKey [NTDLL]
|
|
* ZwRestoreKey
|
|
*/
|
|
NTSTATUS WINAPI NtRestoreKey(
|
|
HANDLE KeyHandle,
|
|
HANDLE FileHandle,
|
|
ULONG RestoreFlags)
|
|
{
|
|
FIXME("(0x%08x,0x%08x,0x%08lx) stub\n",
|
|
KeyHandle, FileHandle, RestoreFlags);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
/******************************************************************************
|
|
* NtSaveKey [NTDLL]
|
|
* ZwSaveKey
|
|
*/
|
|
NTSTATUS WINAPI NtSaveKey(
|
|
IN HANDLE KeyHandle,
|
|
IN HANDLE FileHandle)
|
|
{
|
|
FIXME("(0x%08x,0x%08x) stub\n",
|
|
KeyHandle, FileHandle);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
/******************************************************************************
|
|
* NtSetInformationKey [NTDLL]
|
|
* ZwSetInformationKey
|
|
*/
|
|
NTSTATUS WINAPI NtSetInformationKey(
|
|
IN HANDLE KeyHandle,
|
|
IN const int KeyInformationClass,
|
|
IN PVOID KeyInformation,
|
|
IN ULONG KeyInformationLength)
|
|
{
|
|
FIXME("(0x%08x,0x%08x,%p,0x%08lx) stub\n",
|
|
KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* NtSetValueKey [NTDLL]
|
|
* ZwSetValueKey
|
|
*
|
|
* 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( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
|
|
ULONG type, const void *data, ULONG count )
|
|
{
|
|
NTSTATUS ret;
|
|
ULONG namelen, pos;
|
|
|
|
TRACE( "(0x%x,%s,%ld,%p,%ld)\n", hkey, debugstr_us(name), type, data, count );
|
|
|
|
if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
|
|
|
|
namelen = name->Length + sizeof(WCHAR); /* for storing length */
|
|
pos = 0;
|
|
|
|
do
|
|
{
|
|
ULONG len = count - pos;
|
|
if (len > REQUEST_MAX_VAR_SIZE - namelen) len = REQUEST_MAX_VAR_SIZE - namelen;
|
|
|
|
SERVER_START_REQ
|
|
{
|
|
struct set_key_value_request *req = server_alloc_req( sizeof(*req), namelen + len );
|
|
WCHAR *name_ptr = server_data_ptr(req);
|
|
|
|
req->hkey = hkey;
|
|
req->type = type;
|
|
req->total = count;
|
|
req->offset = pos;
|
|
*name_ptr++ = name->Length;
|
|
memcpy( name_ptr, name->Buffer, name->Length );
|
|
memcpy( (char *)name_ptr + name->Length, (char *)data + pos, len );
|
|
pos += len;
|
|
ret = server_call_noerr( REQ_SET_KEY_VALUE );
|
|
}
|
|
SERVER_END_REQ;
|
|
} while (!ret && pos < count);
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* NtUnloadKey [NTDLL]
|
|
* ZwUnloadKey
|
|
*/
|
|
NTSTATUS WINAPI NtUnloadKey(
|
|
IN HANDLE KeyHandle)
|
|
{
|
|
FIXME("(0x%08x) stub\n",
|
|
KeyHandle);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* RtlFormatCurrentUserKeyPath [NTDLL.371]
|
|
*/
|
|
NTSTATUS WINAPI RtlFormatCurrentUserKeyPath(
|
|
IN OUT PUNICODE_STRING KeyPath)
|
|
{
|
|
/* LPSTR Path = "\\REGISTRY\\USER\\S-1-5-21-0000000000-000000000-0000000000-500";*/
|
|
LPSTR Path = "\\REGISTRY\\USER\\.DEFAULT";
|
|
ANSI_STRING AnsiPath;
|
|
|
|
FIXME("(%p) stub\n",KeyPath);
|
|
RtlInitAnsiString(&AnsiPath, Path);
|
|
return RtlAnsiStringToUnicodeString(KeyPath, &AnsiPath, TRUE);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* RtlOpenCurrentUser [NTDLL]
|
|
*
|
|
* if we return just HKEY_CURRENT_USER the advapi try's to find a remote
|
|
* registry (odd handle) and fails
|
|
*
|
|
*/
|
|
DWORD WINAPI RtlOpenCurrentUser(
|
|
IN ACCESS_MASK DesiredAccess, /* [in] */
|
|
OUT PHANDLE 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 = NtOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
|
|
RtlFreeUnicodeString(&ObjectName);
|
|
return ret;
|
|
}
|