X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Flib%2Fadvapi32%2Freg%2Freg.c;h=671221408836cf1885a651692995c0ad9f5c181e;hp=135ad0150efdfcc0187cfb090a27cd6a3c2b68bc;hb=f34a907c7abfee58303bd726baab0d4d5fcec486;hpb=3975f17012faf7c05121d842db47a56ca0f898af diff --git a/reactos/lib/advapi32/reg/reg.c b/reactos/lib/advapi32/reg/reg.c index 135ad0150ef..67122140883 100644 --- a/reactos/lib/advapi32/reg/reg.c +++ b/reactos/lib/advapi32/reg/reg.c @@ -1,4 +1,5 @@ -/* +/* $Id: reg.c,v 1.56 2004/09/13 11:41:26 ekohl Exp $ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: lib/advapi32/reg/reg.c @@ -8,653 +9,3363 @@ * Created 01/11/98 * 19990309 EA Stubs */ -#include -#include -#include + +/* INCLUDES *****************************************************************/ + +#include "advapi32.h" +#define NDEBUG +#include + +/* 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 ****************************************************************/ /************************************************************************ - * RegCloseKey + * RegInitDefaultHandles */ -LONG -STDCALL -RegCloseKey( - HKEY hKey - ) +BOOL +RegInitialize (VOID) { - if (!hKey) - return ERROR_INVALID_HANDLE; + DPRINT("RegInitialize()\n"); + + ProcessHeap = RtlGetProcessHeap(); + RtlZeroMemory (DefaultHandleTable, + MAX_DEFAULT_HANDLES * sizeof(HANDLE)); + RtlInitializeCriticalSection (&HandleTableCS); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + return TRUE; } /************************************************************************ - * RegConnectRegistryA + * RegInit */ -LONG -STDCALL -RegConnectRegistryA( - LPSTR lpMachineName, - HKEY hKey, - PHKEY phkResult - ) +BOOL +RegCleanup (VOID) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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); } /************************************************************************ - * RegCreateKeyA + * RegCloseKey + * + * @implemented */ -LONG -STDCALL -RegCreateKeyA( - HKEY hKey, - LPCSTR lpSubKey, - PHKEY phkResult - ) +LONG STDCALL +RegCloseKey (HKEY hKey) { - return RegCreateKeyExA(hKey, - lpSubKey, - 0, - NULL, - 0, - MAXIMUM_ALLOWED, - NULL, - phkResult, - NULL); + 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; } /************************************************************************ - * RegCreateKeyW + * RegConnectRegistryA + * + * @unimplemented */ -LONG -STDCALL -RegCreateKeyW( - HKEY hKey, - LPCWSTR lpSubKey, - PHKEY phkResult - ) +LONG STDCALL +RegConnectRegistryA (LPCSTR lpMachineName, + HKEY hKey, + PHKEY phkResult) { - return RegCreateKeyExW(hKey, - lpSubKey, - 0, - NULL, - 0, - MAXIMUM_ALLOWED, - NULL, - phkResult, - NULL); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return ERROR_CALL_NOT_IMPLEMENTED; } /************************************************************************ - * RegCreateKeyExA + * RegConnectRegistryW + * + * @unimplemented */ -LONG -STDCALL -RegCreateKeyExA( - HKEY hKey, - LPCSTR lpSubKey, - DWORD Reserved, - LPSTR lpClass, - DWORD dwOptions, - REGSAM samDesired, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - PHKEY phkResult, - LPDWORD lpdwDisposition - ) +LONG STDCALL +RegConnectRegistryW (LPCWSTR lpMachineName, + HKEY hKey, + PHKEY phkResult) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return ERROR_CALL_NOT_IMPLEMENTED; } /************************************************************************ - * RegCreateKeyExW + * CreateNestedKey + * + * Create key and all necessary intermediate keys */ -LONG -STDCALL -RegCreateKeyExW( - HKEY hKey, - LPCWSTR lpSubKey, - DWORD Reserved, - LPWSTR lpClass, - DWORD dwOptions, - REGSAM samDesired, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - PHKEY phkResult, - LPDWORD lpdwDisposition - ) +static NTSTATUS +CreateNestedKey(PHKEY KeyHandle, + POBJECT_ATTRIBUTES ObjectAttributes, + PUNICODE_STRING ClassString, + DWORD dwOptions, + REGSAM samDesired, + DWORD *lpdwDisposition) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegDeleteKeyA + * RegCreateKeyExA + * + * @implemented */ -LONG -STDCALL -RegDeleteKeyA( - HKEY hKey, - LPCSTR lpSubKey - ) +LONG STDCALL +RegCreateKeyExA (HKEY hKey, + LPCSTR lpSubKey, + DWORD Reserved, + LPSTR lpClass, + DWORD dwOptions, + REGSAM samDesired, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + PHKEY phkResult, + LPDWORD lpdwDisposition) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegDeleteKeyW + * RegCreateKeyExW + * + * @implemented */ -LONG -STDCALL -RegDeleteKeyW( - HKEY hKey, - LPCWSTR lpSubKey - ) +LONG STDCALL +RegCreateKeyExW (HKEY hKey, + LPCWSTR lpSubKey, + DWORD Reserved, + LPWSTR lpClass, + DWORD dwOptions, + REGSAM samDesired, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + PHKEY phkResult, + LPDWORD lpdwDisposition) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegDeleteValueA + * RegCreateKeyA + * + * @implemented */ -LONG -STDCALL -RegDeleteValueA( - HKEY hKey, - LPCSTR lpValueName - ) +LONG STDCALL +RegCreateKeyA (HKEY hKey, + LPCSTR lpSubKey, + PHKEY phkResult) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + return RegCreateKeyExA (hKey, + lpSubKey, + 0, + NULL, + 0, + KEY_ALL_ACCESS, + NULL, + phkResult, + NULL); } /************************************************************************ - * RegEnumKeyA + * RegCreateKeyW + * + * @implemented */ -LONG -STDCALL -RegEnumKeyA( - HKEY hKey, - DWORD dwIndex, - LPSTR lpName, - DWORD cbName - ) +LONG STDCALL +RegCreateKeyW (HKEY hKey, + LPCWSTR lpSubKey, + PHKEY phkResult) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + return RegCreateKeyExW (hKey, + lpSubKey, + 0, + NULL, + 0, + KEY_ALL_ACCESS, + NULL, + phkResult, + NULL); } /************************************************************************ - * RegEnumKeyExA + * RegDeleteKeyA + * + * @implemented */ -LONG -STDCALL -RegEnumKeyExA( - HKEY hKey, - DWORD dwIndex, - LPSTR lpName, - LPDWORD lpcbName, - LPDWORD lpReserved, - LPSTR lpClass, - LPDWORD lpcbClass, - PFILETIME lpftLastWriteTime - ) +LONG STDCALL +RegDeleteKeyA (HKEY hKey, + LPCSTR lpSubKey) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegEnumValueA + * RegDeleteKeyW + * + * @implemented */ -LONG -STDCALL -RegEnumValueA( - HKEY hKey, - DWORD dwIndex, - LPSTR lpValueName, - LPDWORD lpcbValueName, - LPDWORD lpReserved, - LPDWORD lpType, - LPBYTE lpData, - LPDWORD lpcbData - ) +LONG STDCALL +RegDeleteKeyW (HKEY hKey, + LPCWSTR lpSubKey) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegFlushKey + * RegDeleteValueA + * + * @implemented */ -LONG -STDCALL -RegFlushKey( - HKEY hKey - ) +LONG STDCALL +RegDeleteValueA (HKEY hKey, + LPCSTR lpValueName) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegGetKeySecurity + * RegDeleteValueW + * + * @implemented */ -#if 0 -LONG -STDCALL -RegGetKeySecurity ( - HKEY hKey, - SECURITY_INFORMATION SecurityInformation, /* FIXME: ULONG ? */ - PSECURITY_DESCRIPTOR pSecurityDescriptor, - LPDWORD lpcbSecurityDescriptor - ) -{ - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_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; } -#endif /************************************************************************ - * RegLoadKeyA + * RegEnumKeyA + * + * @implemented */ -LONG -STDCALL -RegLoadKey( - HKEY hKey, - LPCSTR lpSubKey, - LPCSTR lpFile - ) +LONG STDCALL +RegEnumKeyA (HKEY hKey, + DWORD dwIndex, + LPSTR lpName, + DWORD cbName) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + DWORD dwLength; + + dwLength = cbName; + return RegEnumKeyExA (hKey, + dwIndex, + lpName, + &dwLength, + NULL, + NULL, + NULL, + NULL); } /************************************************************************ - * RegLoadKeyW + * RegEnumKeyW + * + * @implemented */ -LONG -STDCALL -RegLoadKeyW( - HKEY hKey, - LPCWSTR lpSubKey, - LPCWSTR lpFile - ) +LONG STDCALL +RegEnumKeyW (HKEY hKey, + DWORD dwIndex, + LPWSTR lpName, + DWORD cbName) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + DWORD dwLength; + + dwLength = cbName; + return RegEnumKeyExW (hKey, + dwIndex, + lpName, + &dwLength, + NULL, + NULL, + NULL, + NULL); } /************************************************************************ - * RegNotifyChangeKeyValue + * RegEnumKeyExA + * + * @implemented */ -LONG -STDCALL -RegNotifyChangeKeyValue( - HKEY hKey, - BOOL bWatchSubtree, - DWORD dwNotifyFilter, - HANDLE hEvent, - BOOL fAsynchronous - ) +LONG STDCALL +RegEnumKeyExA (HKEY hKey, + DWORD dwIndex, + LPSTR lpName, + LPDWORD lpcbName, + LPDWORD lpReserved, + LPSTR lpClass, + LPDWORD lpcbClass, + PFILETIME lpftLastWriteTime) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; + } + *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; +} + /************************************************************************ - * RegOpenKeyA + * RegLoadKeyA + * + * @implemented */ -LONG -STDCALL -RegOpenKeyA( - HKEY hKey, - LPCSTR lpSubKey, - PHKEY phkResult - ) +LONG STDCALL +RegLoadKeyA (HKEY hKey, + LPCSTR lpSubKey, + LPCSTR lpFile) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegOpenKeyW + * RegLoadKeyW * - * 19981101 Ariadne - * 19990525 EA + * @implemented */ -LONG -STDCALL -RegOpenKeyW ( - HKEY hKey, - LPCWSTR lpSubKey, - PHKEY phkResult - ) +LONG STDCALL +RegLoadKeyW (HKEY hKey, + LPCWSTR lpSubKey, + LPCWSTR lpFile) { - NTSTATUS errCode; - UNICODE_STRING SubKeyString; - OBJECT_ATTRIBUTES ObjectAttributes; + 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; +} - SubKeyString.Buffer = (LPWSTR)lpSubKey; - SubKeyString.Length = wcslen(lpSubKey); - SubKeyString.MaximumLength = SubKeyString.Length; - ObjectAttributes.RootDirectory = hKey; - ObjectAttributes.ObjectName = & SubKeyString; - ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE; - errCode = NtOpenKey( - phkResult, - GENERIC_ALL, - & ObjectAttributes - ); - if ( !NT_SUCCESS(errCode) ) +/************************************************************************ + * 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) + { + /* FIXME */ + *lpcbSecurityDescriptor = 0; + } + + 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 + * + * @unimplemented + */ +LONG STDCALL +RegQueryMultipleValuesA (HKEY hKey, + PVALENTA val_list, + DWORD num_vals, + LPSTR lpValueBuf, + LPDWORD ldwTotsize) +{ + UNIMPLEMENTED; + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/************************************************************************ + * 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 = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 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_TOO_SMALL) + { + /* 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) { - LONG LastError = RtlNtStatusToDosError(errCode); - - SetLastError(LastError); - return LastError; + ResultSize = sizeof(*ValueInfo) + *lpcbData; } - return ERROR_SUCCESS; + } + + 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 - sizeof(*ValueInfo)); + DPRINT("(string) Returning Size: %lu\n", *lpcbData); + } + } + else + { + if (lpcbData != NULL) + { + *lpcbData = ResultSize - sizeof(*ValueInfo); + DPRINT("(other) Returning Size: %lu\n", *lpcbData); + } + } + + DPRINT("Type %d Size %d\n", ValueInfo->Type, ValueInfo->DataLength); + + RtlFreeHeap (ProcessHeap, + 0, + ValueInfo); + + return ErrorCode; } /************************************************************************ - * RegOpenKeyExA + * RegQueryValueExA + * + * @implemented */ -LONG -STDCALL -RegOpenKeyExA( - HKEY hKey, - LPCSTR lpSubKey, - DWORD ulOptions, - REGSAM samDesired, - PHKEY phkResult - ) +LONG STDCALL +RegQueryValueExA (HKEY hKey, + LPCSTR lpValueName, + LPDWORD lpReserved, + LPDWORD lpType, + LPBYTE lpData, + LPDWORD lpcbData) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegOpenKeyExW + * RegQueryValueA + * + * @implemented */ -LONG -STDCALL -RegOpenKeyExW( - HKEY hKey, - LPCWSTR lpSubKey, - DWORD ulOptions, - REGSAM samDesired, - PHKEY phkResult - ) +LONG STDCALL +RegQueryValueA (HKEY hKey, + LPCSTR lpSubKey, + LPSTR lpValue, + PLONG lpcbValue) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegQueryInfoKeyA + * RegQueryValueW + * + * @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 - ) +LONG STDCALL +RegQueryValueW (HKEY hKey, + LPCWSTR lpSubKey, + LPWSTR lpValue, + PLONG lpcbValue) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegQueryInfoKeyW + * RegReplaceKeyA + * + * @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 - ) +LONG STDCALL +RegReplaceKeyA (HKEY hKey, + LPCSTR lpSubKey, + LPCSTR lpNewFile, + LPCSTR lpOldFile) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegQueryMultipleValuesA + * RegReplaceKeyW + * + * @unimplemented */ -LONG -STDCALL -RegQueryMultipleValuesA( - HKEY hKey, - PVALENT val_list, - DWORD num_vals, - LPSTR lpValueBuf, - LPDWORD ldwTotsize - ) +LONG STDCALL +RegReplaceKeyW (HKEY hKey, + LPCWSTR lpSubKey, + LPCWSTR lpNewFile, + LPCWSTR lpOldFile) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegQueryValueA + * RegRestoreKeyA + * + * @implemented */ -LONG -STDCALL -RegQueryValueA( - HKEY hKey, - LPCSTR lpSubKey, - LPSTR lpValue, - PLONG lpcbValue - ) +LONG STDCALL +RegRestoreKeyA (HKEY hKey, + LPCSTR lpFile, + DWORD dwFlags) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + UNICODE_STRING FileName; + LONG ErrorCode; + + RtlCreateUnicodeStringFromAsciiz (&FileName, + (PCSZ)lpFile); + + ErrorCode = RegRestoreKeyW (hKey, + FileName.Buffer, + dwFlags); + + RtlFreeUnicodeString (&FileName); + + return ErrorCode; } /************************************************************************ - * RegQueryValueExA + * RegRestoreKeyW + * + * @implemented */ -LONG -STDCALL -RegQueryValueExA( - HKEY hKey, - LPSTR lpValueName, - LPDWORD lpReserved, - LPDWORD lpType, - LPBYTE lpData, - LPDWORD lpcbData - ) +LONG STDCALL +RegRestoreKeyW (HKEY hKey, + LPCWSTR lpFile, + DWORD dwFlags) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegQueryValueExW + * RegSaveKeyA + * + * @implemented */ -LONG -STDCALL -RegQueryValueExW( - HKEY hKey, - LPWSTR lpValueName, - LPDWORD lpReserved, - LPDWORD lpType, - LPBYTE lpData, - LPDWORD lpcbData - ) +LONG STDCALL +RegSaveKeyA (HKEY hKey, + LPCSTR lpFile, + LPSECURITY_ATTRIBUTES lpSecurityAttributes) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + UNICODE_STRING FileName; + LONG ErrorCode; + + RtlCreateUnicodeStringFromAsciiz (&FileName, + (LPSTR)lpFile); + ErrorCode = RegSaveKeyW (hKey, + FileName.Buffer, + lpSecurityAttributes); + RtlFreeUnicodeString (&FileName); + + return ErrorCode; } /************************************************************************ - * RegReplaceKeyA + * RegSaveKeyW + * + * @implemented */ -LONG -STDCALL -RegReplaceKeyA( - HKEY hKey, - LPCSTR lpSubKey, - LPCSTR lpNewFile, - LPCSTR lpOldFile - ) +LONG STDCALL +RegSaveKeyW (HKEY hKey, + LPCWSTR lpFile, + LPSECURITY_ATTRIBUTES lpSecurityAttributes) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegRestoreKeyA + * RegSetKeySecurity + * + * @implemented */ -LONG -STDCALL -RegRestoreKeyA( - HKEY hKey, - LPCSTR lpFile, - DWORD dwFlags - ) +LONG STDCALL +RegSetKeySecurity (HKEY hKey, + SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegSaveKeyA + * RegSetValueExA + * + * @implemented */ -LONG -STDCALL -RegSaveKeyA( - HKEY hKey, - LPCSTR lpFile, - LPSECURITY_ATTRIBUTES lpSecurityAttributes - ) +LONG STDCALL +RegSetValueExA (HKEY hKey, + LPCSTR lpValueName, + DWORD Reserved, + DWORD dwType, + CONST BYTE* lpData, + DWORD cbData) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + UNICODE_STRING ValueName; + LPWSTR pValueName; + ANSI_STRING AnsiString; + UNICODE_STRING Data; + LONG ErrorCode; + LPBYTE pData; + DWORD DataSize; + + if (lpData == NULL) + { + SetLastError (ERROR_INVALID_PARAMETER); + return ERROR_INVALID_PARAMETER; + } + + 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; } /************************************************************************ - * RegSetKeySecurity + * RegSetValueExW + * + * @implemented */ -#if 0 -LONG -STDCALL -RegSetKeySecurity( - HKEY hKey, - SECURITY_INFORMATION SecurityInformation, /* FIXME: ULONG? */ - PSECURITY_DESCRIPTOR pSecurityDescriptor - ) +LONG STDCALL +RegSetValueExW (HKEY hKey, + LPCWSTR lpValueName, + DWORD Reserved, + DWORD dwType, + CONST BYTE* lpData, + DWORD cbData) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } -#endif + /************************************************************************ - * RegSetValueA + * RegSetValueA + * + * @implemented */ -LONG -STDCALL -RegSetValueA( - HKEY hKey, - LPCSTR lpSubKey, - DWORD dwType, - LPCSTR lpData, - DWORD cbData - ) +LONG STDCALL +RegSetValueA (HKEY hKey, + LPCSTR lpSubKey, + DWORD dwType, + LPCSTR lpData, + DWORD cbData) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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; } /************************************************************************ - * RegSetValueExA + * RegSetValueW + * + * @implemented */ -LONG -STDCALL -RegSetValueExA( - HKEY hKey, - LPCSTR lpValueName, - DWORD Reserved, - DWORD dwType, - CONST BYTE *lpData, - DWORD cbData - ) +LONG STDCALL +RegSetValueW (HKEY hKey, + LPCWSTR lpSubKey, + DWORD dwType, + LPCWSTR lpData, + DWORD cbData) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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 + * RegUnLoadKeyA + * + * @implemented */ -LONG -STDCALL -RegUnLoadKeyA( - HKEY hKey, - LPCSTR lpSubKey - ) +LONG STDCALL +RegUnLoadKeyA (HKEY hKey, + LPCSTR lpSubKey) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return ERROR_CALL_NOT_IMPLEMENTED; + 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 */