Files
reactos/reactos/lib/advapi32/reg/reg.c
T
Eric Kohl 7ac73dbbc4 RegSetValueExA: lpData can be NULL.
This fixes three failures of the WINE regression tests.

svn path=/trunk/; revision=11614
2004-11-11 11:21:30 +00:00

3435 lines
74 KiB
C

/* $Id: reg.c,v 1.62 2004/11/11 11:21:30 ekohl Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/advapi32/reg/reg.c
* PURPOSE: Registry functions
* PROGRAMMER: Ariadne ( [email protected])
* UPDATE HISTORY:
* Created 01/11/98
* 19990309 EA Stubs
*/
/* INCLUDES *****************************************************************/
#include "advapi32.h"
#define NDEBUG
#include <debug.h>
/* DEFINES ******************************************************************/
#define MAX_DEFAULT_HANDLES 6
#define REG_MAX_NAME_SIZE 256
#define REG_MAX_DATA_SIZE 2048
/* GLOBALS ******************************************************************/
static CRITICAL_SECTION HandleTableCS;
static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
static HANDLE ProcessHeap;
/* PROTOTYPES ***************************************************************/
static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
static VOID CloseDefaultKeys(VOID);
static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
static NTSTATUS OpenUsersKey (PHANDLE KeyHandle);
static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
/* FUNCTIONS ****************************************************************/
/************************************************************************
* RegInitDefaultHandles
*/
BOOL
RegInitialize (VOID)
{
DPRINT("RegInitialize()\n");
ProcessHeap = RtlGetProcessHeap();
RtlZeroMemory (DefaultHandleTable,
MAX_DEFAULT_HANDLES * sizeof(HANDLE));
RtlInitializeCriticalSection (&HandleTableCS);
return TRUE;
}
/************************************************************************
* RegInit
*/
BOOL
RegCleanup (VOID)
{
DPRINT("RegCleanup()\n");
CloseDefaultKeys ();
RtlDeleteCriticalSection (&HandleTableCS);
return TRUE;
}
static NTSTATUS
MapDefaultKey (PHANDLE RealKey,
HKEY Key)
{
PHANDLE Handle;
ULONG Index;
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("MapDefaultKey (Key %x)\n", Key);
if (((ULONG)Key & 0xF0000000) != 0x80000000)
{
*RealKey = (HANDLE)Key;
return STATUS_SUCCESS;
}
/* Handle special cases here */
Index = (ULONG)Key & 0x0FFFFFFF;
if (Index >= MAX_DEFAULT_HANDLES)
{
return STATUS_INVALID_PARAMETER;
}
RtlEnterCriticalSection (&HandleTableCS);
Handle = &DefaultHandleTable[Index];
if (*Handle == NULL)
{
/* create/open the default handle */
switch (Index)
{
case 0: /* HKEY_CLASSES_ROOT */
Status = OpenClassesRootKey (Handle);
break;
case 1: /* HKEY_CURRENT_USER */
Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
Handle);
break;
case 2: /* HKEY_LOCAL_MACHINE */
Status = OpenLocalMachineKey (Handle);
break;
case 3: /* HKEY_USERS */
Status = OpenUsersKey (Handle);
break;
#if 0
case 4: /* HKEY_PERFORMANCE_DATA */
Status = OpenPerformanceDataKey (Handle);
break;
#endif
case 5: /* HKEY_CURRENT_CONFIG */
Status = OpenCurrentConfigKey (Handle);
break;
case 6: /* HKEY_DYN_DATA */
Status = STATUS_NOT_IMPLEMENTED;
break;
default:
DPRINT("MapDefaultHandle() no handle creator\n");
Status = STATUS_INVALID_PARAMETER;
}
}
RtlLeaveCriticalSection (&HandleTableCS);
if (NT_SUCCESS(Status))
{
*RealKey = *Handle;
}
return Status;
}
static VOID
CloseDefaultKeys (VOID)
{
ULONG i;
RtlEnterCriticalSection (&HandleTableCS);
for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
{
if (DefaultHandleTable[i] != NULL)
{
NtClose (DefaultHandleTable[i]);
DefaultHandleTable[i] = NULL;
}
}
RtlLeaveCriticalSection (&HandleTableCS);
}
static NTSTATUS
OpenClassesRootKey (PHANDLE KeyHandle)
{
OBJECT_ATTRIBUTES Attributes;
UNICODE_STRING KeyName = ROS_STRING_INITIALIZER(L"\\Registry\\Machine\\Software\\CLASSES");
DPRINT("OpenClassesRootKey()\n");
InitializeObjectAttributes (&Attributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
return NtOpenKey (KeyHandle,
MAXIMUM_ALLOWED,
&Attributes);
}
static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle)
{
OBJECT_ATTRIBUTES Attributes;
UNICODE_STRING KeyName = ROS_STRING_INITIALIZER(L"\\Registry\\Machine");
NTSTATUS Status;
DPRINT("OpenLocalMachineKey()\n");
InitializeObjectAttributes (&Attributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey (KeyHandle,
MAXIMUM_ALLOWED,
&Attributes);
DPRINT("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
return Status;
}
static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle)
{
OBJECT_ATTRIBUTES Attributes;
UNICODE_STRING KeyName = ROS_STRING_INITIALIZER(L"\\Registry\\User");
DPRINT("OpenUsersKey()\n");
InitializeObjectAttributes (&Attributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
return NtOpenKey (KeyHandle,
KEY_ALL_ACCESS,
&Attributes);
}
static NTSTATUS
OpenCurrentConfigKey (PHANDLE KeyHandle)
{
OBJECT_ATTRIBUTES Attributes;
UNICODE_STRING KeyName =
ROS_STRING_INITIALIZER(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
DPRINT("OpenCurrentConfigKey()\n");
InitializeObjectAttributes (&Attributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
return NtOpenKey (KeyHandle,
MAXIMUM_ALLOWED,
&Attributes);
}
/************************************************************************
* RegCloseKey
*
* @implemented
*/
LONG STDCALL
RegCloseKey (HKEY hKey)
{
LONG ErrorCode;
NTSTATUS Status;
/* don't close null handle or a pseudo handle */
if ((!hKey) || (((ULONG)hKey & 0xF0000000) == 0x80000000))
{
return ERROR_INVALID_HANDLE;
}
Status = NtClose (hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegConnectRegistryA
*
* @unimplemented
*/
LONG STDCALL
RegConnectRegistryA (LPCSTR lpMachineName,
HKEY hKey,
PHKEY phkResult)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return ERROR_CALL_NOT_IMPLEMENTED;
}
/************************************************************************
* RegConnectRegistryW
*
* @unimplemented
*/
LONG STDCALL
RegConnectRegistryW (LPCWSTR lpMachineName,
HKEY hKey,
PHKEY phkResult)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return ERROR_CALL_NOT_IMPLEMENTED;
}
/************************************************************************
* CreateNestedKey
*
* Create key and all necessary intermediate keys
*/
static NTSTATUS
CreateNestedKey(PHKEY KeyHandle,
POBJECT_ATTRIBUTES ObjectAttributes,
PUNICODE_STRING ClassString,
DWORD dwOptions,
REGSAM samDesired,
DWORD *lpdwDisposition)
{
OBJECT_ATTRIBUTES LocalObjectAttributes;
UNICODE_STRING LocalKeyName;
ULONG Disposition;
NTSTATUS Status;
ULONG FullNameLength;
ULONG Length;
PWCHAR Ptr;
HANDLE LocalKeyHandle;
Status = NtCreateKey((PHANDLE) KeyHandle,
samDesired,
ObjectAttributes,
0,
ClassString,
dwOptions,
(PULONG)lpdwDisposition);
DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
return Status;
/* Copy object attributes */
RtlCopyMemory (&LocalObjectAttributes,
ObjectAttributes,
sizeof(OBJECT_ATTRIBUTES));
RtlCreateUnicodeString (&LocalKeyName,
ObjectAttributes->ObjectName->Buffer);
LocalObjectAttributes.ObjectName = &LocalKeyName;
FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
/* Remove the last part of the key name and try to create the key again. */
while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
Ptr = wcsrchr (LocalKeyName.Buffer, '\\');
if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
*Ptr = (WCHAR)0;
LocalKeyName.Length = wcslen (LocalKeyName.Buffer) * sizeof(WCHAR);
Status = NtCreateKey (&LocalKeyHandle,
KEY_ALL_ACCESS,
&LocalObjectAttributes,
0,
NULL,
0,
&Disposition);
DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
}
if (!NT_SUCCESS(Status))
{
RtlFreeUnicodeString (&LocalKeyName);
return Status;
}
/* Add removed parts of the key name and create them too. */
Length = wcslen (LocalKeyName.Buffer);
while (TRUE)
{
NtClose (LocalKeyHandle);
LocalKeyName.Buffer[Length] = L'\\';
Length = wcslen (LocalKeyName.Buffer);
LocalKeyName.Length = Length * sizeof(WCHAR);
if (Length == FullNameLength)
{
Status = NtCreateKey((PHANDLE) KeyHandle,
samDesired,
ObjectAttributes,
0,
ClassString,
dwOptions,
(PULONG)lpdwDisposition);
break;
}
Status = NtCreateKey (&LocalKeyHandle,
KEY_ALL_ACCESS,
&LocalObjectAttributes,
0,
NULL,
0,
&Disposition);
DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
if (!NT_SUCCESS(Status))
break;
}
RtlFreeUnicodeString (&LocalKeyName);
return Status;
}
/************************************************************************
* RegCreateKeyExA
*
* @implemented
*/
LONG STDCALL
RegCreateKeyExA (HKEY hKey,
LPCSTR lpSubKey,
DWORD Reserved,
LPSTR lpClass,
DWORD dwOptions,
REGSAM samDesired,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
PHKEY phkResult,
LPDWORD lpdwDisposition)
{
UNICODE_STRING SubKeyString;
UNICODE_STRING ClassString;
OBJECT_ATTRIBUTES Attributes;
HANDLE ParentKey;
LONG ErrorCode;
NTSTATUS Status;
DPRINT("RegCreateKeyExA() called\n");
/* get the real parent key */
Status = MapDefaultKey (&ParentKey,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
DPRINT("ParentKey %x\n", (ULONG)ParentKey);
if (lpClass != NULL)
{
RtlCreateUnicodeStringFromAsciiz (&ClassString,
lpClass);
}
RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
(LPSTR)lpSubKey);
InitializeObjectAttributes (&Attributes,
&SubKeyString,
OBJ_CASE_INSENSITIVE,
(HANDLE)ParentKey,
(PSECURITY_DESCRIPTOR)lpSecurityAttributes);
Status = CreateNestedKey(phkResult,
&Attributes,
(lpClass == NULL)? NULL : &ClassString,
dwOptions,
samDesired,
lpdwDisposition);
RtlFreeUnicodeString (&SubKeyString);
if (lpClass != NULL)
{
RtlFreeUnicodeString (&ClassString);
}
DPRINT("Status %x\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegCreateKeyExW
*
* @implemented
*/
LONG STDCALL
RegCreateKeyExW (HKEY hKey,
LPCWSTR lpSubKey,
DWORD Reserved,
LPWSTR lpClass,
DWORD dwOptions,
REGSAM samDesired,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
PHKEY phkResult,
LPDWORD lpdwDisposition)
{
UNICODE_STRING SubKeyString;
UNICODE_STRING ClassString;
OBJECT_ATTRIBUTES Attributes;
HANDLE ParentKey;
LONG ErrorCode;
NTSTATUS Status;
DPRINT("RegCreateKeyExW() called\n");
/* get the real parent key */
Status = MapDefaultKey (&ParentKey,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError(Status);
SetLastError (ErrorCode);
return ErrorCode;
}
DPRINT("ParentKey %x\n", (ULONG)ParentKey);
RtlInitUnicodeString (&ClassString,
lpClass);
RtlInitUnicodeString (&SubKeyString,
lpSubKey);
InitializeObjectAttributes (&Attributes,
&SubKeyString,
OBJ_CASE_INSENSITIVE,
(HANDLE)ParentKey,
(PSECURITY_DESCRIPTOR)lpSecurityAttributes);
Status = CreateNestedKey(phkResult,
&Attributes,
(lpClass == NULL)? NULL : &ClassString,
dwOptions,
samDesired,
lpdwDisposition);
DPRINT("Status %x\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegCreateKeyA
*
* @implemented
*/
LONG STDCALL
RegCreateKeyA (HKEY hKey,
LPCSTR lpSubKey,
PHKEY phkResult)
{
return RegCreateKeyExA (hKey,
lpSubKey,
0,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
phkResult,
NULL);
}
/************************************************************************
* RegCreateKeyW
*
* @implemented
*/
LONG STDCALL
RegCreateKeyW (HKEY hKey,
LPCWSTR lpSubKey,
PHKEY phkResult)
{
return RegCreateKeyExW (hKey,
lpSubKey,
0,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
phkResult,
NULL);
}
/************************************************************************
* RegDeleteKeyA
*
* @implemented
*/
LONG STDCALL
RegDeleteKeyA (HKEY hKey,
LPCSTR lpSubKey)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyName;
HANDLE ParentKey;
HANDLE TargetKey;
NTSTATUS Status;
LONG ErrorCode;
Status = MapDefaultKey (&ParentKey,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
RtlCreateUnicodeStringFromAsciiz (&SubKeyName,
(LPSTR)lpSubKey);
InitializeObjectAttributes(&ObjectAttributes,
&SubKeyName,
OBJ_CASE_INSENSITIVE,
(HANDLE)ParentKey,
NULL);
Status = NtOpenKey (&TargetKey,
DELETE,
&ObjectAttributes);
RtlFreeUnicodeString (&SubKeyName);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
Status = NtDeleteKey (TargetKey);
NtClose (TargetKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError(Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegDeleteKeyW
*
* @implemented
*/
LONG STDCALL
RegDeleteKeyW (HKEY hKey,
LPCWSTR lpSubKey)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyName;
HANDLE ParentKey;
HANDLE TargetKey;
NTSTATUS Status;
LONG ErrorCode;
Status = MapDefaultKey (&ParentKey,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
RtlInitUnicodeString (&SubKeyName,
(LPWSTR)lpSubKey);
InitializeObjectAttributes (&ObjectAttributes,
&SubKeyName,
OBJ_CASE_INSENSITIVE,
(HANDLE)ParentKey,
NULL);
Status = NtOpenKey (&TargetKey,
DELETE,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
Status = NtDeleteKey (TargetKey);
NtClose (TargetKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegDeleteValueA
*
* @implemented
*/
LONG STDCALL
RegDeleteValueA (HKEY hKey,
LPCSTR lpValueName)
{
UNICODE_STRING ValueName;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
RtlCreateUnicodeStringFromAsciiz (&ValueName,
(LPSTR)lpValueName);
Status = NtDeleteValueKey (KeyHandle,
&ValueName);
RtlFreeUnicodeString (&ValueName);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegDeleteValueW
*
* @implemented
*/
LONG STDCALL
RegDeleteValueW (HKEY hKey,
LPCWSTR lpValueName)
{
UNICODE_STRING ValueName;
NTSTATUS Status;
LONG ErrorCode;
HANDLE KeyHandle;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
RtlInitUnicodeString (&ValueName,
(LPWSTR)lpValueName);
Status = NtDeleteValueKey (KeyHandle,
&ValueName);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegEnumKeyA
*
* @implemented
*/
LONG STDCALL
RegEnumKeyA (HKEY hKey,
DWORD dwIndex,
LPSTR lpName,
DWORD cbName)
{
DWORD dwLength;
dwLength = cbName;
return RegEnumKeyExA (hKey,
dwIndex,
lpName,
&dwLength,
NULL,
NULL,
NULL,
NULL);
}
/************************************************************************
* RegEnumKeyW
*
* @implemented
*/
LONG STDCALL
RegEnumKeyW (HKEY hKey,
DWORD dwIndex,
LPWSTR lpName,
DWORD cbName)
{
DWORD dwLength;
dwLength = cbName;
return RegEnumKeyExW (hKey,
dwIndex,
lpName,
&dwLength,
NULL,
NULL,
NULL,
NULL);
}
/************************************************************************
* RegEnumKeyExA
*
* @implemented
*/
LONG STDCALL
RegEnumKeyExA (HKEY hKey,
DWORD dwIndex,
LPSTR lpName,
LPDWORD lpcbName,
LPDWORD lpReserved,
LPSTR lpClass,
LPDWORD lpcbClass,
PFILETIME lpftLastWriteTime)
{
union
{
KEY_NODE_INFORMATION Node;
KEY_BASIC_INFORMATION Basic;
} *KeyInfo;
UNICODE_STRING StringU;
ANSI_STRING StringA;
LONG ErrorCode = ERROR_SUCCESS;
DWORD NameLength;
DWORD ClassLength = 0;
DWORD BufferSize;
DWORD ResultSize;
HANDLE KeyHandle;
NTSTATUS Status;
DPRINT("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
if ((lpClass) && (!lpcbClass))
{
SetLastError (ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
Status = MapDefaultKey(&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (*lpcbName > 0)
{
NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
}
else
{
NameLength = 0;
}
if (lpClass)
{
if (*lpcbClass > 0)
{
ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else
{
ClassLength = 0;
}
/* The class name should start at a dword boundary */
BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
}
else
{
BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
}
KeyInfo = RtlAllocateHeap (ProcessHeap,
0,
BufferSize);
if (KeyInfo == NULL)
{
SetLastError (ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtEnumerateKey (KeyHandle,
(ULONG)dwIndex,
lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
KeyInfo,
BufferSize,
&ResultSize);
DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
if (lpClass == NULL)
{
if (KeyInfo->Basic.NameLength > NameLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
StringU.Buffer = KeyInfo->Basic.Name;
StringU.Length = KeyInfo->Basic.NameLength;
StringU.MaximumLength = KeyInfo->Basic.NameLength;
}
}
else
{
if (KeyInfo->Node.NameLength > NameLength ||
KeyInfo->Node.ClassLength > ClassLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
StringA.Buffer = lpClass;
StringA.Length = 0;
StringA.MaximumLength = *lpcbClass;
StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
StringU.Length = KeyInfo->Node.ClassLength;
StringU.MaximumLength = KeyInfo->Node.ClassLength;
RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
lpClass[StringA.Length] = 0;
*lpcbClass = StringA.Length;
StringU.Buffer = KeyInfo->Node.Name;
StringU.Length = KeyInfo->Node.NameLength;
StringU.MaximumLength = KeyInfo->Node.NameLength;
}
}
if (ErrorCode == ERROR_SUCCESS)
{
StringA.Buffer = lpName;
StringA.Length = 0;
StringA.MaximumLength = *lpcbName;
RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
lpName[StringA.Length] = 0;
*lpcbName = StringA.Length;
if (lpftLastWriteTime != NULL)
{
if (lpClass == NULL)
{
lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
}
else
{
lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
}
}
}
}
DPRINT("Key Namea0 Length %d\n", StringU.Length);
DPRINT("Key Namea1 Length %d\n", NameLength);
DPRINT("Key Namea Length %d\n", *lpcbName);
DPRINT("Key Namea %s\n", lpName);
RtlFreeHeap (ProcessHeap,
0,
KeyInfo);
if (ErrorCode != ERROR_SUCCESS)
{
SetLastError(ErrorCode);
}
return ErrorCode;
}
/************************************************************************
* RegEnumKeyExW
*
* @implemented
*/
LONG STDCALL
RegEnumKeyExW (HKEY hKey,
DWORD dwIndex,
LPWSTR lpName,
LPDWORD lpcbName,
LPDWORD lpReserved,
LPWSTR lpClass,
LPDWORD lpcbClass,
PFILETIME lpftLastWriteTime)
{
union
{
KEY_NODE_INFORMATION Node;
KEY_BASIC_INFORMATION Basic;
} *KeyInfo;
ULONG BufferSize;
ULONG ResultSize;
ULONG NameLength;
ULONG ClassLength = 0;
HANDLE KeyHandle;
LONG ErrorCode = ERROR_SUCCESS;
NTSTATUS Status;
Status = MapDefaultKey(&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (*lpcbName > 0)
{
NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
}
else
{
NameLength = 0;
}
if (lpClass)
{
if (*lpcbClass > 0)
{
ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else
{
ClassLength = 0;
}
BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
}
else
{
BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
}
KeyInfo = RtlAllocateHeap (ProcessHeap,
0,
BufferSize);
if (KeyInfo == NULL)
{
SetLastError (ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtEnumerateKey (KeyHandle,
(ULONG)dwIndex,
lpClass ? KeyNodeInformation : KeyBasicInformation,
KeyInfo,
BufferSize,
&ResultSize);
DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
if (lpClass == NULL)
{
if (KeyInfo->Basic.NameLength > NameLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
RtlCopyMemory (lpName,
KeyInfo->Basic.Name,
KeyInfo->Basic.NameLength);
*lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
lpName[*lpcbName] = 0;
}
}
else
{
if (KeyInfo->Node.NameLength > NameLength ||
KeyInfo->Node.ClassLength > ClassLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
RtlCopyMemory (lpName,
KeyInfo->Node.Name,
KeyInfo->Node.NameLength);
*lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
lpName[*lpcbName] = 0;
RtlCopyMemory (lpClass,
(PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
KeyInfo->Node.ClassLength);
*lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
lpClass[*lpcbClass] = 0;
}
}
if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
{
if (lpClass == NULL)
{
lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
}
else
{
lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
}
}
}
RtlFreeHeap (ProcessHeap,
0,
KeyInfo);
if (ErrorCode != ERROR_SUCCESS)
{
SetLastError(ErrorCode);
}
return ErrorCode;
}
/************************************************************************
* RegEnumValueA
*
* @implemented
*/
LONG STDCALL
RegEnumValueA (HKEY hKey,
DWORD dwIndex,
LPSTR lpValueName,
LPDWORD lpcbValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData)
{
union
{
KEY_VALUE_FULL_INFORMATION Full;
KEY_VALUE_BASIC_INFORMATION Basic;
} *ValueInfo;
ULONG NameLength;
ULONG BufferSize;
ULONG DataLength = 0;
ULONG ResultSize;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
UNICODE_STRING StringU;
ANSI_STRING StringA;
BOOL IsStringType;
ErrorCode = ERROR_SUCCESS;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (*lpcbValueName > 0)
{
NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else
{
NameLength = 0;
}
if (lpData)
{
DataLength = min (*lpcbData * sizeof(WCHAR), REG_MAX_DATA_SIZE);
BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
}
else
{
BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
}
ValueInfo = RtlAllocateHeap (ProcessHeap,
0,
BufferSize);
if (ValueInfo == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtEnumerateValueKey (KeyHandle,
(ULONG)dwIndex,
lpData ? KeyValueFullInformation : KeyValueBasicInformation,
ValueInfo,
BufferSize,
&ResultSize);
DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
if (lpData)
{
IsStringType = (ValueInfo->Full.Type == REG_SZ) ||
(ValueInfo->Full.Type == REG_MULTI_SZ) ||
(ValueInfo->Full.Type == REG_EXPAND_SZ);
if (ValueInfo->Full.NameLength > NameLength ||
(!IsStringType && ValueInfo->Full.DataLength > *lpcbData) ||
ValueInfo->Full.DataLength > DataLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
if (IsStringType)
{
StringU.Buffer = (PWCHAR)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset);
StringU.Length = ValueInfo->Full.DataLength;
StringU.MaximumLength = DataLength;
StringA.Buffer = (PCHAR)lpData;
StringA.Length = 0;
StringA.MaximumLength = *lpcbData;
RtlUnicodeStringToAnsiString (&StringA,
&StringU,
FALSE);
*lpcbData = StringA.Length;
}
else
{
RtlCopyMemory (lpData,
(PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
ValueInfo->Full.DataLength);
*lpcbData = ValueInfo->Full.DataLength;
}
StringU.Buffer = ValueInfo->Full.Name;
StringU.Length = ValueInfo->Full.NameLength;
StringU.MaximumLength = NameLength;
}
}
else
{
if (ValueInfo->Basic.NameLength > NameLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
StringU.Buffer = ValueInfo->Basic.Name;
StringU.Length = ValueInfo->Basic.NameLength;
StringU.MaximumLength = NameLength;
}
}
if (ErrorCode == ERROR_SUCCESS)
{
StringA.Buffer = (PCHAR)lpValueName;
StringA.Length = 0;
StringA.MaximumLength = *lpcbValueName;
RtlUnicodeStringToAnsiString (&StringA,
&StringU,
FALSE);
StringA.Buffer[StringA.Length] = 0;
*lpcbValueName = StringA.Length;
if (lpType)
{
*lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
}
}
}
RtlFreeHeap (ProcessHeap,
0,
ValueInfo);
if (ErrorCode != ERROR_SUCCESS)
{
SetLastError(ErrorCode);
}
return ErrorCode;
}
/************************************************************************
* RegEnumValueW
*
* @implemented
*/
LONG STDCALL
RegEnumValueW (HKEY hKey,
DWORD dwIndex,
LPWSTR lpValueName,
LPDWORD lpcbValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData)
{
union
{
KEY_VALUE_FULL_INFORMATION Full;
KEY_VALUE_BASIC_INFORMATION Basic;
} *ValueInfo;
ULONG NameLength;
ULONG BufferSize;
ULONG DataLength = 0;
ULONG ResultSize;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
ErrorCode = ERROR_SUCCESS;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (*lpcbValueName > 0)
{
NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else
{
NameLength = 0;
}
if (lpData)
{
DataLength = min(*lpcbData, REG_MAX_DATA_SIZE);
BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
}
else
{
BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
}
ValueInfo = RtlAllocateHeap (ProcessHeap,
0,
BufferSize);
if (ValueInfo == NULL)
{
SetLastError (ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtEnumerateValueKey (KeyHandle,
(ULONG)dwIndex,
lpData ? KeyValueFullInformation : KeyValueBasicInformation,
ValueInfo,
BufferSize,
&ResultSize);
DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
if (lpData)
{
if (ValueInfo->Full.DataLength > DataLength ||
ValueInfo->Full.NameLength > NameLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
RtlCopyMemory (lpValueName,
ValueInfo->Full.Name,
ValueInfo->Full.NameLength);
*lpcbValueName = (DWORD)(ValueInfo->Full.NameLength / sizeof(WCHAR));
lpValueName[*lpcbValueName] = 0;
RtlCopyMemory (lpData,
(PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
ValueInfo->Full.DataLength);
*lpcbData = (DWORD)ValueInfo->Full.DataLength;
}
}
else
{
if (ValueInfo->Basic.NameLength > NameLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
RtlCopyMemory (lpValueName,
ValueInfo->Basic.Name,
ValueInfo->Basic.NameLength);
*lpcbValueName = (DWORD)(ValueInfo->Basic.NameLength / sizeof(WCHAR));
lpValueName[*lpcbValueName] = 0;
}
if (NULL != lpcbData)
{
*lpcbData = (DWORD)ValueInfo->Full.DataLength;
}
}
if (ErrorCode == ERROR_SUCCESS && lpType != NULL)
{
*lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
}
}
RtlFreeHeap (ProcessHeap,
0,
ValueInfo);
if (ErrorCode != ERROR_SUCCESS)
{
SetLastError (ErrorCode);
}
return ErrorCode;
}
/************************************************************************
* RegFlushKey
*
* @implemented
*/
LONG STDCALL
RegFlushKey(HKEY hKey)
{
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
if (hKey == HKEY_PERFORMANCE_DATA)
{
return ERROR_SUCCESS;
}
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
Status = NtFlushKey (KeyHandle);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegGetKeySecurity
*
* @implemented
*/
LONG STDCALL
RegGetKeySecurity(HKEY hKey,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
LPDWORD lpcbSecurityDescriptor)
{
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
if (hKey == HKEY_PERFORMANCE_DATA)
{
SetLastError(ERROR_INVALID_HANDLE);
return ERROR_INVALID_HANDLE;
}
Status = MapDefaultKey(&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
DPRINT("MapDefaultKey() failed (Status %lx)\n", Status);
ErrorCode = RtlNtStatusToDosError(Status);
SetLastError(ErrorCode);
return ErrorCode;
}
Status = NtQuerySecurityObject(KeyHandle,
SecurityInformation,
pSecurityDescriptor,
*lpcbSecurityDescriptor,
lpcbSecurityDescriptor);
if (!NT_SUCCESS(Status))
{
DPRINT("NtQuerySecurityObject() failed (Status %lx)\n", Status);
ErrorCode = RtlNtStatusToDosError(Status);
SetLastError(ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegLoadKeyA
*
* @implemented
*/
LONG STDCALL
RegLoadKeyA (HKEY hKey,
LPCSTR lpSubKey,
LPCSTR lpFile)
{
UNICODE_STRING FileName;
UNICODE_STRING KeyName;
LONG ErrorCode;
RtlCreateUnicodeStringFromAsciiz (&KeyName,
(LPSTR)lpSubKey);
RtlCreateUnicodeStringFromAsciiz (&FileName,
(LPSTR)lpFile);
ErrorCode = RegLoadKeyW (hKey,
KeyName.Buffer,
FileName.Buffer);
RtlFreeUnicodeString (&FileName);
RtlFreeUnicodeString (&KeyName);
return ErrorCode;
}
/************************************************************************
* RegLoadKeyW
*
* @implemented
*/
LONG STDCALL
RegLoadKeyW (HKEY hKey,
LPCWSTR lpSubKey,
LPCWSTR lpFile)
{
OBJECT_ATTRIBUTES FileObjectAttributes;
OBJECT_ATTRIBUTES KeyObjectAttributes;
UNICODE_STRING FileName;
UNICODE_STRING KeyName;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
if (hKey == HKEY_PERFORMANCE_DATA)
{
SetLastError(ERROR_INVALID_HANDLE);
return ERROR_INVALID_HANDLE;
}
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
&FileName,
NULL,
NULL))
{
SetLastError (ERROR_BAD_PATHNAME);
return ERROR_BAD_PATHNAME;
}
InitializeObjectAttributes (&FileObjectAttributes,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
RtlInitUnicodeString (&KeyName,
(LPWSTR)lpSubKey);
InitializeObjectAttributes (&KeyObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtLoadKey (&KeyObjectAttributes,
&FileObjectAttributes);
RtlFreeUnicodeString (&FileName);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegNotifyChangeKeyValue
*
* @unimplemented
*/
LONG STDCALL
RegNotifyChangeKeyValue (HKEY hKey,
BOOL bWatchSubtree,
DWORD dwNotifyFilter,
HANDLE hEvent,
BOOL fAsynchronous)
{
IO_STATUS_BLOCK IoStatusBlock;
HANDLE KeyHandle;
NTSTATUS Status;
if (hKey == HKEY_PERFORMANCE_DATA)
{
return ERROR_INVALID_HANDLE;
}
if (fAsynchronous == TRUE && hEvent == NULL)
{
return ERROR_INVALID_PARAMETER;
}
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
return RtlNtStatusToDosError (Status);
}
/* FIXME: Remote key handles must fail */
Status = NtNotifyChangeKey (KeyHandle,
hEvent,
0,
0,
&IoStatusBlock,
dwNotifyFilter,
bWatchSubtree,
0,
0,
fAsynchronous);
if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
{
return RtlNtStatusToDosError (Status);
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegOpenKeyA
*
* @implemented
*/
LONG STDCALL
RegOpenKeyA (HKEY hKey,
LPCSTR lpSubKey,
PHKEY phkResult)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyString;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
RtlCreateUnicodeStringFromAsciiz (&SubKeyString,
(LPSTR)lpSubKey);
InitializeObjectAttributes (&ObjectAttributes,
&SubKeyString,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtOpenKey ((PHANDLE)phkResult,
MAXIMUM_ALLOWED,
&ObjectAttributes);
RtlFreeUnicodeString (&SubKeyString);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegOpenKeyW
*
* 19981101 Ariadne
* 19990525 EA
*
* @implemented
*/
LONG STDCALL
RegOpenKeyW (HKEY hKey,
LPCWSTR lpSubKey,
PHKEY phkResult)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyString;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
RtlInitUnicodeString (&SubKeyString,
(LPWSTR)lpSubKey);
InitializeObjectAttributes (&ObjectAttributes,
&SubKeyString,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtOpenKey ((PHANDLE)phkResult,
MAXIMUM_ALLOWED,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError(ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegOpenKeyExA
*
* @implemented
*/
LONG STDCALL
RegOpenKeyExA (HKEY hKey,
LPCSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyString;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
RtlCreateUnicodeStringFromAsciiz (&SubKeyString,
(LPSTR)lpSubKey);
InitializeObjectAttributes (&ObjectAttributes,
&SubKeyString,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtOpenKey ((PHANDLE)phkResult,
samDesired,
&ObjectAttributes);
RtlFreeUnicodeString (&SubKeyString);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegOpenKeyExW
*
* @implemented
*/
LONG STDCALL
RegOpenKeyExW (HKEY hKey,
LPCWSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyString;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (lpSubKey != NULL)
{
RtlInitUnicodeString (&SubKeyString,
(LPWSTR)lpSubKey);
}
else
{
RtlInitUnicodeString (&SubKeyString,
(LPWSTR)L"");
}
InitializeObjectAttributes (&ObjectAttributes,
&SubKeyString,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtOpenKey ((PHANDLE)phkResult,
samDesired,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegQueryInfoKeyA
*
* @implemented
*/
LONG STDCALL
RegQueryInfoKeyA (HKEY hKey,
LPSTR lpClass,
LPDWORD lpcbClass,
LPDWORD lpReserved,
LPDWORD lpcSubKeys,
LPDWORD lpcbMaxSubKeyLen,
LPDWORD lpcbMaxClassLen,
LPDWORD lpcValues,
LPDWORD lpcbMaxValueNameLen,
LPDWORD lpcbMaxValueLen,
LPDWORD lpcbSecurityDescriptor,
PFILETIME lpftLastWriteTime)
{
WCHAR ClassName[MAX_PATH];
UNICODE_STRING UnicodeString;
ANSI_STRING AnsiString;
LONG ErrorCode;
RtlInitUnicodeString (&UnicodeString,
NULL);
if (lpClass != NULL)
{
UnicodeString.Buffer = &ClassName[0];
UnicodeString.MaximumLength = sizeof(ClassName);
AnsiString.MaximumLength = *lpcbClass;
}
ErrorCode = RegQueryInfoKeyW (hKey,
UnicodeString.Buffer,
lpcbClass,
lpReserved,
lpcSubKeys,
lpcbMaxSubKeyLen,
lpcbMaxClassLen,
lpcValues,
lpcbMaxValueNameLen,
lpcbMaxValueLen,
lpcbSecurityDescriptor,
lpftLastWriteTime);
if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
{
AnsiString.Buffer = lpClass;
AnsiString.Length = 0;
UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
RtlUnicodeStringToAnsiString (&AnsiString,
&UnicodeString,
FALSE);
*lpcbClass = AnsiString.Length;
lpClass[AnsiString.Length] = 0;
}
return ErrorCode;
}
/************************************************************************
* RegQueryInfoKeyW
*
* @implemented
*/
LONG STDCALL
RegQueryInfoKeyW (HKEY hKey,
LPWSTR lpClass,
LPDWORD lpcbClass,
LPDWORD lpReserved,
LPDWORD lpcSubKeys,
LPDWORD lpcbMaxSubKeyLen,
LPDWORD lpcbMaxClassLen,
LPDWORD lpcValues,
LPDWORD lpcbMaxValueNameLen,
LPDWORD lpcbMaxValueLen,
LPDWORD lpcbSecurityDescriptor,
PFILETIME lpftLastWriteTime)
{
KEY_FULL_INFORMATION FullInfoBuffer;
PKEY_FULL_INFORMATION FullInfo;
ULONG FullInfoSize;
ULONG ClassLength = 0;
HANDLE KeyHandle;
NTSTATUS Status;
LONG ErrorCode = ERROR_SUCCESS;
ULONG Length;
if ((lpClass) && (!lpcbClass))
{
SetLastError(ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (lpClass != NULL)
{
if (*lpcbClass > 0)
{
ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else
{
ClassLength = 0;
}
FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
FullInfo = RtlAllocateHeap (ProcessHeap,
0,
FullInfoSize);
if (FullInfo == NULL)
{
SetLastError (ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
FullInfo->ClassLength = ClassLength;
}
else
{
FullInfoSize = sizeof(KEY_FULL_INFORMATION);
FullInfo = &FullInfoBuffer;
FullInfo->ClassLength = 0;
}
FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
Status = NtQueryKey (KeyHandle,
KeyFullInformation,
FullInfo,
FullInfoSize,
&Length);
DPRINT("NtQueryKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(Status))
{
if (lpClass != NULL)
{
RtlFreeHeap (ProcessHeap,
0,
FullInfo);
}
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
DPRINT("SubKeys %d\n", FullInfo->SubKeys);
if (lpcSubKeys != NULL)
{
*lpcSubKeys = FullInfo->SubKeys;
}
DPRINT("MaxNameLen %lu\n", FullInfo->MaxNameLen);
if (lpcbMaxSubKeyLen != NULL)
{
*lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
}
DPRINT("MaxClassLen %lu\n", FullInfo->MaxClassLen);
if (lpcbMaxClassLen != NULL)
{
*lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
}
DPRINT("Values %lu\n", FullInfo->Values);
if (lpcValues != NULL)
{
*lpcValues = FullInfo->Values;
}
DPRINT("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
if (lpcbMaxValueNameLen != NULL)
{
*lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
}
DPRINT("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
if (lpcbMaxValueLen != NULL)
{
*lpcbMaxValueLen = FullInfo->MaxValueDataLen;
}
if (lpcbSecurityDescriptor != NULL)
{
Status = NtQuerySecurityObject(KeyHandle,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
NULL,
0,
lpcbSecurityDescriptor);
if (!NT_SUCCESS(Status))
{
if (lpClass != NULL)
{
RtlFreeHeap(ProcessHeap,
0,
FullInfo);
}
ErrorCode = RtlNtStatusToDosError(Status);
SetLastError(ErrorCode);
return ErrorCode;
}
}
if (lpftLastWriteTime != NULL)
{
lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
}
if (lpClass != NULL)
{
if (FullInfo->ClassLength > ClassLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
RtlCopyMemory (lpClass,
FullInfo->Class,
FullInfo->ClassLength);
*lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
lpClass[*lpcbClass] = 0;
}
RtlFreeHeap (ProcessHeap,
0,
FullInfo);
}
if (ErrorCode != ERROR_SUCCESS)
{
SetLastError (ErrorCode);
}
return ErrorCode;
}
/************************************************************************
* RegQueryMultipleValuesA
*
* @implemented
*/
LONG STDCALL
RegQueryMultipleValuesA (HKEY hKey,
PVALENTA val_list,
DWORD num_vals,
LPSTR lpValueBuf,
LPDWORD ldwTotsize)
{
ULONG i;
DWORD maxBytes = *ldwTotsize;
LPSTR bufptr = (LPSTR)lpValueBuf;
LONG ErrorCode;
if (maxBytes >= (1024*1024))
return ERROR_TRANSFER_TOO_LONG;
*ldwTotsize = 0;
DPRINT ("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
for (i = 0; i < num_vals; i++)
{
val_list[i].ve_valuelen = 0;
ErrorCode = RegQueryValueExA (hKey,
val_list[i].ve_valuename,
NULL,
NULL,
NULL,
&val_list[i].ve_valuelen);
if (ErrorCode != ERROR_SUCCESS)
{
return ErrorCode;
}
if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
{
ErrorCode = RegQueryValueExA (hKey,
val_list[i].ve_valuename,
NULL,
&val_list[i].ve_type,
bufptr,
&val_list[i].ve_valuelen);
if (ErrorCode != ERROR_SUCCESS)
{
return ErrorCode;
}
val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
bufptr += val_list[i].ve_valuelen;
}
*ldwTotsize += val_list[i].ve_valuelen;
}
return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
}
/************************************************************************
* RegQueryMultipleValuesW
*
* @implemented
*/
LONG STDCALL
RegQueryMultipleValuesW (HKEY hKey,
PVALENTW val_list,
DWORD num_vals,
LPWSTR lpValueBuf,
LPDWORD ldwTotsize)
{
ULONG i;
DWORD maxBytes = *ldwTotsize;
LPSTR bufptr = (LPSTR)lpValueBuf;
LONG ErrorCode;
if (maxBytes >= (1024*1024))
return ERROR_TRANSFER_TOO_LONG;
*ldwTotsize = 0;
DPRINT ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
for (i = 0; i < num_vals; i++)
{
val_list[i].ve_valuelen = 0;
ErrorCode = RegQueryValueExW (hKey,
val_list[i].ve_valuename,
NULL,
NULL,
NULL,
&val_list[i].ve_valuelen);
if (ErrorCode != ERROR_SUCCESS)
{
return ErrorCode;
}
if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
{
ErrorCode = RegQueryValueExW (hKey,
val_list[i].ve_valuename,
NULL,
&val_list[i].ve_type,
bufptr,
&val_list[i].ve_valuelen);
if (ErrorCode != ERROR_SUCCESS)
{
return ErrorCode;
}
val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
bufptr += val_list[i].ve_valuelen;
}
*ldwTotsize += val_list[i].ve_valuelen;
}
return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
}
/************************************************************************
* RegQueryValueExW
*
* @implemented
*/
LONG STDCALL
RegQueryValueExW (HKEY hKey,
LPCWSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData)
{
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
UNICODE_STRING ValueName;
NTSTATUS Status;
LONG ErrorCode = ERROR_SUCCESS;
ULONG BufferSize;
ULONG ResultSize;
HANDLE KeyHandle;
ULONG MaxCopy = lpcbData != NULL && lpData != NULL ? *lpcbData : 0;
DPRINT("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (lpData != NULL && lpcbData == NULL)
{
SetLastError (ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
RtlInitUnicodeString (&ValueName,
lpValueName);
BufferSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MaxCopy;
ValueInfo = RtlAllocateHeap (ProcessHeap,
0,
BufferSize);
if (ValueInfo == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtQueryValueKey (hKey,
&ValueName,
KeyValuePartialInformation,
ValueInfo,
BufferSize,
&ResultSize);
DPRINT("Status 0x%X\n", Status);
if (Status == STATUS_BUFFER_OVERFLOW)
{
/* Return ERROR_SUCCESS and the buffer space needed for a successful call */
MaxCopy = 0;
ErrorCode = lpData ? ERROR_MORE_DATA : ERROR_SUCCESS;
}
else if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
MaxCopy = 0;
if (lpcbData != NULL)
{
ResultSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + *lpcbData;
}
}
if (lpType != NULL)
{
*lpType = ValueInfo->Type;
}
if (NT_SUCCESS(Status) && lpData != NULL)
{
RtlMoveMemory (lpData,
ValueInfo->Data,
min(ValueInfo->DataLength, MaxCopy));
}
if ((ValueInfo->Type == REG_SZ) ||
(ValueInfo->Type == REG_MULTI_SZ) ||
(ValueInfo->Type == REG_EXPAND_SZ))
{
if (lpData != NULL && MaxCopy > ValueInfo->DataLength)
{
((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
}
if (lpcbData != NULL)
{
*lpcbData = (ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]));
DPRINT("(string) Returning Size: %lu\n", *lpcbData);
}
}
else
{
if (lpcbData != NULL)
{
*lpcbData = ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
DPRINT("(other) Returning Size: %lu\n", *lpcbData);
}
}
DPRINT("Type %d Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
RtlFreeHeap (ProcessHeap,
0,
ValueInfo);
return ErrorCode;
}
/************************************************************************
* RegQueryValueExA
*
* @implemented
*/
LONG STDCALL
RegQueryValueExA (HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData)
{
UNICODE_STRING ValueName;
UNICODE_STRING ValueData;
ANSI_STRING AnsiString;
LONG ErrorCode;
DWORD Length;
DWORD Type;
if (lpData != NULL && lpcbData == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
if (lpData)
{
ValueData.Length = *lpcbData * sizeof(WCHAR);
ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
ValueData.Buffer = RtlAllocateHeap (ProcessHeap,
0,
ValueData.MaximumLength);
if (!ValueData.Buffer)
{
SetLastError(ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
}
else
{
ValueData.Buffer = NULL;
ValueData.Length = 0;
ValueData.MaximumLength = 0;
}
RtlCreateUnicodeStringFromAsciiz (&ValueName,
(LPSTR)lpValueName);
if (NULL != lpcbData)
{
Length = *lpcbData * sizeof(WCHAR);
}
ErrorCode = RegQueryValueExW (hKey,
ValueName.Buffer,
lpReserved,
&Type,
(LPBYTE)ValueData.Buffer,
NULL == lpcbData ? NULL : &Length);
DPRINT("ErrorCode %lu\n", ErrorCode);
if (ErrorCode == ERROR_SUCCESS ||
ErrorCode == ERROR_MORE_DATA)
{
if (lpType != NULL)
{
*lpType = Type;
}
if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ))
{
if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
{
RtlInitAnsiString(&AnsiString, NULL);
AnsiString.Buffer = lpData;
AnsiString.MaximumLength = *lpcbData;
ValueData.Length = Length;
ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
}
Length = Length / sizeof(WCHAR);
}
else if (lpcbData != NULL)
{
Length = min(*lpcbData, Length);
if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
{
RtlMoveMemory(lpData, ValueData.Buffer, Length);
}
}
if (lpcbData != NULL)
{
*lpcbData = Length;
}
}
if (ValueData.Buffer != NULL)
{
RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
}
return ErrorCode;
}
/************************************************************************
* RegQueryValueA
*
* @implemented
*/
LONG STDCALL
RegQueryValueA (HKEY hKey,
LPCSTR lpSubKey,
LPSTR lpValue,
PLONG lpcbValue)
{
WCHAR SubKeyNameBuffer[MAX_PATH+1];
UNICODE_STRING SubKeyName;
UNICODE_STRING Value;
ANSI_STRING AnsiString;
LONG ValueSize;
LONG ErrorCode;
if (lpValue != NULL &&
lpcbValue == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
RtlInitUnicodeString (&SubKeyName,
NULL);
RtlInitUnicodeString (&Value,
NULL);
if (lpSubKey != NULL &&
strlen(lpSubKey) != 0)
{
RtlInitAnsiString (&AnsiString,
(LPSTR)lpSubKey);
SubKeyName.Buffer = &SubKeyNameBuffer[0];
SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
RtlAnsiStringToUnicodeString (&SubKeyName,
&AnsiString,
FALSE);
}
if (lpValue != NULL)
{
ValueSize = *lpcbValue * sizeof(WCHAR);
Value.MaximumLength = ValueSize;
Value.Buffer = RtlAllocateHeap (ProcessHeap,
0,
ValueSize);
if (Value.Buffer == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
}
else
{
ValueSize = 0;
}
ErrorCode = RegQueryValueW (hKey,
(LPCWSTR)SubKeyName.Buffer,
Value.Buffer,
&ValueSize);
if (ErrorCode == ERROR_SUCCESS)
{
Value.Length = ValueSize;
RtlInitAnsiString (&AnsiString,
NULL);
AnsiString.Buffer = lpValue;
AnsiString.MaximumLength = *lpcbValue;
RtlUnicodeStringToAnsiString (&AnsiString,
&Value,
FALSE);
}
*lpcbValue = ValueSize;
if (Value.Buffer != NULL)
{
RtlFreeHeap (ProcessHeap,
0,
Value.Buffer);
}
return ErrorCode;
}
/************************************************************************
* RegQueryValueW
*
* @implemented
*/
LONG STDCALL
RegQueryValueW (HKEY hKey,
LPCWSTR lpSubKey,
LPWSTR lpValue,
PLONG lpcbValue)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyString;
HANDLE KeyHandle;
HANDLE RealKey;
LONG ErrorCode;
BOOL CloseRealKey;
NTSTATUS Status;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (lpSubKey != NULL &&
wcslen(lpSubKey) != 0)
{
RtlInitUnicodeString (&SubKeyString,
(LPWSTR)lpSubKey);
InitializeObjectAttributes (&ObjectAttributes,
&SubKeyString,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtOpenKey (&RealKey,
KEY_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
CloseRealKey = TRUE;
}
else
{
RealKey = hKey;
CloseRealKey = FALSE;
}
ErrorCode = RegQueryValueExW (RealKey,
NULL,
NULL,
NULL,
(LPBYTE)lpValue,
(LPDWORD)lpcbValue);
if (CloseRealKey)
{
NtClose (RealKey);
}
return ErrorCode;
}
/************************************************************************
* RegReplaceKeyA
*
* @implemented
*/
LONG STDCALL
RegReplaceKeyA (HKEY hKey,
LPCSTR lpSubKey,
LPCSTR lpNewFile,
LPCSTR lpOldFile)
{
UNICODE_STRING SubKey;
UNICODE_STRING NewFile;
UNICODE_STRING OldFile;
LONG ErrorCode;
RtlCreateUnicodeStringFromAsciiz (&SubKey,
(PCSZ)lpSubKey);
RtlCreateUnicodeStringFromAsciiz (&OldFile,
(PCSZ)lpOldFile);
RtlCreateUnicodeStringFromAsciiz (&NewFile,
(PCSZ)lpNewFile);
ErrorCode = RegReplaceKeyW (hKey,
SubKey.Buffer,
NewFile.Buffer,
OldFile.Buffer);
RtlFreeUnicodeString (&OldFile);
RtlFreeUnicodeString (&NewFile);
RtlFreeUnicodeString (&SubKey);
return ErrorCode;
}
/************************************************************************
* RegReplaceKeyW
*
* @unimplemented
*/
LONG STDCALL
RegReplaceKeyW (HKEY hKey,
LPCWSTR lpSubKey,
LPCWSTR lpNewFile,
LPCWSTR lpOldFile)
{
OBJECT_ATTRIBUTES KeyObjectAttributes;
OBJECT_ATTRIBUTES NewObjectAttributes;
OBJECT_ATTRIBUTES OldObjectAttributes;
UNICODE_STRING SubKeyName;
UNICODE_STRING NewFileName;
UNICODE_STRING OldFileName;
BOOLEAN CloseRealKey;
HANDLE RealKeyHandle;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
if (hKey == HKEY_PERFORMANCE_DATA)
{
return ERROR_INVALID_HANDLE;
}
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
/* Open the real key */
if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
{
RtlInitUnicodeString (&SubKeyName,
(PWSTR)lpSubKey);
InitializeObjectAttributes (&KeyObjectAttributes,
&SubKeyName,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtOpenKey (&RealKeyHandle,
KEY_ALL_ACCESS,
&KeyObjectAttributes);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
CloseRealKey = TRUE;
}
else
{
RealKeyHandle = KeyHandle;
CloseRealKey = FALSE;
}
/* Convert new file name */
if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewFile,
&NewFileName,
NULL,
NULL))
{
if (CloseRealKey)
{
NtClose (RealKeyHandle);
}
SetLastError (ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
InitializeObjectAttributes (&NewObjectAttributes,
&NewFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Convert old file name */
if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpOldFile,
&OldFileName,
NULL,
NULL))
{
RtlFreeUnicodeString (&NewFileName);
if (CloseRealKey)
{
NtClose (RealKeyHandle);
}
SetLastError (ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
InitializeObjectAttributes (&OldObjectAttributes,
&OldFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtReplaceKey (&NewObjectAttributes,
RealKeyHandle,
&OldObjectAttributes);
RtlFreeUnicodeString (&OldFileName);
RtlFreeUnicodeString (&NewFileName);
if (CloseRealKey)
{
NtClose (RealKeyHandle);
}
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegRestoreKeyA
*
* @implemented
*/
LONG STDCALL
RegRestoreKeyA (HKEY hKey,
LPCSTR lpFile,
DWORD dwFlags)
{
UNICODE_STRING FileName;
LONG ErrorCode;
RtlCreateUnicodeStringFromAsciiz (&FileName,
(PCSZ)lpFile);
ErrorCode = RegRestoreKeyW (hKey,
FileName.Buffer,
dwFlags);
RtlFreeUnicodeString (&FileName);
return ErrorCode;
}
/************************************************************************
* RegRestoreKeyW
*
* @implemented
*/
LONG STDCALL
RegRestoreKeyW (HKEY hKey,
LPCWSTR lpFile,
DWORD dwFlags)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING FileName;
HANDLE FileHandle;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
if (hKey == HKEY_PERFORMANCE_DATA)
{
return ERROR_INVALID_HANDLE;
}
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFile,
&FileName,
NULL,
NULL))
{
SetLastError (ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
InitializeObjectAttributes (&ObjectAttributes,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile (&FileHandle,
FILE_GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT);
RtlFreeUnicodeString (&FileName);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
Status = NtRestoreKey (KeyHandle,
FileHandle,
(ULONG)dwFlags);
NtClose (FileHandle);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegSaveKeyA
*
* @implemented
*/
LONG STDCALL
RegSaveKeyA (HKEY hKey,
LPCSTR lpFile,
LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
UNICODE_STRING FileName;
LONG ErrorCode;
RtlCreateUnicodeStringFromAsciiz (&FileName,
(LPSTR)lpFile);
ErrorCode = RegSaveKeyW (hKey,
FileName.Buffer,
lpSecurityAttributes);
RtlFreeUnicodeString (&FileName);
return ErrorCode;
}
/************************************************************************
* RegSaveKeyW
*
* @implemented
*/
LONG STDCALL
RegSaveKeyW (HKEY hKey,
LPCWSTR lpFile,
LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle;
HANDLE KeyHandle;
NTSTATUS Status;
LONG ErrorCode;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (!RtlDosPathNameToNtPathName_U ((PWSTR)lpFile,
&FileName,
NULL,
NULL))
{
SetLastError (ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
if (lpSecurityAttributes != NULL)
{
SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
}
InitializeObjectAttributes (&ObjectAttributes,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
SecurityDescriptor);
Status = NtCreateFile (&FileHandle,
GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_CREATE,
FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
RtlFreeUnicodeString (&FileName);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
Status = NtSaveKey (KeyHandle,
FileHandle);
NtClose (FileHandle);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegSetKeySecurity
*
* @implemented
*/
LONG STDCALL
RegSetKeySecurity (HKEY hKey,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor)
{
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
if (hKey == HKEY_PERFORMANCE_DATA)
{
SetLastError(ERROR_INVALID_HANDLE);
return ERROR_INVALID_HANDLE;
}
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
Status = NtSetSecurityObject (KeyHandle,
SecurityInformation,
pSecurityDescriptor);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegSetValueExA
*
* @implemented
*/
LONG STDCALL
RegSetValueExA (HKEY hKey,
LPCSTR lpValueName,
DWORD Reserved,
DWORD dwType,
CONST BYTE* lpData,
DWORD cbData)
{
UNICODE_STRING ValueName;
LPWSTR pValueName;
ANSI_STRING AnsiString;
UNICODE_STRING Data;
LONG ErrorCode;
LPBYTE pData;
DWORD DataSize;
if (lpValueName != NULL &&
strlen(lpValueName) != 0)
{
RtlCreateUnicodeStringFromAsciiz (&ValueName,
(PSTR)lpValueName);
pValueName = (LPWSTR)ValueName.Buffer;
}
else
{
pValueName = NULL;
}
if ((dwType == REG_SZ) ||
(dwType == REG_MULTI_SZ) ||
(dwType == REG_EXPAND_SZ))
{
RtlInitAnsiString (&AnsiString,
NULL);
AnsiString.Buffer = (PSTR)lpData;
AnsiString.Length = cbData;
AnsiString.MaximumLength = cbData;
RtlAnsiStringToUnicodeString (&Data,
&AnsiString,
TRUE);
pData = (LPBYTE)Data.Buffer;
DataSize = cbData * sizeof(WCHAR);
}
else
{
RtlInitUnicodeString (&Data,
NULL);
pData = (LPBYTE)lpData;
DataSize = cbData;
}
ErrorCode = RegSetValueExW (hKey,
pValueName,
Reserved,
dwType,
pData,
DataSize);
if (pValueName != NULL)
{
RtlFreeHeap (ProcessHeap,
0,
ValueName.Buffer);
}
if (Data.Buffer != NULL)
{
RtlFreeHeap (ProcessHeap,
0,
Data.Buffer);
}
return ErrorCode;
}
/************************************************************************
* RegSetValueExW
*
* @implemented
*/
LONG STDCALL
RegSetValueExW (HKEY hKey,
LPCWSTR lpValueName,
DWORD Reserved,
DWORD dwType,
CONST BYTE* lpData,
DWORD cbData)
{
UNICODE_STRING ValueName;
PUNICODE_STRING pValueName;
HANDLE KeyHandle;
NTSTATUS Status;
LONG ErrorCode;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (lpValueName != NULL)
{
RtlInitUnicodeString (&ValueName,
lpValueName);
}
else
{
RtlInitUnicodeString (&ValueName, L"");
}
pValueName = &ValueName;
Status = NtSetValueKey (KeyHandle,
pValueName,
0,
dwType,
(PVOID)lpData,
(ULONG)cbData);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/************************************************************************
* RegSetValueA
*
* @implemented
*/
LONG STDCALL
RegSetValueA (HKEY hKey,
LPCSTR lpSubKey,
DWORD dwType,
LPCSTR lpData,
DWORD cbData)
{
WCHAR SubKeyNameBuffer[MAX_PATH+1];
UNICODE_STRING SubKeyName;
UNICODE_STRING Data;
ANSI_STRING AnsiString;
LONG DataSize;
LONG ErrorCode;
if (lpData == NULL)
{
SetLastError (ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
RtlInitUnicodeString (&SubKeyName, NULL);
RtlInitUnicodeString (&Data, NULL);
if (lpSubKey != NULL && (strlen(lpSubKey) != 0))
{
RtlInitAnsiString (&AnsiString, (LPSTR)lpSubKey);
SubKeyName.Buffer = &SubKeyNameBuffer[0];
SubKeyName.MaximumLength = sizeof(SubKeyNameBuffer);
RtlAnsiStringToUnicodeString (&SubKeyName, &AnsiString, FALSE);
}
DataSize = cbData * sizeof(WCHAR);
Data.MaximumLength = DataSize;
Data.Buffer = RtlAllocateHeap (ProcessHeap,
0,
DataSize);
if (Data.Buffer == NULL)
{
SetLastError (ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
ErrorCode = RegSetValueW (hKey,
(LPCWSTR)SubKeyName.Buffer,
dwType,
Data.Buffer,
DataSize);
RtlFreeHeap (ProcessHeap,
0,
Data.Buffer);
return ErrorCode;
}
/************************************************************************
* RegSetValueW
*
* @implemented
*/
LONG STDCALL
RegSetValueW (HKEY hKey,
LPCWSTR lpSubKey,
DWORD dwType,
LPCWSTR lpData,
DWORD cbData)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyString;
HANDLE KeyHandle;
HANDLE RealKey;
LONG ErrorCode;
BOOL CloseRealKey;
NTSTATUS Status;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if ((lpSubKey) && (wcslen(lpSubKey) != 0))
{
RtlInitUnicodeString (&SubKeyString,
(LPWSTR)lpSubKey);
InitializeObjectAttributes (&ObjectAttributes,
&SubKeyString,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtOpenKey (&RealKey,
KEY_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
CloseRealKey = TRUE;
}
else
{
RealKey = hKey;
CloseRealKey = FALSE;
}
ErrorCode = RegSetValueExW (RealKey,
NULL,
0,
dwType,
(LPBYTE)lpData,
cbData);
if (CloseRealKey == TRUE)
{
NtClose (RealKey);
}
return ErrorCode;
}
/************************************************************************
* RegUnLoadKeyA
*
* @implemented
*/
LONG STDCALL
RegUnLoadKeyA (HKEY hKey,
LPCSTR lpSubKey)
{
UNICODE_STRING KeyName;
DWORD ErrorCode;
RtlCreateUnicodeStringFromAsciiz (&KeyName,
(LPSTR)lpSubKey);
ErrorCode = RegUnLoadKeyW (hKey,
KeyName.Buffer);
RtlFreeUnicodeString (&KeyName);
return ErrorCode;
}
/************************************************************************
* RegUnLoadKeyW
*
* @implemented
*/
LONG STDCALL
RegUnLoadKeyW (HKEY hKey,
LPCWSTR lpSubKey)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
HANDLE KeyHandle;
DWORD ErrorCode;
NTSTATUS Status;
if (hKey == HKEY_PERFORMANCE_DATA)
{
SetLastError(ERROR_INVALID_HANDLE);
return ERROR_INVALID_HANDLE;
}
Status = MapDefaultKey (&KeyHandle, hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
RtlInitUnicodeString (&KeyName,
(LPWSTR)lpSubKey);
InitializeObjectAttributes (&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtUnloadKey (&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
return ERROR_SUCCESS;
}
/* EOF */