wine/dlls/ntdll/reg.c
2022-11-21 18:03:53 +01:00

768 lines
25 KiB
C

/*
* Registry functions
*
* Copyright (C) 1999 Juergen Schmied
* Copyright (C) 2000 Alexandre Julliard
* Copyright 2005 Ivan Leo Puoti, Laurent Pinchart
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "ntdll_misc.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(reg);
/******************************************************************************
* RtlpNtCreateKey [NTDLL.@]
*
* See NtCreateKey.
*/
NTSTATUS WINAPI RtlpNtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
PULONG dispos )
{
OBJECT_ATTRIBUTES oa;
if (attr)
{
oa = *attr;
oa.Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
attr = &oa;
}
return NtCreateKey(retkey, access, attr, 0, NULL, 0, dispos);
}
/******************************************************************************
* RtlpNtOpenKey [NTDLL.@]
*
* See NtOpenKey.
*/
NTSTATUS WINAPI RtlpNtOpenKey( PHANDLE retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
{
if (attr)
attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
return NtOpenKey(retkey, access, attr);
}
/******************************************************************************
* RtlpNtMakeTemporaryKey [NTDLL.@]
*
* See NtDeleteKey.
*/
NTSTATUS WINAPI RtlpNtMakeTemporaryKey( HANDLE hkey )
{
return NtDeleteKey(hkey);
}
/******************************************************************************
* RtlpNtEnumerateSubKey [NTDLL.@]
*
*/
NTSTATUS WINAPI RtlpNtEnumerateSubKey( HANDLE handle, UNICODE_STRING *out, ULONG index )
{
KEY_BASIC_INFORMATION *info;
DWORD dwLen, dwResultLen;
NTSTATUS ret;
if (out->MaximumLength)
{
dwLen = out->MaximumLength + offsetof(KEY_BASIC_INFORMATION, Name);
info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
if (!info)
return STATUS_NO_MEMORY;
}
else
{
dwLen = 0;
info = NULL;
}
ret = NtEnumerateKey( handle, index, KeyBasicInformation, info, dwLen, &dwResultLen );
dwResultLen -= offsetof(KEY_BASIC_INFORMATION, Name);
if (ret == STATUS_BUFFER_OVERFLOW)
out->Length = dwResultLen;
else if (!ret)
{
if (out->MaximumLength < info->NameLength)
{
out->Length = dwResultLen;
ret = STATUS_BUFFER_OVERFLOW;
}
else
{
out->Length = info->NameLength;
memcpy(out->Buffer, info->Name, info->NameLength);
}
}
RtlFreeHeap( GetProcessHeap(), 0, info );
return ret;
}
/******************************************************************************
* RtlpNtQueryValueKey [NTDLL.@]
*
*/
NTSTATUS WINAPI RtlpNtQueryValueKey( HANDLE handle, ULONG *result_type, PBYTE dest,
DWORD *result_len, void *unknown )
{
KEY_VALUE_PARTIAL_INFORMATION *info;
UNICODE_STRING name;
NTSTATUS ret;
DWORD dwResultLen;
DWORD dwLen = offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data[result_len ? *result_len : 0]);
info = 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;
}
/******************************************************************************
* RtlpNtSetValueKey [NTDLL.@]
*
*/
NTSTATUS WINAPI RtlpNtSetValueKey( HANDLE hkey, ULONG type, const void *data,
ULONG count )
{
UNICODE_STRING name;
name.Length = 0;
return NtSetValueKey( hkey, &name, 0, type, data, count );
}
/******************************************************************************
* RtlFormatCurrentUserKeyPath [NTDLL.@]
*
*/
NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
{
static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
char buffer[sizeof(TOKEN_USER) + sizeof(SID) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES];
DWORD len = sizeof(buffer);
NTSTATUS status;
status = NtQueryInformationToken(GetCurrentThreadEffectiveToken(), TokenUser, buffer, len, &len);
if (status == STATUS_SUCCESS)
{
KeyPath->MaximumLength = 0;
status = RtlConvertSidToUnicodeString(KeyPath, ((TOKEN_USER *)buffer)->User.Sid, FALSE);
if (status == STATUS_BUFFER_OVERFLOW)
{
PWCHAR buf = RtlAllocateHeap(GetProcessHeap(), 0,
sizeof(pathW) + KeyPath->Length + sizeof(WCHAR));
if (buf)
{
memcpy(buf, pathW, sizeof(pathW));
KeyPath->MaximumLength = KeyPath->Length + sizeof(WCHAR);
KeyPath->Buffer = (PWCHAR)((LPBYTE)buf + sizeof(pathW));
status = RtlConvertSidToUnicodeString(KeyPath,
((TOKEN_USER *)buffer)->User.Sid, FALSE);
KeyPath->Buffer = buf;
KeyPath->Length += sizeof(pathW);
KeyPath->MaximumLength += sizeof(pathW);
}
else
status = STATUS_NO_MEMORY;
}
}
return status;
}
/******************************************************************************
* RtlOpenCurrentUser [NTDLL.@]
*
* NOTES
* If we return just HKEY_CURRENT_USER the advapi tries to find a remote
* registry (odd handle) and fails.
*/
NTSTATUS 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)\n",DesiredAccess, KeyHandle);
if ((ret = RtlFormatCurrentUserKeyPath(&ObjectName))) return ret;
InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
RtlFreeUnicodeString(&ObjectName);
return ret;
}
static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
{
PUNICODE_STRING str;
UNICODE_STRING src, dst;
LONG *bin;
ULONG offset;
PWSTR wstr;
DWORD res;
NTSTATUS status = STATUS_SUCCESS;
ULONG len;
LPWSTR String;
ULONG count = 0;
if (pInfo == NULL)
{
if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
return STATUS_INVALID_PARAMETER;
else
{
status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
pQuery->DefaultLength, pContext, pQuery->EntryContext);
}
return status;
}
len = pInfo->DataLength;
if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
{
str = pQuery->EntryContext;
switch(pInfo->Type)
{
case REG_EXPAND_SZ:
if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
{
RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
res = 0;
dst.MaximumLength = 0;
RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
dst.Length = 0;
dst.MaximumLength = res;
dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
dst.Length, pContext, pQuery->EntryContext);
RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
}
case REG_SZ:
case REG_LINK:
if (str->Buffer == NULL)
RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
else
RtlAppendUnicodeToString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
break;
case REG_MULTI_SZ:
if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
return STATUS_INVALID_PARAMETER;
if (str->Buffer == NULL)
{
str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
str->MaximumLength = len;
}
len = min(len, str->MaximumLength);
memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
str->Length = len;
break;
default:
bin = pQuery->EntryContext;
if (pInfo->DataLength <= sizeof(ULONG))
memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
pInfo->DataLength);
else
{
if (bin[0] <= sizeof(ULONG))
{
memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
min(-bin[0], pInfo->DataLength));
}
else
{
len = min(bin[0], pInfo->DataLength);
bin[1] = len;
bin[2] = pInfo->Type;
memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
}
}
break;
}
}
else
{
if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
(pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
{
status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type,
((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
pContext, pQuery->EntryContext);
}
else if (pInfo->Type == REG_EXPAND_SZ)
{
RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
res = 0;
dst.MaximumLength = 0;
RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
dst.Length = 0;
dst.MaximumLength = res;
dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
dst.Length, pContext, pQuery->EntryContext);
RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
}
else /* REG_MULTI_SZ */
{
if(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
{
for (offset = 0; offset <= pInfo->DataLength; offset += len + sizeof(WCHAR))
{
wstr = (WCHAR*)(((CHAR*)pInfo) + offset);
len = wcslen(wstr) * sizeof(WCHAR);
status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, wstr, len,
pContext, pQuery->EntryContext);
if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
return status;
}
}
else
{
while(count<=pInfo->DataLength)
{
String = (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset)+count;
count+=wcslen(String)+1;
RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
res = 0;
dst.MaximumLength = 0;
RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
dst.Length = 0;
dst.MaximumLength = res;
dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
dst.Length, pContext, pQuery->EntryContext);
RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
return status;
}
}
}
}
return status;
}
static NTSTATUS RTL_KeyHandleCreateObject(ULONG RelativeTo, PCWSTR Path, POBJECT_ATTRIBUTES regkey, PUNICODE_STRING str)
{
PCWSTR base;
INT len;
switch (RelativeTo & 0xff)
{
case RTL_REGISTRY_ABSOLUTE:
base = L"";
break;
case RTL_REGISTRY_CONTROL:
base = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\";
break;
case RTL_REGISTRY_DEVICEMAP:
base = L"\\Registry\\Machine\\Hardware\\DeviceMap\\";
break;
case RTL_REGISTRY_SERVICES:
base = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
break;
case RTL_REGISTRY_USER:
base = L"\\Registry\\User\\CurrentUser\\";
break;
case RTL_REGISTRY_WINDOWS_NT:
base = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\";
break;
default:
return STATUS_INVALID_PARAMETER;
}
len = (wcslen(base) + wcslen(Path) + 1) * sizeof(WCHAR);
str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
if (str->Buffer == NULL)
return STATUS_NO_MEMORY;
wcscpy(str->Buffer, base);
wcscat(str->Buffer, Path);
str->Length = len - sizeof(WCHAR);
str->MaximumLength = len;
InitializeObjectAttributes(regkey, str, OBJ_CASE_INSENSITIVE, NULL, NULL);
return STATUS_SUCCESS;
}
static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
{
OBJECT_ATTRIBUTES regkey;
UNICODE_STRING string;
NTSTATUS status;
status = RTL_KeyHandleCreateObject(RelativeTo, Path, &regkey, &string);
if(status != STATUS_SUCCESS)
return status;
status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
RtlFreeUnicodeString( &string );
return status;
}
/******************************************************************************
* RtlQueryRegistryValues (NTDLL.@)
* RtlQueryRegistryValuesEx (NTDLL.@)
*/
NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
IN PVOID Environment OPTIONAL)
{
UNICODE_STRING Value;
HANDLE handle, topkey;
PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
ULONG len, buflen = 0;
NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
INT i;
TRACE("(%ld, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
if(Path == NULL)
return STATUS_INVALID_PARAMETER;
/* get a valid handle */
if (RelativeTo & RTL_REGISTRY_HANDLE)
topkey = handle = (HANDLE)Path;
else
{
status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
handle = topkey;
}
if(status != STATUS_SUCCESS)
return status;
/* Process query table entries */
for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
{
if (QueryTable->Flags &
(RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
{
/* topkey must be kept open just in case we will reuse it later */
if (handle != topkey)
NtClose(handle);
if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
{
handle = 0;
status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
if(status != STATUS_SUCCESS)
{
ret = status;
goto out;
}
}
else
handle = topkey;
}
if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
{
QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
Context, QueryTable->EntryContext);
continue;
}
if (!handle)
{
if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
{
ret = STATUS_OBJECT_NAME_NOT_FOUND;
goto out;
}
continue;
}
if (QueryTable->Name == NULL)
{
if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
{
ret = STATUS_INVALID_PARAMETER;
goto out;
}
/* Report all subkeys */
for (i = 0;; ++i)
{
status = NtEnumerateValueKey(handle, i,
KeyValueFullInformation, pInfo, buflen, &len);
if (status == STATUS_NO_MORE_ENTRIES)
break;
if (status == STATUS_BUFFER_OVERFLOW ||
status == STATUS_BUFFER_TOO_SMALL)
{
buflen = len;
RtlFreeHeap(GetProcessHeap(), 0, pInfo);
pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
NtEnumerateValueKey(handle, i, KeyValueFullInformation,
pInfo, buflen, &len);
}
status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
{
ret = status;
goto out;
}
if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
{
RtlInitUnicodeString(&Value, pInfo->Name);
NtDeleteValueKey(handle, &Value);
}
}
if (i == 0 && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
{
ret = STATUS_OBJECT_NAME_NOT_FOUND;
goto out;
}
}
else
{
RtlInitUnicodeString(&Value, QueryTable->Name);
status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
pInfo, buflen, &len);
if (status == STATUS_BUFFER_OVERFLOW ||
status == STATUS_BUFFER_TOO_SMALL)
{
buflen = len;
RtlFreeHeap(GetProcessHeap(), 0, pInfo);
pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
status = NtQueryValueKey(handle, &Value,
KeyValueFullInformation, pInfo, buflen, &len);
}
if (status != STATUS_SUCCESS)
{
if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
{
ret = STATUS_OBJECT_NAME_NOT_FOUND;
goto out;
}
status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
{
ret = status;
goto out;
}
}
else
{
status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
{
ret = status;
goto out;
}
if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
NtDeleteValueKey(handle, &Value);
}
}
}
out:
RtlFreeHeap(GetProcessHeap(), 0, pInfo);
if (handle != topkey)
NtClose(handle);
NtClose(topkey);
return ret;
}
/*************************************************************************
* RtlCheckRegistryKey [NTDLL.@]
*
* Query multiple registry values with a single call.
*
* PARAMS
* RelativeTo [I] Registry path that Path refers to
* Path [I] Path to key
*
* RETURNS
* STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
*/
NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
{
HANDLE handle;
NTSTATUS status;
TRACE("(%ld, %s)\n", RelativeTo, debugstr_w(Path));
if(!RelativeTo && (Path == NULL || Path[0] == 0))
return STATUS_OBJECT_PATH_SYNTAX_BAD;
if(RelativeTo & RTL_REGISTRY_HANDLE)
return STATUS_SUCCESS;
if((RelativeTo <= RTL_REGISTRY_USER) && (Path == NULL || Path[0] == 0))
return STATUS_SUCCESS;
status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
if (handle) NtClose(handle);
if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
return status;
}
/*************************************************************************
* RtlCreateRegistryKey [NTDLL.@]
*
* Add a key to the registry given by absolute or relative path
*
* PARAMS
* RelativeTo [I] Registry path that Path refers to
* path [I] Path to key
*
* RETURNS
* STATUS_SUCCESS or an appropriate NTSTATUS error code.
*/
NTSTATUS WINAPI RtlCreateRegistryKey(ULONG RelativeTo, PWSTR path)
{
OBJECT_ATTRIBUTES regkey;
UNICODE_STRING string;
HANDLE handle;
NTSTATUS status;
RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
if (!RelativeTo && (path == NULL || path[0] == 0))
return STATUS_OBJECT_PATH_SYNTAX_BAD;
if (RelativeTo <= RTL_REGISTRY_USER && (path == NULL || path[0] == 0))
return STATUS_SUCCESS;
status = RTL_KeyHandleCreateObject(RelativeTo, path, &regkey, &string);
if(status != STATUS_SUCCESS)
return status;
status = NtCreateKey(&handle, KEY_ALL_ACCESS, &regkey, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
if (handle) NtClose(handle);
RtlFreeUnicodeString( &string );
return status;
}
/*************************************************************************
* RtlDeleteRegistryValue [NTDLL.@]
*
* Query multiple registry values with a single call.
*
* PARAMS
* RelativeTo [I] Registry path that Path refers to
* Path [I] Path to key
* ValueName [I] Name of the value to delete
*
* RETURNS
* STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
*/
NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
{
NTSTATUS status;
HANDLE handle;
UNICODE_STRING Value;
TRACE("(%ld, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
RtlInitUnicodeString(&Value, ValueName);
if(RelativeTo == RTL_REGISTRY_HANDLE)
{
return NtDeleteValueKey((HANDLE)Path, &Value);
}
status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
if (status) return status;
status = NtDeleteValueKey(handle, &Value);
NtClose(handle);
return status;
}
/*************************************************************************
* RtlWriteRegistryValue [NTDLL.@]
*
* Sets the registry value with provided data.
*
* PARAMS
* RelativeTo [I] Registry path that path parameter refers to
* path [I] Path to the key (or handle - see RTL_GetKeyHandle)
* name [I] Name of the registry value to set
* type [I] Type of the registry key to set
* data [I] Pointer to the user data to be set
* length [I] Length of the user data pointed by data
*
* RETURNS
* STATUS_SUCCESS if the specified key is successfully set,
* or an NTSTATUS error code.
*/
NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
ULONG type, PVOID data, ULONG length )
{
HANDLE hkey;
NTSTATUS status;
UNICODE_STRING str;
TRACE( "(%ld, %s, %s) -> %ld: %p [%ld]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
type, data, length );
RtlInitUnicodeString( &str, name );
if (RelativeTo == RTL_REGISTRY_HANDLE)
return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
if (status != STATUS_SUCCESS) return status;
status = NtSetValueKey( hkey, &str, 0, type, data, length );
NtClose( hkey );
return status;
}