2005-01-03 23:02:15 +00:00
|
|
|
/* $Id$
|
2000-09-05 23:03:09 +00:00
|
|
|
*
|
1998-12-04 18:28:13 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS system libraries
|
1999-03-12 06:29:00 +00:00
|
|
|
* FILE: lib/advapi32/reg/reg.c
|
1998-12-04 18:28:13 +00:00
|
|
|
* PURPOSE: Registry functions
|
|
|
|
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
|
2005-09-26 12:44:03 +00:00
|
|
|
* Thomas Weidenmueller <w3seek@reactos.com>
|
1998-12-04 18:28:13 +00:00
|
|
|
* UPDATE HISTORY:
|
|
|
|
* Created 01/11/98
|
1999-03-12 06:29:00 +00:00
|
|
|
* 19990309 EA Stubs
|
2005-05-04 15:53:54 +00:00
|
|
|
* 20050502 Fireball imported some stuff from WINE
|
1998-12-04 18:28:13 +00:00
|
|
|
*/
|
2003-03-24 13:44:15 +00:00
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
2002-12-08 16:14:28 +00:00
|
|
|
|
2005-08-05 10:31:28 +00:00
|
|
|
#include <advapi32.h>
|
2005-12-29 22:43:36 +00:00
|
|
|
#define NDEBUG
|
2005-08-16 05:17:06 +00:00
|
|
|
#include <wine/debug.h>
|
2002-11-10 13:44:48 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
/* DEFINES ******************************************************************/
|
2000-09-05 23:03:09 +00:00
|
|
|
|
2001-07-01 17:54:07 +00:00
|
|
|
#define MAX_DEFAULT_HANDLES 6
|
2003-08-30 14:46:29 +00:00
|
|
|
#define REG_MAX_NAME_SIZE 256
|
2004-09-13 08:51:40 +00:00
|
|
|
#define REG_MAX_DATA_SIZE 2048
|
2003-08-30 14:46:29 +00:00
|
|
|
|
|
|
|
/* GLOBALS ******************************************************************/
|
2000-09-05 23:03:09 +00:00
|
|
|
|
2005-01-03 23:02:15 +00:00
|
|
|
static RTL_CRITICAL_SECTION HandleTableCS;
|
2000-09-05 23:03:09 +00:00
|
|
|
static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
|
2003-08-30 14:46:29 +00:00
|
|
|
static HANDLE ProcessHeap;
|
2005-08-26 09:40:37 +00:00
|
|
|
static BOOLEAN DefaultHandlesDisabled = FALSE;
|
2000-09-05 23:03:09 +00:00
|
|
|
|
2003-03-24 13:44:15 +00:00
|
|
|
/* PROTOTYPES ***************************************************************/
|
2000-09-05 23:03:09 +00:00
|
|
|
|
2004-06-17 09:07:12 +00:00
|
|
|
static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
|
2000-09-06 19:59:54 +00:00
|
|
|
static VOID CloseDefaultKeys(VOID);
|
2005-09-26 18:05:57 +00:00
|
|
|
#define ClosePredefKey(Handle) \
|
2005-08-26 09:40:37 +00:00
|
|
|
if ((ULONG_PTR)Handle & 0x1) { \
|
|
|
|
NtClose(Handle); \
|
|
|
|
}
|
2005-09-26 18:05:57 +00:00
|
|
|
#define IsPredefKey(HKey) \
|
|
|
|
(((ULONG)(HKey) & 0xF0000000) == 0x80000000)
|
|
|
|
#define GetPredefKeyIndex(HKey) \
|
|
|
|
((ULONG)(HKey) & 0x0FFFFFFF)
|
2000-09-05 23:03:09 +00:00
|
|
|
|
2001-07-01 17:54:07 +00:00
|
|
|
static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
|
2000-09-05 23:03:09 +00:00
|
|
|
static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
|
2001-07-01 17:54:07 +00:00
|
|
|
static NTSTATUS OpenUsersKey (PHANDLE KeyHandle);
|
|
|
|
static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
|
2000-09-05 23:03:09 +00:00
|
|
|
|
|
|
|
|
2003-03-24 13:44:15 +00:00
|
|
|
/* FUNCTIONS ****************************************************************/
|
2005-05-04 15:53:54 +00:00
|
|
|
/* check if value type needs string conversion (Ansi<->Unicode) */
|
2005-11-28 23:35:35 +00:00
|
|
|
__inline static int is_string( DWORD type )
|
2005-05-04 15:53:54 +00:00
|
|
|
{
|
|
|
|
return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
|
|
|
|
}
|
2001-09-01 15:36:45 +00:00
|
|
|
|
2000-09-05 23:03:09 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegInitDefaultHandles
|
2000-09-05 23:03:09 +00:00
|
|
|
*/
|
|
|
|
BOOL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegInitialize (VOID)
|
2000-09-05 23:03:09 +00:00
|
|
|
{
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegInitialize()\n");
|
2000-09-05 23:03:09 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
ProcessHeap = RtlGetProcessHeap();
|
2003-07-12 00:03:42 +00:00
|
|
|
RtlZeroMemory (DefaultHandleTable,
|
|
|
|
MAX_DEFAULT_HANDLES * sizeof(HANDLE));
|
|
|
|
RtlInitializeCriticalSection (&HandleTableCS);
|
|
|
|
|
2003-03-24 13:44:15 +00:00
|
|
|
return TRUE;
|
2000-09-05 23:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegInit
|
2000-09-05 23:03:09 +00:00
|
|
|
*/
|
|
|
|
BOOL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegCleanup (VOID)
|
2000-09-05 23:03:09 +00:00
|
|
|
{
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegCleanup()\n");
|
2000-09-05 23:03:09 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
CloseDefaultKeys ();
|
|
|
|
RtlDeleteCriticalSection (&HandleTableCS);
|
|
|
|
|
|
|
|
return TRUE;
|
2000-09-05 23:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-26 12:44:03 +00:00
|
|
|
static NTSTATUS
|
|
|
|
OpenPredefinedKey(IN ULONG Index,
|
|
|
|
OUT HANDLE Handle)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
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:
|
|
|
|
WARN("MapDefaultHandle() no handle creator\n");
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-05 23:03:09 +00:00
|
|
|
static NTSTATUS
|
2005-08-26 09:40:37 +00:00
|
|
|
MapDefaultKey (OUT PHANDLE RealKey,
|
|
|
|
IN HKEY Key)
|
2000-09-05 23:03:09 +00:00
|
|
|
{
|
2003-03-24 13:44:15 +00:00
|
|
|
PHANDLE Handle;
|
|
|
|
ULONG Index;
|
2005-08-26 09:40:37 +00:00
|
|
|
BOOLEAN DoOpen;
|
2003-03-24 13:44:15 +00:00
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("MapDefaultKey (Key %x)\n", Key);
|
2003-03-24 13:44:15 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
if (!IsPredefKey(Key))
|
2003-03-24 13:44:15 +00:00
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
*RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
|
2003-07-12 00:03:42 +00:00
|
|
|
return STATUS_SUCCESS;
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle special cases here */
|
2005-09-26 18:05:57 +00:00
|
|
|
Index = GetPredefKeyIndex(Key);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (Index >= MAX_DEFAULT_HANDLES)
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
2003-03-24 13:44:15 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
RtlEnterCriticalSection (&HandleTableCS);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
if (!DefaultHandlesDisabled)
|
|
|
|
{
|
|
|
|
Handle = &DefaultHandleTable[Index];
|
|
|
|
DoOpen = (*Handle == NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Handle = RealKey;
|
|
|
|
DoOpen = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DoOpen)
|
2003-03-24 13:44:15 +00:00
|
|
|
{
|
|
|
|
/* create/open the default handle */
|
2005-09-26 12:44:03 +00:00
|
|
|
Status = OpenPredefinedKey(Index,
|
|
|
|
Handle);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
if (!DefaultHandlesDisabled)
|
|
|
|
*RealKey = *Handle;
|
|
|
|
else
|
|
|
|
*(PULONG_PTR)Handle |= 0x1;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlLeaveCriticalSection (&HandleTableCS);
|
2003-03-24 13:44:15 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
return Status;
|
2000-09-05 23:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-07-01 17:54:07 +00:00
|
|
|
static VOID
|
2003-07-12 00:03:42 +00:00
|
|
|
CloseDefaultKeys (VOID)
|
2000-09-05 23:03:09 +00:00
|
|
|
{
|
2003-03-24 13:44:15 +00:00
|
|
|
ULONG i;
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
RtlEnterCriticalSection (&HandleTableCS);
|
2003-03-24 13:44:15 +00:00
|
|
|
for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
|
|
|
|
{
|
|
|
|
if (DefaultHandleTable[i] != NULL)
|
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
NtClose (DefaultHandleTable[i]);
|
2003-03-24 13:44:15 +00:00
|
|
|
DefaultHandleTable[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
RtlLeaveCriticalSection (&HandleTableCS);
|
2000-09-05 23:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static NTSTATUS
|
2003-07-12 00:03:42 +00:00
|
|
|
OpenClassesRootKey (PHANDLE KeyHandle)
|
2000-09-05 23:03:09 +00:00
|
|
|
{
|
2001-07-01 17:54:07 +00:00
|
|
|
OBJECT_ATTRIBUTES Attributes;
|
2005-06-20 18:58:56 +00:00
|
|
|
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
|
2000-09-05 23:03:09 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("OpenClassesRootKey()\n");
|
2000-09-05 23:03:09 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
InitializeObjectAttributes (&Attributes,
|
|
|
|
&KeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
return NtOpenKey (KeyHandle,
|
2003-08-30 14:46:29 +00:00
|
|
|
MAXIMUM_ALLOWED,
|
2003-07-12 00:03:42 +00:00
|
|
|
&Attributes);
|
2000-09-05 23:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-07-01 17:54:07 +00:00
|
|
|
static NTSTATUS
|
2003-07-12 00:03:42 +00:00
|
|
|
OpenLocalMachineKey (PHANDLE KeyHandle)
|
2001-07-01 17:54:07 +00:00
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES Attributes;
|
2005-06-20 18:58:56 +00:00
|
|
|
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
|
2003-12-28 08:47:28 +00:00
|
|
|
NTSTATUS Status;
|
2001-07-01 17:54:07 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("OpenLocalMachineKey()\n");
|
2001-07-01 17:54:07 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
InitializeObjectAttributes (&Attributes,
|
|
|
|
&KeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2003-12-28 08:47:28 +00:00
|
|
|
Status = NtOpenKey (KeyHandle,
|
|
|
|
MAXIMUM_ALLOWED,
|
|
|
|
&Attributes);
|
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
|
2003-12-28 08:47:28 +00:00
|
|
|
return Status;
|
2001-07-01 17:54:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static NTSTATUS
|
2003-07-12 00:03:42 +00:00
|
|
|
OpenUsersKey (PHANDLE KeyHandle)
|
2001-07-01 17:54:07 +00:00
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES Attributes;
|
2005-06-20 18:58:56 +00:00
|
|
|
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User");
|
2001-07-01 17:54:07 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("OpenUsersKey()\n");
|
2001-07-01 17:54:07 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
InitializeObjectAttributes (&Attributes,
|
|
|
|
&KeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
return NtOpenKey (KeyHandle,
|
2005-03-19 19:13:01 +00:00
|
|
|
MAXIMUM_ALLOWED,
|
2003-07-12 00:03:42 +00:00
|
|
|
&Attributes);
|
2001-07-01 17:54:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static NTSTATUS
|
2003-07-12 00:03:42 +00:00
|
|
|
OpenCurrentConfigKey (PHANDLE KeyHandle)
|
2001-07-01 17:54:07 +00:00
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES Attributes;
|
2002-08-20 20:37:19 +00:00
|
|
|
UNICODE_STRING KeyName =
|
2005-06-20 18:58:56 +00:00
|
|
|
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
|
2001-07-01 17:54:07 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("OpenCurrentConfigKey()\n");
|
2001-07-01 17:54:07 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
InitializeObjectAttributes (&Attributes,
|
|
|
|
&KeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
return NtOpenKey (KeyHandle,
|
2003-08-30 14:46:29 +00:00
|
|
|
MAXIMUM_ALLOWED,
|
2003-07-12 00:03:42 +00:00
|
|
|
&Attributes);
|
2001-07-01 17:54:07 +00:00
|
|
|
}
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
/************************************************************************
|
|
|
|
* RegDisablePredefinedCacheEx
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegDisablePredefinedCacheEx(VOID)
|
|
|
|
{
|
|
|
|
RtlEnterCriticalSection (&HandleTableCS);
|
|
|
|
DefaultHandlesDisabled = TRUE;
|
|
|
|
RtlLeaveCriticalSection (&HandleTableCS);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-26 12:44:03 +00:00
|
|
|
/************************************************************************
|
|
|
|
* RegOverridePredefKey
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegOverridePredefKey(IN HKEY hKey,
|
|
|
|
IN HKEY hNewHKey OPTIONAL)
|
|
|
|
{
|
|
|
|
LONG ErrorCode = ERROR_SUCCESS;
|
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
if ((hKey == HKEY_CLASSES_ROOT ||
|
|
|
|
hKey == HKEY_CURRENT_CONFIG ||
|
|
|
|
hKey == HKEY_CURRENT_USER ||
|
|
|
|
hKey == HKEY_LOCAL_MACHINE ||
|
|
|
|
hKey == HKEY_PERFORMANCE_DATA ||
|
|
|
|
hKey == HKEY_USERS) &&
|
|
|
|
!IsPredefKey(hNewHKey))
|
2005-09-26 12:44:03 +00:00
|
|
|
{
|
|
|
|
PHANDLE Handle;
|
|
|
|
ULONG Index;
|
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
Index = GetPredefKeyIndex(hKey);
|
2005-09-26 12:44:03 +00:00
|
|
|
Handle = &DefaultHandleTable[Index];
|
|
|
|
|
|
|
|
if (hNewHKey == NULL)
|
|
|
|
{
|
|
|
|
/* restore the default mapping */
|
|
|
|
NTSTATUS Status = OpenPredefinedKey(Index,
|
|
|
|
&hNewHKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return RtlNtStatusToDosError(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(hNewHKey != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlEnterCriticalSection (&HandleTableCS);
|
|
|
|
|
|
|
|
/* close the currently mapped handle if existing */
|
|
|
|
if (*Handle != NULL)
|
|
|
|
{
|
|
|
|
NtClose(*Handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update the mapping */
|
|
|
|
*Handle = hNewHKey;
|
|
|
|
|
|
|
|
RtlLeaveCriticalSection (&HandleTableCS);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ErrorCode = ERROR_INVALID_HANDLE;
|
|
|
|
|
|
|
|
return ErrorCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegCloseKey
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2001-07-01 17:54:07 +00:00
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegCloseKey (HKEY hKey)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2001-07-01 17:54:07 +00:00
|
|
|
NTSTATUS Status;
|
2000-09-06 19:59:54 +00:00
|
|
|
|
2001-07-01 17:54:07 +00:00
|
|
|
/* don't close null handle or a pseudo handle */
|
|
|
|
if ((!hKey) || (((ULONG)hKey & 0xF0000000) == 0x80000000))
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
|
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
}
|
2003-03-24 13:44:15 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = NtClose (hKey);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-24 17:08:13 +00:00
|
|
|
static NTSTATUS
|
|
|
|
RegpCopyTree(IN HKEY hKeySrc,
|
|
|
|
IN HKEY hKeyDest)
|
|
|
|
{
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
LIST_ENTRY ListEntry;
|
|
|
|
HANDLE hKeySrc;
|
|
|
|
HANDLE hKeyDest;
|
|
|
|
} REGP_COPY_KEYS, *PREGP_COPY_KEYS;
|
|
|
|
|
|
|
|
LIST_ENTRY copyQueueHead;
|
|
|
|
PREGP_COPY_KEYS copyKeys, newCopyKeys;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
KEY_VALUE_FULL_INFORMATION *KeyValue;
|
|
|
|
KEY_NODE_INFORMATION *KeyNode;
|
|
|
|
PVOID Buffer;
|
|
|
|
} Info;
|
|
|
|
ULONG Index, BufferSizeRequired, BufferSize = 0x200;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
NTSTATUS Status2 = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
InitializeListHead(©QueueHead);
|
|
|
|
|
|
|
|
Info.Buffer = RtlAllocateHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
BufferSize);
|
|
|
|
if (Info.Buffer == NULL)
|
|
|
|
{
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
copyKeys = RtlAllocateHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
sizeof(REGP_COPY_KEYS));
|
|
|
|
if (copyKeys != NULL)
|
|
|
|
{
|
|
|
|
copyKeys->hKeySrc = hKeySrc;
|
|
|
|
copyKeys->hKeyDest = hKeyDest;
|
|
|
|
InsertHeadList(©QueueHead,
|
|
|
|
©Keys->ListEntry);
|
|
|
|
|
|
|
|
/* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
copyKeys = CONTAINING_RECORD(copyQueueHead.Flink,
|
|
|
|
REGP_COPY_KEYS,
|
|
|
|
ListEntry);
|
|
|
|
|
|
|
|
/* enumerate all values and copy them */
|
|
|
|
Index = 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
Status2 = NtEnumerateValueKey(copyKeys->hKeySrc,
|
|
|
|
Index,
|
|
|
|
KeyValueFullInformation,
|
|
|
|
Info.KeyValue,
|
|
|
|
BufferSize,
|
|
|
|
&BufferSizeRequired);
|
|
|
|
if (NT_SUCCESS(Status2))
|
|
|
|
{
|
|
|
|
UNICODE_STRING ValueName;
|
|
|
|
PVOID Data;
|
|
|
|
|
|
|
|
/* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
|
|
|
|
ValueName.Length = Info.KeyValue->NameLength;
|
|
|
|
ValueName.MaximumLength = ValueName.Length;
|
|
|
|
ValueName.Buffer = Info.KeyValue->Name;
|
|
|
|
|
|
|
|
Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset);
|
|
|
|
|
|
|
|
Status2 = NtSetValueKey(copyKeys->hKeyDest,
|
|
|
|
&ValueName,
|
|
|
|
Info.KeyValue->TitleIndex,
|
|
|
|
Info.KeyValue->Type,
|
|
|
|
Data,
|
|
|
|
Info.KeyValue->DataLength);
|
|
|
|
|
|
|
|
/* don't break, let's try to copy as many values as possible */
|
|
|
|
if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Status = Status2;
|
|
|
|
}
|
|
|
|
|
|
|
|
Index++;
|
|
|
|
}
|
|
|
|
else if (Status2 == STATUS_BUFFER_OVERFLOW)
|
|
|
|
{
|
|
|
|
PVOID Buffer;
|
|
|
|
|
|
|
|
ASSERT(BufferSize < BufferSizeRequired);
|
|
|
|
|
|
|
|
Buffer = RtlReAllocateHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
Info.Buffer,
|
|
|
|
BufferSizeRequired);
|
|
|
|
if (Buffer != NULL)
|
|
|
|
{
|
|
|
|
Info.Buffer = Buffer;
|
|
|
|
/* try again */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* don't break, let's try to copy as many values as possible */
|
|
|
|
Status2 = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
Index++;
|
|
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Status = Status2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* break to avoid an infinite loop in case of denied access or
|
|
|
|
other errors! */
|
|
|
|
if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Status = Status2;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* enumerate all subkeys and open and enqueue them */
|
|
|
|
Index = 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
Status2 = NtEnumerateKey(copyKeys->hKeySrc,
|
|
|
|
Index,
|
|
|
|
KeyNodeInformation,
|
|
|
|
Info.KeyNode,
|
|
|
|
BufferSize,
|
|
|
|
&BufferSizeRequired);
|
|
|
|
if (NT_SUCCESS(Status2))
|
|
|
|
{
|
|
|
|
HANDLE KeyHandle, NewKeyHandle;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyName, ClassName;
|
|
|
|
|
|
|
|
/* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
|
|
|
|
SubKeyName.Length = Info.KeyNode->NameLength;
|
|
|
|
SubKeyName.MaximumLength = SubKeyName.Length;
|
|
|
|
SubKeyName.Buffer = Info.KeyNode->Name;
|
|
|
|
ClassName.Length = Info.KeyNode->ClassLength;
|
|
|
|
ClassName.MaximumLength = ClassName.Length;
|
|
|
|
ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset);
|
|
|
|
|
|
|
|
/* open the subkey with sufficient rights */
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&SubKeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
copyKeys->hKeySrc,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status2 = NtOpenKey(&KeyHandle,
|
|
|
|
KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status2))
|
|
|
|
{
|
|
|
|
/* FIXME - attempt to query the security information */
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&SubKeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
copyKeys->hKeyDest,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status2 = NtCreateKey(&NewKeyHandle,
|
|
|
|
KEY_ALL_ACCESS,
|
|
|
|
&ObjectAttributes,
|
|
|
|
Info.KeyNode->TitleIndex,
|
|
|
|
&ClassName,
|
|
|
|
0,
|
|
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(Status2))
|
|
|
|
{
|
|
|
|
newCopyKeys = RtlAllocateHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
sizeof(REGP_COPY_KEYS));
|
|
|
|
if (newCopyKeys != NULL)
|
|
|
|
{
|
|
|
|
/* save the handles and enqueue the subkey */
|
|
|
|
newCopyKeys->hKeySrc = KeyHandle;
|
|
|
|
newCopyKeys->hKeyDest = NewKeyHandle;
|
|
|
|
InsertTailList(©QueueHead,
|
|
|
|
&newCopyKeys->ListEntry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
NtClose(NewKeyHandle);
|
|
|
|
|
|
|
|
Status2 = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Status = Status2;
|
|
|
|
}
|
|
|
|
|
|
|
|
Index++;
|
|
|
|
}
|
|
|
|
else if (Status2 == STATUS_BUFFER_OVERFLOW)
|
|
|
|
{
|
|
|
|
PVOID Buffer;
|
|
|
|
|
|
|
|
ASSERT(BufferSize < BufferSizeRequired);
|
|
|
|
|
|
|
|
Buffer = RtlReAllocateHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
Info.Buffer,
|
|
|
|
BufferSizeRequired);
|
|
|
|
if (Buffer != NULL)
|
|
|
|
{
|
|
|
|
Info.Buffer = Buffer;
|
|
|
|
/* try again */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* don't break, let's try to copy as many keys as possible */
|
|
|
|
Status2 = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
Index++;
|
|
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Status = Status2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* break to avoid an infinite loop in case of denied access or
|
|
|
|
other errors! */
|
|
|
|
if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Status = Status2;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* close the handles and remove the entry from the list */
|
|
|
|
if (copyKeys->hKeySrc != hKeySrc)
|
|
|
|
{
|
|
|
|
NtClose(copyKeys->hKeySrc);
|
|
|
|
}
|
|
|
|
if (copyKeys->hKeyDest != hKeyDest)
|
|
|
|
{
|
|
|
|
NtClose(copyKeys->hKeyDest);
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveEntryList(©Keys->ListEntry);
|
|
|
|
|
|
|
|
RtlFreeHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
copyKeys);
|
|
|
|
} while (!IsListEmpty(©QueueHead));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
|
|
|
RtlFreeHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
Info.Buffer);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-25 12:25:11 +00:00
|
|
|
/************************************************************************
|
|
|
|
* RegCopyTreeW
|
|
|
|
*
|
2005-09-24 17:08:13 +00:00
|
|
|
* @implemented
|
2005-08-25 12:25:11 +00:00
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegCopyTreeW(IN HKEY hKeySrc,
|
|
|
|
IN LPCWSTR lpSubKey OPTIONAL,
|
|
|
|
IN HKEY hKeyDest)
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
|
2005-08-25 12:25:11 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = MapDefaultKey(&KeyHandle,
|
|
|
|
hKeySrc);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return RtlNtStatusToDosError(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = MapDefaultKey(&DestKeyHandle,
|
|
|
|
hKeyDest);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
goto Cleanup2;
|
2005-08-25 12:25:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lpSubKey != NULL)
|
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyName;
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&SubKeyName,
|
|
|
|
(LPWSTR)lpSubKey);
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&SubKeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
KeyHandle,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtOpenKey(&SubKeyHandle,
|
2005-09-24 17:08:13 +00:00
|
|
|
KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
|
2005-08-25 12:25:11 +00:00
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
goto Cleanup;
|
2005-08-25 12:25:11 +00:00
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
CurKey = SubKeyHandle;
|
2005-08-25 12:25:11 +00:00
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
else
|
|
|
|
CurKey = KeyHandle;
|
2005-08-25 12:25:11 +00:00
|
|
|
|
2005-09-24 17:08:13 +00:00
|
|
|
Status = RegpCopyTree(CurKey,
|
|
|
|
hKeyDest);
|
2005-08-25 12:25:11 +00:00
|
|
|
|
|
|
|
if (SubKeyHandle != NULL)
|
|
|
|
{
|
|
|
|
NtClose(SubKeyHandle);
|
|
|
|
}
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(DestKeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup2:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-08-25 12:25:11 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return RtlNtStatusToDosError(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* RegCopyTreeA
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegCopyTreeA(IN HKEY hKeySrc,
|
|
|
|
IN LPCSTR lpSubKey OPTIONAL,
|
|
|
|
IN HKEY hKeyDest)
|
|
|
|
{
|
2005-09-22 19:46:36 +00:00
|
|
|
UNICODE_STRING SubKeyName = {0};
|
2005-08-25 12:25:11 +00:00
|
|
|
LONG Ret;
|
|
|
|
|
2005-09-22 19:46:36 +00:00
|
|
|
if (lpSubKey != NULL &&
|
|
|
|
!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
|
|
|
|
(LPSTR)lpSubKey))
|
2005-08-25 12:25:11 +00:00
|
|
|
{
|
2005-09-22 19:46:36 +00:00
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
2005-08-25 12:25:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ret = RegCopyTreeW(hKeySrc,
|
|
|
|
SubKeyName.Buffer,
|
|
|
|
hKeyDest);
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&SubKeyName);
|
|
|
|
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-29 13:54:05 +00:00
|
|
|
/************************************************************************
|
|
|
|
* RegConnectRegistryA
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegConnectRegistryA (IN LPCSTR lpMachineName,
|
|
|
|
IN HKEY hKey,
|
|
|
|
OUT PHKEY phkResult)
|
|
|
|
{
|
2005-09-22 19:46:36 +00:00
|
|
|
UNICODE_STRING MachineName = {0};
|
2005-08-29 13:54:05 +00:00
|
|
|
LONG Ret;
|
|
|
|
|
2005-09-22 19:46:36 +00:00
|
|
|
if (lpMachineName != NULL &&
|
|
|
|
!RtlCreateUnicodeStringFromAsciiz(&MachineName,
|
|
|
|
(LPSTR)lpMachineName))
|
2005-08-29 13:54:05 +00:00
|
|
|
{
|
2005-09-22 19:46:36 +00:00
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
2005-08-29 13:54:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ret = RegConnectRegistryW(MachineName.Buffer,
|
|
|
|
hKey,
|
|
|
|
phkResult);
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&MachineName);
|
|
|
|
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-08 22:55:14 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegConnectRegistryW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @unimplemented
|
2000-09-08 22:55:14 +00:00
|
|
|
*/
|
2001-07-01 17:54:07 +00:00
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegConnectRegistryW (LPCWSTR lpMachineName,
|
|
|
|
HKEY hKey,
|
|
|
|
PHKEY phkResult)
|
2000-09-08 22:55:14 +00:00
|
|
|
{
|
2001-07-01 17:54:07 +00:00
|
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
2000-09-08 22:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-02 21:20:51 +00:00
|
|
|
/************************************************************************
|
|
|
|
* 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);
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
|
2004-07-02 21:20:51 +00:00
|
|
|
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);
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
|
2004-07-02 21:20:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2005-05-05 00:07:27 +00:00
|
|
|
KEY_CREATE_SUB_KEY,
|
2004-07-02 21:20:51 +00:00
|
|
|
&LocalObjectAttributes,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
&Disposition);
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
|
2004-07-02 21:20:51 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlFreeUnicodeString (&LocalKeyName);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegCreateKeyExA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2001-07-01 17:54:07 +00:00
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegCreateKeyExA (HKEY hKey,
|
|
|
|
LPCSTR lpSubKey,
|
|
|
|
DWORD Reserved,
|
|
|
|
LPSTR lpClass,
|
|
|
|
DWORD dwOptions,
|
|
|
|
REGSAM samDesired,
|
|
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
|
|
|
PHKEY phkResult,
|
|
|
|
LPDWORD lpdwDisposition)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2001-07-01 17:54:07 +00:00
|
|
|
UNICODE_STRING SubKeyString;
|
|
|
|
UNICODE_STRING ClassString;
|
|
|
|
OBJECT_ATTRIBUTES Attributes;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE ParentKey;
|
2003-07-12 00:03:42 +00:00
|
|
|
NTSTATUS Status;
|
2001-07-01 17:54:07 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegCreateKeyExA() called\n");
|
2001-07-01 17:54:07 +00:00
|
|
|
|
|
|
|
/* get the real parent key */
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = MapDefaultKey (&ParentKey,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("ParentKey %x\n", (ULONG)ParentKey);
|
2001-07-01 17:54:07 +00:00
|
|
|
|
|
|
|
if (lpClass != NULL)
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
|
|
|
RtlCreateUnicodeStringFromAsciiz (&ClassString,
|
|
|
|
lpClass);
|
|
|
|
}
|
2004-10-10 10:43:23 +00:00
|
|
|
|
|
|
|
RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
|
|
|
|
(LPSTR)lpSubKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
InitializeObjectAttributes (&Attributes,
|
|
|
|
&SubKeyString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
(HANDLE)ParentKey,
|
|
|
|
(PSECURITY_DESCRIPTOR)lpSecurityAttributes);
|
2004-07-02 21:20:51 +00:00
|
|
|
Status = CreateNestedKey(phkResult,
|
2004-10-10 10:43:23 +00:00
|
|
|
&Attributes,
|
|
|
|
(lpClass == NULL)? NULL : &ClassString,
|
|
|
|
dwOptions,
|
|
|
|
samDesired,
|
|
|
|
lpdwDisposition);
|
2003-07-12 00:03:42 +00:00
|
|
|
RtlFreeUnicodeString (&SubKeyString);
|
2001-07-01 17:54:07 +00:00
|
|
|
if (lpClass != NULL)
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
|
|
|
RtlFreeUnicodeString (&ClassString);
|
|
|
|
}
|
2004-10-10 10:43:23 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(ParentKey);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("Status %x\n", Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
return ERROR_SUCCESS;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-22 21:36:37 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegCreateKeyExW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-07-22 21:36:37 +00:00
|
|
|
*/
|
2001-07-01 17:54:07 +00:00
|
|
|
LONG STDCALL
|
2004-02-22 14:26:07 +00:00
|
|
|
RegCreateKeyExW (HKEY hKey,
|
|
|
|
LPCWSTR lpSubKey,
|
|
|
|
DWORD Reserved,
|
|
|
|
LPWSTR lpClass,
|
|
|
|
DWORD dwOptions,
|
|
|
|
REGSAM samDesired,
|
|
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
|
|
|
PHKEY phkResult,
|
|
|
|
LPDWORD lpdwDisposition)
|
1999-07-22 21:36:37 +00:00
|
|
|
{
|
2002-12-08 16:14:28 +00:00
|
|
|
UNICODE_STRING SubKeyString;
|
|
|
|
UNICODE_STRING ClassString;
|
|
|
|
OBJECT_ATTRIBUTES Attributes;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE ParentKey;
|
2003-07-12 00:03:42 +00:00
|
|
|
NTSTATUS Status;
|
2002-12-08 16:14:28 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegCreateKeyExW() called\n");
|
2002-12-08 16:14:28 +00:00
|
|
|
|
|
|
|
/* get the real parent key */
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = MapDefaultKey (&ParentKey,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError(Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("ParentKey %x\n", (ULONG)ParentKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
|
|
|
|
RtlInitUnicodeString (&ClassString,
|
|
|
|
lpClass);
|
|
|
|
RtlInitUnicodeString (&SubKeyString,
|
|
|
|
lpSubKey);
|
2002-12-08 16:14:28 +00:00
|
|
|
InitializeObjectAttributes (&Attributes,
|
2003-07-12 00:03:42 +00:00
|
|
|
&SubKeyString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
(HANDLE)ParentKey,
|
|
|
|
(PSECURITY_DESCRIPTOR)lpSecurityAttributes);
|
2004-07-02 21:20:51 +00:00
|
|
|
Status = CreateNestedKey(phkResult,
|
|
|
|
&Attributes,
|
|
|
|
(lpClass == NULL)? NULL : &ClassString,
|
|
|
|
dwOptions,
|
|
|
|
samDesired,
|
|
|
|
lpdwDisposition);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(ParentKey);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("Status %x\n", Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
2002-12-08 16:14:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
1999-07-22 21:36:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-10 13:44:48 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegCreateKeyA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2002-11-10 13:44:48 +00:00
|
|
|
*/
|
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegCreateKeyA (HKEY hKey,
|
|
|
|
LPCSTR lpSubKey,
|
|
|
|
PHKEY phkResult)
|
2002-11-10 13:44:48 +00:00
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
return RegCreateKeyExA (hKey,
|
|
|
|
lpSubKey,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
2005-05-05 00:07:27 +00:00
|
|
|
MAXIMUM_ALLOWED,
|
2003-07-12 00:03:42 +00:00
|
|
|
NULL,
|
|
|
|
phkResult,
|
|
|
|
NULL);
|
2002-11-10 13:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegCreateKeyW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2002-11-10 13:44:48 +00:00
|
|
|
*/
|
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegCreateKeyW (HKEY hKey,
|
|
|
|
LPCWSTR lpSubKey,
|
|
|
|
PHKEY phkResult)
|
2002-11-10 13:44:48 +00:00
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
return RegCreateKeyExW (hKey,
|
|
|
|
lpSubKey,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
2005-05-05 00:07:27 +00:00
|
|
|
MAXIMUM_ALLOWED,
|
2003-07-12 00:03:42 +00:00
|
|
|
NULL,
|
|
|
|
phkResult,
|
|
|
|
NULL);
|
2002-11-10 13:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegDeleteKeyA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegDeleteKeyA (HKEY hKey,
|
|
|
|
LPCSTR lpSubKey)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2002-12-08 16:14:28 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
2003-07-12 00:03:42 +00:00
|
|
|
UNICODE_STRING SubKeyName;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE ParentKey;
|
2002-12-08 16:14:28 +00:00
|
|
|
HANDLE TargetKey;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = MapDefaultKey (&ParentKey,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
RtlCreateUnicodeStringFromAsciiz (&SubKeyName,
|
|
|
|
(LPSTR)lpSubKey);
|
2003-03-24 13:44:15 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
2003-07-12 00:03:42 +00:00
|
|
|
&SubKeyName,
|
2003-03-24 13:44:15 +00:00
|
|
|
OBJ_CASE_INSENSITIVE,
|
2005-05-08 03:09:14 +00:00
|
|
|
ParentKey,
|
2003-03-24 13:44:15 +00:00
|
|
|
NULL);
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = NtOpenKey (&TargetKey,
|
|
|
|
DELETE,
|
|
|
|
&ObjectAttributes);
|
|
|
|
RtlFreeUnicodeString (&SubKeyName);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
goto Cleanup;
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = NtDeleteKey (TargetKey);
|
|
|
|
NtClose (TargetKey);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(ParentKey);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError(Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2002-12-08 16:14:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-22 21:36:37 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegDeleteKeyW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-07-22 21:36:37 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegDeleteKeyW (HKEY hKey,
|
|
|
|
LPCWSTR lpSubKey)
|
1999-07-22 21:36:37 +00:00
|
|
|
{
|
2002-12-08 16:14:28 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
2003-07-12 00:03:42 +00:00
|
|
|
UNICODE_STRING SubKeyName;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE ParentKey;
|
2002-12-08 16:14:28 +00:00
|
|
|
HANDLE TargetKey;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = MapDefaultKey (&ParentKey,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2002-12-08 16:14:28 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
RtlInitUnicodeString (&SubKeyName,
|
|
|
|
(LPWSTR)lpSubKey);
|
2002-12-08 16:14:28 +00:00
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
2003-07-12 00:03:42 +00:00
|
|
|
&SubKeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
2005-05-08 03:09:14 +00:00
|
|
|
ParentKey,
|
2003-07-12 00:03:42 +00:00
|
|
|
NULL);
|
|
|
|
Status = NtOpenKey (&TargetKey,
|
|
|
|
DELETE,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
goto Cleanup;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status = NtDeleteKey (TargetKey);
|
|
|
|
NtClose (TargetKey);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(ParentKey);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
2002-12-08 16:14:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
1999-07-22 21:36:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-24 23:29:51 +00:00
|
|
|
/************************************************************************
|
|
|
|
* RegDeleteKeyValueW
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegDeleteKeyValueW(IN HKEY hKey,
|
|
|
|
IN LPCWSTR lpSubKey OPTIONAL,
|
|
|
|
IN LPCWSTR lpValueName OPTIONAL)
|
|
|
|
{
|
|
|
|
UNICODE_STRING ValueName;
|
2005-08-26 09:40:37 +00:00
|
|
|
HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
|
2005-08-24 23:29:51 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = MapDefaultKey(&KeyHandle,
|
|
|
|
hKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return RtlNtStatusToDosError(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lpSubKey != NULL)
|
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyName;
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&SubKeyName,
|
|
|
|
(LPWSTR)lpSubKey);
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&SubKeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
KeyHandle,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtOpenKey(&SubKeyHandle,
|
|
|
|
KEY_SET_VALUE,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
goto Cleanup;
|
2005-08-24 23:29:51 +00:00
|
|
|
}
|
2005-08-25 12:30:10 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
CurKey = SubKeyHandle;
|
2005-08-24 23:29:51 +00:00
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
else
|
|
|
|
CurKey = KeyHandle;
|
2005-08-24 23:29:51 +00:00
|
|
|
|
|
|
|
RtlInitUnicodeString(&ValueName,
|
|
|
|
(LPWSTR)lpValueName);
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Status = NtDeleteValueKey(CurKey,
|
2005-08-24 23:29:51 +00:00
|
|
|
&ValueName);
|
|
|
|
|
|
|
|
if (SubKeyHandle != NULL)
|
|
|
|
{
|
|
|
|
NtClose(SubKeyHandle);
|
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-24 23:29:51 +00:00
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return RtlNtStatusToDosError(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* RegDeleteKeyValueA
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegDeleteKeyValueA(IN HKEY hKey,
|
|
|
|
IN LPCSTR lpSubKey OPTIONAL,
|
|
|
|
IN LPCSTR lpValueName OPTIONAL)
|
|
|
|
{
|
2005-09-22 19:46:36 +00:00
|
|
|
UNICODE_STRING SubKey = {0}, ValueName = {0};
|
2005-08-24 23:29:51 +00:00
|
|
|
LONG Ret;
|
|
|
|
|
2005-09-22 19:46:36 +00:00
|
|
|
if (lpSubKey != NULL &&
|
|
|
|
!RtlCreateUnicodeStringFromAsciiz(&SubKey,
|
|
|
|
(LPSTR)lpSubKey))
|
2005-08-24 23:29:51 +00:00
|
|
|
{
|
2005-09-22 19:46:36 +00:00
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
2005-08-24 23:29:51 +00:00
|
|
|
}
|
|
|
|
|
2005-09-22 19:46:36 +00:00
|
|
|
if (lpValueName != NULL &&
|
|
|
|
!RtlCreateUnicodeStringFromAsciiz(&ValueName,
|
|
|
|
(LPSTR)lpValueName))
|
2005-08-24 23:29:51 +00:00
|
|
|
{
|
2005-09-22 19:46:36 +00:00
|
|
|
RtlFreeUnicodeString(&SubKey);
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
2005-08-24 23:29:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ret = RegDeleteKeyValueW(hKey,
|
|
|
|
SubKey.Buffer,
|
|
|
|
SubKey.Buffer);
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&SubKey);
|
|
|
|
RtlFreeUnicodeString(&ValueName);
|
|
|
|
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-27 18:13:52 +00:00
|
|
|
static NTSTATUS
|
2005-09-21 23:56:52 +00:00
|
|
|
RegpDeleteTree(IN HKEY hKey)
|
2005-08-27 18:13:52 +00:00
|
|
|
{
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
LIST_ENTRY ListEntry;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
} REGP_DEL_KEYS, *PREG_DEL_KEYS;
|
|
|
|
|
|
|
|
LIST_ENTRY delQueueHead;
|
2005-08-29 13:54:05 +00:00
|
|
|
PREG_DEL_KEYS delKeys, newDelKeys;
|
2005-08-27 18:13:52 +00:00
|
|
|
HANDLE ProcessHeap;
|
|
|
|
ULONG BufferSize;
|
|
|
|
PKEY_BASIC_INFORMATION BasicInfo;
|
|
|
|
PREG_DEL_KEYS KeyDelRoot;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
NTSTATUS Status2 = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
InitializeListHead(&delQueueHead);
|
|
|
|
|
|
|
|
ProcessHeap = RtlGetProcessHeap();
|
|
|
|
|
|
|
|
/* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
|
|
|
|
structure for the root key, we only do that for subkeys as we need to
|
|
|
|
allocate REGP_DEL_KEYS structures anyway! */
|
|
|
|
KeyDelRoot = RtlAllocateHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
sizeof(REGP_DEL_KEYS));
|
|
|
|
if (KeyDelRoot != NULL)
|
|
|
|
{
|
|
|
|
KeyDelRoot->KeyHandle = hKey;
|
|
|
|
InsertTailList(&delQueueHead,
|
|
|
|
&KeyDelRoot->ListEntry);
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
delKeys = CONTAINING_RECORD(delQueueHead.Flink,
|
|
|
|
REGP_DEL_KEYS,
|
|
|
|
ListEntry);
|
|
|
|
|
|
|
|
BufferSize = 0;
|
|
|
|
BasicInfo = NULL;
|
|
|
|
newDelKeys = NULL;
|
|
|
|
|
|
|
|
ReadFirstSubKey:
|
|
|
|
/* check if this key contains subkeys and delete them first by queuing
|
|
|
|
them at the head of the list */
|
|
|
|
Status2 = NtEnumerateKey(delKeys->KeyHandle,
|
|
|
|
0,
|
|
|
|
KeyBasicInformation,
|
|
|
|
BasicInfo,
|
|
|
|
BufferSize,
|
|
|
|
&BufferSize);
|
|
|
|
|
|
|
|
if (NT_SUCCESS(Status2))
|
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyName;
|
|
|
|
|
|
|
|
ASSERT(newDelKeys != NULL);
|
|
|
|
ASSERT(BasicInfo != NULL);
|
|
|
|
|
|
|
|
/* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
|
|
|
|
SubKeyName.Length = BasicInfo->NameLength;
|
|
|
|
SubKeyName.MaximumLength = BasicInfo->NameLength;
|
|
|
|
SubKeyName.Buffer = BasicInfo->Name;
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&SubKeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
delKeys->KeyHandle,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* open the subkey */
|
|
|
|
Status2 = NtOpenKey(&newDelKeys->KeyHandle,
|
2005-10-03 21:37:05 +00:00
|
|
|
DELETE | KEY_ENUMERATE_SUB_KEYS,
|
2005-08-27 18:13:52 +00:00
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status2))
|
|
|
|
{
|
|
|
|
goto SubKeyFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* enqueue this key to the head of the deletion queue */
|
|
|
|
InsertHeadList(&delQueueHead,
|
|
|
|
&newDelKeys->ListEntry);
|
|
|
|
|
|
|
|
/* try again from the head of the list */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (Status2 == STATUS_BUFFER_TOO_SMALL)
|
|
|
|
{
|
|
|
|
newDelKeys = RtlAllocateHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
BufferSize + sizeof(REGP_DEL_KEYS));
|
|
|
|
if (newDelKeys != NULL)
|
|
|
|
{
|
|
|
|
BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
|
|
|
|
|
|
|
|
/* try again */
|
|
|
|
goto ReadFirstSubKey;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* don't break, let's try to delete as many keys as possible */
|
|
|
|
Status2 = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto SubKeyFailureNoFree;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (Status2 == STATUS_BUFFER_OVERFLOW)
|
|
|
|
{
|
|
|
|
PREG_DEL_KEYS newDelKeys2;
|
|
|
|
|
|
|
|
ASSERT(newDelKeys != NULL);
|
|
|
|
|
|
|
|
/* we need more memory to query the key name */
|
|
|
|
newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
newDelKeys,
|
|
|
|
BufferSize + sizeof(REGP_DEL_KEYS));
|
|
|
|
if (newDelKeys2 != NULL)
|
|
|
|
{
|
|
|
|
newDelKeys = newDelKeys2;
|
|
|
|
BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
|
|
|
|
|
|
|
|
/* try again */
|
|
|
|
goto ReadFirstSubKey;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* don't break, let's try to delete as many keys as possible */
|
|
|
|
Status2 = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
}
|
2005-10-03 21:37:05 +00:00
|
|
|
else if (Status2 == STATUS_NO_MORE_ENTRIES)
|
|
|
|
{
|
2005-10-03 22:46:49 +00:00
|
|
|
/* in some race conditions where another thread would delete
|
|
|
|
the same tree at the same time, newDelKeys could actually
|
|
|
|
be != NULL! */
|
|
|
|
if (newDelKeys != NULL)
|
|
|
|
{
|
|
|
|
RtlFreeHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
newDelKeys);
|
|
|
|
}
|
2005-10-03 21:37:05 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-08-29 13:54:05 +00:00
|
|
|
|
2005-08-27 18:13:52 +00:00
|
|
|
SubKeyFailure:
|
2005-10-03 23:01:10 +00:00
|
|
|
/* newDelKeys can be NULL here when NtEnumerateKey returned an
|
|
|
|
error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
|
|
|
|
if (newDelKeys != NULL)
|
|
|
|
{
|
|
|
|
RtlFreeHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
newDelKeys);
|
|
|
|
}
|
2005-08-29 13:54:05 +00:00
|
|
|
|
2005-08-27 18:13:52 +00:00
|
|
|
SubKeyFailureNoFree:
|
|
|
|
/* don't break, let's try to delete as many keys as possible */
|
2005-10-03 23:01:10 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
2005-08-27 18:13:52 +00:00
|
|
|
{
|
|
|
|
Status = Status2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Status2 = NtDeleteKey(delKeys->KeyHandle);
|
|
|
|
|
|
|
|
/* NOTE: do NOT close the handle anymore, it's invalid already! */
|
|
|
|
|
2005-09-21 23:56:52 +00:00
|
|
|
if (!NT_SUCCESS(Status2))
|
2005-08-27 18:13:52 +00:00
|
|
|
{
|
2005-09-21 23:56:52 +00:00
|
|
|
/* close the key handle so we don't leak handles for keys we were
|
|
|
|
unable to delete. But only do this for handles not supplied
|
|
|
|
by the caller! */
|
|
|
|
|
|
|
|
if (delKeys->KeyHandle != hKey)
|
|
|
|
{
|
|
|
|
NtClose(delKeys->KeyHandle);
|
|
|
|
}
|
|
|
|
|
2005-09-24 17:08:13 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
2005-09-21 23:56:52 +00:00
|
|
|
{
|
|
|
|
/* don't break, let's try to delete as many keys as possible */
|
|
|
|
Status = Status2;
|
|
|
|
}
|
2005-08-27 18:13:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* remove the entry from the list */
|
|
|
|
RemoveEntryList(&delKeys->ListEntry);
|
|
|
|
|
|
|
|
RtlFreeHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
delKeys);
|
|
|
|
} while (!IsListEmpty(&delQueueHead));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
2005-10-03 21:37:05 +00:00
|
|
|
|
2005-08-27 18:13:52 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-25 12:25:11 +00:00
|
|
|
/************************************************************************
|
|
|
|
* RegDeleteTreeW
|
|
|
|
*
|
2005-08-27 18:13:52 +00:00
|
|
|
* @implemented
|
2005-08-25 12:25:11 +00:00
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegDeleteTreeW(IN HKEY hKey,
|
|
|
|
IN LPCWSTR lpSubKey OPTIONAL)
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
|
2005-08-25 12:25:11 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = MapDefaultKey(&KeyHandle,
|
|
|
|
hKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return RtlNtStatusToDosError(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lpSubKey != NULL)
|
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyName;
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&SubKeyName,
|
|
|
|
(LPWSTR)lpSubKey);
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&SubKeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
KeyHandle,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtOpenKey(&SubKeyHandle,
|
2005-10-03 22:46:49 +00:00
|
|
|
DELETE | KEY_ENUMERATE_SUB_KEYS,
|
2005-08-25 12:25:11 +00:00
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
goto Cleanup;
|
2005-08-25 12:25:11 +00:00
|
|
|
}
|
2005-08-25 12:30:10 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
CurKey = SubKeyHandle;
|
2005-08-25 12:25:11 +00:00
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
else
|
|
|
|
CurKey = KeyHandle;
|
2005-08-25 12:25:11 +00:00
|
|
|
|
2005-09-21 23:56:52 +00:00
|
|
|
Status = RegpDeleteTree(CurKey);
|
2005-08-25 12:25:11 +00:00
|
|
|
|
2005-09-21 23:56:52 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
2005-08-25 12:25:11 +00:00
|
|
|
{
|
2005-09-21 23:56:52 +00:00
|
|
|
/* make sure we only close hKey (KeyHandle) when the caller specified a
|
|
|
|
subkey, because the handle would be invalid already! */
|
|
|
|
if (CurKey != KeyHandle)
|
|
|
|
{
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-09-21 23:56:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* make sure we close all handles we created! */
|
2005-08-29 13:54:05 +00:00
|
|
|
if (SubKeyHandle != NULL)
|
|
|
|
{
|
|
|
|
NtClose(SubKeyHandle);
|
|
|
|
}
|
2005-08-25 12:25:11 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-09-21 23:56:52 +00:00
|
|
|
|
2005-08-25 12:25:11 +00:00
|
|
|
return RtlNtStatusToDosError(Status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* RegDeleteTreeA
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegDeleteTreeA(IN HKEY hKey,
|
|
|
|
IN LPCSTR lpSubKey OPTIONAL)
|
|
|
|
{
|
2005-09-22 19:46:36 +00:00
|
|
|
UNICODE_STRING SubKeyName = {0};
|
2005-08-25 12:25:11 +00:00
|
|
|
LONG Ret;
|
|
|
|
|
2005-09-22 19:46:36 +00:00
|
|
|
if (lpSubKey != NULL &&
|
|
|
|
!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
|
|
|
|
(LPSTR)lpSubKey))
|
2005-08-25 12:25:11 +00:00
|
|
|
{
|
2005-09-22 19:46:36 +00:00
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
2005-08-25 12:25:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ret = RegDeleteTreeW(hKey,
|
|
|
|
SubKeyName.Buffer);
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&SubKeyName);
|
|
|
|
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-24 23:44:27 +00:00
|
|
|
/************************************************************************
|
|
|
|
* RegSetKeyValueW
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegSetKeyValueW(IN HKEY hKey,
|
|
|
|
IN LPCWSTR lpSubKey OPTIONAL,
|
|
|
|
IN LPCWSTR lpValueName OPTIONAL,
|
|
|
|
IN DWORD dwType,
|
|
|
|
IN LPCVOID lpData OPTIONAL,
|
|
|
|
IN DWORD cbData)
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
|
2005-08-24 23:44:27 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
LONG Ret;
|
|
|
|
|
|
|
|
Status = MapDefaultKey(&KeyHandle,
|
|
|
|
hKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return RtlNtStatusToDosError(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lpSubKey != NULL)
|
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyName;
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&SubKeyName,
|
|
|
|
(LPWSTR)lpSubKey);
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&SubKeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
KeyHandle,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtOpenKey(&SubKeyHandle,
|
|
|
|
KEY_SET_VALUE,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
Ret = RtlNtStatusToDosError(Status);
|
|
|
|
goto Cleanup;
|
2005-08-24 23:44:27 +00:00
|
|
|
}
|
2005-08-25 12:30:10 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
CurKey = SubKeyHandle;
|
2005-08-24 23:44:27 +00:00
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
else
|
|
|
|
CurKey = KeyHandle;
|
2005-08-24 23:44:27 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Ret = RegSetValueExW(CurKey,
|
2005-08-24 23:44:27 +00:00
|
|
|
lpValueName,
|
|
|
|
0,
|
|
|
|
dwType,
|
|
|
|
lpData,
|
|
|
|
cbData);
|
|
|
|
|
|
|
|
if (SubKeyHandle != NULL)
|
|
|
|
{
|
|
|
|
NtClose(SubKeyHandle);
|
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-24 23:44:27 +00:00
|
|
|
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* RegSetKeyValueA
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegSetKeyValueA(IN HKEY hKey,
|
|
|
|
IN LPCSTR lpSubKey OPTIONAL,
|
|
|
|
IN LPCSTR lpValueName OPTIONAL,
|
|
|
|
IN DWORD dwType,
|
|
|
|
IN LPCVOID lpData OPTIONAL,
|
|
|
|
IN DWORD cbData)
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
|
2005-08-24 23:44:27 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
LONG Ret;
|
|
|
|
|
|
|
|
Status = MapDefaultKey(&KeyHandle,
|
|
|
|
hKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return RtlNtStatusToDosError(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lpSubKey != NULL)
|
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyName;
|
|
|
|
|
|
|
|
if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
|
|
|
|
(LPSTR)lpSubKey))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
Ret = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
goto Cleanup;
|
2005-08-24 23:44:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&SubKeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
KeyHandle,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtOpenKey(&SubKeyHandle,
|
|
|
|
KEY_SET_VALUE,
|
|
|
|
&ObjectAttributes);
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&SubKeyName);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
Ret = RtlNtStatusToDosError(Status);
|
|
|
|
goto Cleanup;
|
2005-08-24 23:44:27 +00:00
|
|
|
}
|
2005-08-25 12:30:10 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
CurKey = SubKeyHandle;
|
2005-08-24 23:44:27 +00:00
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
else
|
|
|
|
CurKey = KeyHandle;
|
2005-08-24 23:44:27 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Ret = RegSetValueExA(CurKey,
|
2005-08-24 23:44:27 +00:00
|
|
|
lpValueName,
|
|
|
|
0,
|
|
|
|
dwType,
|
|
|
|
lpData,
|
|
|
|
cbData);
|
|
|
|
|
|
|
|
if (SubKeyHandle != NULL)
|
|
|
|
{
|
|
|
|
NtClose(SubKeyHandle);
|
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-24 23:44:27 +00:00
|
|
|
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegDeleteValueA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegDeleteValueA (HKEY hKey,
|
|
|
|
LPCSTR lpValueName)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
UNICODE_STRING ValueName;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2003-07-12 00:03:42 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RtlCreateUnicodeStringFromAsciiz (&ValueName,
|
|
|
|
(LPSTR)lpValueName);
|
|
|
|
Status = NtDeleteValueKey (KeyHandle,
|
|
|
|
&ValueName);
|
|
|
|
RtlFreeUnicodeString (&ValueName);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2002-12-08 16:14:28 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-06 19:59:54 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegDeleteValueW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2000-09-06 19:59:54 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegDeleteValueW (HKEY hKey,
|
|
|
|
LPCWSTR lpValueName)
|
2000-09-06 19:59:54 +00:00
|
|
|
{
|
2002-12-08 16:14:28 +00:00
|
|
|
UNICODE_STRING ValueName;
|
|
|
|
NTSTATUS Status;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2002-12-08 16:14:28 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RtlInitUnicodeString (&ValueName,
|
|
|
|
(LPWSTR)lpValueName);
|
|
|
|
|
|
|
|
Status = NtDeleteValueKey (KeyHandle,
|
|
|
|
&ValueName);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2002-12-08 16:14:28 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
2002-12-08 16:14:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
2000-09-06 19:59:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-08 22:55:14 +00:00
|
|
|
/************************************************************************
|
2003-07-12 00:03:42 +00:00
|
|
|
* RegEnumKeyA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2000-09-08 22:55:14 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegEnumKeyA (HKEY hKey,
|
|
|
|
DWORD dwIndex,
|
|
|
|
LPSTR lpName,
|
|
|
|
DWORD cbName)
|
2000-09-08 22:55:14 +00:00
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
DWORD dwLength;
|
|
|
|
|
|
|
|
dwLength = cbName;
|
|
|
|
return RegEnumKeyExA (hKey,
|
|
|
|
dwIndex,
|
|
|
|
lpName,
|
|
|
|
&dwLength,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2000-09-08 22:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegEnumKeyW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2000-09-08 22:55:14 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegEnumKeyW (HKEY hKey,
|
|
|
|
DWORD dwIndex,
|
|
|
|
LPWSTR lpName,
|
|
|
|
DWORD cbName)
|
2000-09-08 22:55:14 +00:00
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
DWORD dwLength;
|
|
|
|
|
|
|
|
dwLength = cbName;
|
|
|
|
return RegEnumKeyExW (hKey,
|
|
|
|
dwIndex,
|
|
|
|
lpName,
|
|
|
|
&dwLength,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2000-09-08 22:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegEnumKeyExA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegEnumKeyExA (HKEY hKey,
|
|
|
|
DWORD dwIndex,
|
|
|
|
LPSTR lpName,
|
|
|
|
LPDWORD lpcbName,
|
|
|
|
LPDWORD lpReserved,
|
|
|
|
LPSTR lpClass,
|
|
|
|
LPDWORD lpcbClass,
|
|
|
|
PFILETIME lpftLastWriteTime)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2005-04-30 21:11:34 +00:00
|
|
|
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;
|
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
|
2005-04-30 21:11:34 +00:00
|
|
|
hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
|
|
|
|
|
|
|
|
if ((lpClass) && (!lpcbClass))
|
|
|
|
{
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2005-04-30 21:11:34 +00:00
|
|
|
Status = MapDefaultKey(&KeyHandle, hKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2005-04-30 21:11:34 +00:00
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2005-04-30 21:11:34 +00:00
|
|
|
if (*lpcbName > 0)
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2005-04-30 21:11:34 +00:00
|
|
|
NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
|
2003-08-30 14:46:29 +00:00
|
|
|
}
|
2005-04-30 21:11:34 +00:00
|
|
|
else
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2005-04-30 21:11:34 +00:00
|
|
|
NameLength = 0;
|
2003-08-30 14:46:29 +00:00
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2005-04-30 21:11:34 +00:00
|
|
|
if (lpClass)
|
|
|
|
{
|
|
|
|
if (*lpcbClass > 0)
|
|
|
|
{
|
|
|
|
ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ClassLength = 0;
|
|
|
|
}
|
2001-09-01 15:36:45 +00:00
|
|
|
|
2005-04-30 21:11:34 +00:00
|
|
|
/* The class name should start at a dword boundary */
|
|
|
|
BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
|
|
|
|
}
|
|
|
|
else
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2005-04-30 21:11:34 +00:00
|
|
|
BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
|
2003-08-30 14:46:29 +00:00
|
|
|
}
|
2005-04-30 21:11:34 +00:00
|
|
|
|
|
|
|
KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
|
|
|
|
if (KeyInfo == NULL)
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = ERROR_OUTOFMEMORY;
|
|
|
|
goto Cleanup;
|
2003-08-30 14:46:29 +00:00
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2005-04-30 21:11:34 +00:00
|
|
|
Status = NtEnumerateKey (KeyHandle,
|
|
|
|
(ULONG)dwIndex,
|
|
|
|
lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
|
|
|
|
KeyInfo,
|
|
|
|
BufferSize,
|
|
|
|
&ResultSize);
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
|
2005-04-30 21:11:34 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2005-04-30 21:11:34 +00:00
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (lpClass == NULL)
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2005-04-30 21:11:34 +00:00
|
|
|
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;
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
}
|
2005-04-30 21:11:34 +00:00
|
|
|
else
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2005-04-30 21:11:34 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
}
|
2002-11-10 13:44:48 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("Key Namea0 Length %d\n", StringU.Length);
|
|
|
|
TRACE("Key Namea1 Length %d\n", NameLength);
|
|
|
|
TRACE("Key Namea Length %d\n", *lpcbName);
|
|
|
|
TRACE("Key Namea %s\n", lpName);
|
2002-11-10 13:44:48 +00:00
|
|
|
|
2005-04-30 21:11:34 +00:00
|
|
|
RtlFreeHeap (ProcessHeap,
|
|
|
|
0,
|
|
|
|
KeyInfo);
|
2003-08-30 14:46:29 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
return ErrorCode;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-10 13:44:48 +00:00
|
|
|
/************************************************************************
|
2003-07-12 00:03:42 +00:00
|
|
|
* RegEnumKeyExW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2002-11-10 13:44:48 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegEnumKeyExW (HKEY hKey,
|
|
|
|
DWORD dwIndex,
|
|
|
|
LPWSTR lpName,
|
|
|
|
LPDWORD lpcbName,
|
|
|
|
LPDWORD lpReserved,
|
|
|
|
LPWSTR lpClass,
|
|
|
|
LPDWORD lpcbClass,
|
|
|
|
PFILETIME lpftLastWriteTime)
|
2002-11-10 13:44:48 +00:00
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
union
|
|
|
|
{
|
|
|
|
KEY_NODE_INFORMATION Node;
|
|
|
|
KEY_BASIC_INFORMATION Basic;
|
|
|
|
} *KeyInfo;
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
ULONG BufferSize;
|
|
|
|
ULONG ResultSize;
|
2003-08-30 14:46:29 +00:00
|
|
|
ULONG NameLength;
|
2004-07-03 17:40:27 +00:00
|
|
|
ULONG ClassLength = 0;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2003-08-30 14:46:29 +00:00
|
|
|
LONG ErrorCode = ERROR_SUCCESS;
|
2003-07-12 00:03:42 +00:00
|
|
|
NTSTATUS Status;
|
2002-11-10 13:44:48 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = MapDefaultKey(&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
if (*lpcbName > 0)
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
NameLength = 0;
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
if (lpClass)
|
|
|
|
{
|
|
|
|
if (*lpcbClass > 0)
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
|
|
|
ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
|
2003-08-30 14:46:29 +00:00
|
|
|
}
|
|
|
|
else
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
ClassLength = 0;
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
KeyInfo = RtlAllocateHeap (ProcessHeap,
|
2003-07-12 00:03:42 +00:00
|
|
|
0,
|
|
|
|
BufferSize);
|
|
|
|
if (KeyInfo == NULL)
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = ERROR_OUTOFMEMORY;
|
|
|
|
goto Cleanup;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2000-09-08 22:55:14 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
Status = NtEnumerateKey (KeyHandle,
|
|
|
|
(ULONG)dwIndex,
|
|
|
|
lpClass ? KeyNodeInformation : KeyBasicInformation,
|
|
|
|
KeyInfo,
|
|
|
|
BufferSize,
|
|
|
|
&ResultSize);
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
|
2003-08-30 14:46:29 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (lpClass == NULL)
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
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;
|
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
else
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
if (KeyInfo->Node.NameLength > NameLength ||
|
|
|
|
KeyInfo->Node.ClassLength > ClassLength)
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
ErrorCode = ERROR_BUFFER_OVERFLOW;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
else
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
RtlCopyMemory (lpName,
|
2004-02-22 14:26:07 +00:00
|
|
|
KeyInfo->Node.Name,
|
2003-08-30 14:46:29 +00:00
|
|
|
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;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
|
|
|
|
{
|
|
|
|
if (lpClass == NULL)
|
|
|
|
{
|
|
|
|
lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
|
|
|
|
lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
|
|
|
|
}
|
|
|
|
else
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
|
|
|
|
lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
}
|
2002-12-08 16:14:28 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
RtlFreeHeap (ProcessHeap,
|
2003-07-12 00:03:42 +00:00
|
|
|
0,
|
|
|
|
KeyInfo);
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
return ErrorCode;
|
2000-09-08 22:55:14 +00:00
|
|
|
}
|
|
|
|
|
2002-11-10 13:44:48 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegEnumValueA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2002-11-10 13:44:48 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
2005-05-04 15:53:54 +00:00
|
|
|
RegEnumValueA( HKEY hKey, DWORD index, LPSTR value, LPDWORD val_count,
|
|
|
|
LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
|
2002-11-10 13:44:48 +00:00
|
|
|
{
|
2005-04-30 21:11:34 +00:00
|
|
|
HANDLE KeyHandle;
|
2005-05-04 15:53:54 +00:00
|
|
|
NTSTATUS status;
|
|
|
|
DWORD total_size;
|
|
|
|
char buffer[256], *buf_ptr = buffer;
|
|
|
|
KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
|
2005-11-11 11:59:56 +00:00
|
|
|
static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
|
2005-05-04 15:53:54 +00:00
|
|
|
|
|
|
|
//TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
|
|
|
|
// hkey, index, value, val_count, reserved, type, data, count );
|
|
|
|
|
|
|
|
/* NT only checks count, not val_count */
|
|
|
|
if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
|
|
|
|
status = MapDefaultKey (&KeyHandle, hKey);
|
|
|
|
if (!NT_SUCCESS(status))
|
2005-04-30 21:11:34 +00:00
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (status);
|
2005-04-30 21:11:34 +00:00
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
|
|
|
|
if (data) total_size += *count;
|
|
|
|
total_size = min( sizeof(buffer), total_size );
|
2003-08-30 14:46:29 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
|
|
|
|
buffer, total_size, &total_size );
|
|
|
|
if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
|
2005-04-30 21:11:34 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
/* we need to fetch the contents for a string type even if not requested,
|
|
|
|
* because we need to compute the length of the ASCII string. */
|
|
|
|
if (value || data || is_string(info->Type))
|
|
|
|
{
|
|
|
|
/* retry with a dynamically allocated buffer */
|
|
|
|
while (status == STATUS_BUFFER_OVERFLOW)
|
|
|
|
{
|
|
|
|
if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
|
|
|
|
if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
|
2005-08-26 09:40:37 +00:00
|
|
|
{
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto done;
|
|
|
|
}
|
2005-05-04 15:53:54 +00:00
|
|
|
info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
|
|
|
|
status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
|
|
|
|
buf_ptr, total_size, &total_size );
|
|
|
|
}
|
2005-04-30 21:11:34 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (status) goto done;
|
2005-04-30 21:11:34 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (is_string(info->Type))
|
|
|
|
{
|
|
|
|
DWORD len;
|
|
|
|
RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
|
|
|
|
total_size - info->DataOffset );
|
|
|
|
if (data && len)
|
|
|
|
{
|
|
|
|
if (len > *count) status = STATUS_BUFFER_OVERFLOW;
|
|
|
|
else
|
|
|
|
{
|
2005-05-08 03:09:14 +00:00
|
|
|
RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
|
2005-05-04 15:53:54 +00:00
|
|
|
total_size - info->DataOffset );
|
|
|
|
/* if the type is REG_SZ and data is not 0-terminated
|
|
|
|
* and there is enough space in the buffer NT appends a \0 */
|
|
|
|
if (len < *count && data[len-1]) data[len] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
info->DataLength = len;
|
|
|
|
}
|
|
|
|
else if (data)
|
|
|
|
{
|
|
|
|
if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
|
|
|
|
else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (value && !status)
|
|
|
|
{
|
|
|
|
DWORD len;
|
|
|
|
|
|
|
|
RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
|
|
|
|
if (len >= *val_count)
|
|
|
|
{
|
|
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
|
|
if (*val_count)
|
|
|
|
{
|
|
|
|
len = *val_count - 1;
|
|
|
|
RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
|
|
|
|
value[len] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
|
|
|
|
value[len] = 0;
|
|
|
|
*val_count = len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else status = STATUS_SUCCESS;
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (type) *type = info->Type;
|
|
|
|
if (count) *count = info->DataLength;
|
2005-04-30 21:11:34 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
done:
|
|
|
|
if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-05-04 15:53:54 +00:00
|
|
|
return RtlNtStatusToDosError(status);
|
2002-11-10 13:44:48 +00:00
|
|
|
}
|
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* RegEnumValueW [ADVAPI32.@]
|
2003-07-12 00:03:42 +00:00
|
|
|
* @implemented
|
2005-05-09 01:43:41 +00:00
|
|
|
*
|
2005-05-04 15:53:54 +00:00
|
|
|
* PARAMS
|
|
|
|
* hkey [I] Handle to key to query
|
|
|
|
* index [I] Index of value to query
|
|
|
|
* value [O] Value string
|
|
|
|
* val_count [I/O] Size of value buffer (in wchars)
|
|
|
|
* reserved [I] Reserved
|
|
|
|
* type [O] Type code
|
|
|
|
* data [O] Value data
|
|
|
|
* count [I/O] Size of data buffer (in bytes)
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: ERROR_SUCCESS
|
|
|
|
* Failure: nonzero error code from Winerror.h
|
2003-07-12 00:03:42 +00:00
|
|
|
*/
|
|
|
|
LONG STDCALL
|
2005-05-04 15:53:54 +00:00
|
|
|
RegEnumValueW( HKEY hKey, DWORD index, LPWSTR value, PDWORD val_count,
|
|
|
|
PDWORD reserved, PDWORD type, LPBYTE data, PDWORD count )
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
2005-04-30 21:11:34 +00:00
|
|
|
HANDLE KeyHandle;
|
2005-05-04 15:53:54 +00:00
|
|
|
NTSTATUS status;
|
|
|
|
DWORD total_size;
|
|
|
|
char buffer[256], *buf_ptr = buffer;
|
|
|
|
KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
|
2005-11-11 11:59:56 +00:00
|
|
|
static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
|
2005-05-04 15:53:54 +00:00
|
|
|
|
|
|
|
//TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
|
|
|
|
// hkey, index, value, val_count, reserved, type, data, count );
|
|
|
|
|
|
|
|
/* NT only checks count, not val_count */
|
|
|
|
if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
status = MapDefaultKey (&KeyHandle, hKey);
|
|
|
|
if (!NT_SUCCESS(status))
|
2005-04-30 21:11:34 +00:00
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (status);
|
2005-04-30 21:11:34 +00:00
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
|
|
|
|
if (data) total_size += *count;
|
|
|
|
total_size = min( sizeof(buffer), total_size );
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
|
|
|
|
buffer, total_size, &total_size );
|
|
|
|
if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
|
2005-04-30 21:11:34 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (value || data)
|
|
|
|
{
|
|
|
|
/* retry with a dynamically allocated buffer */
|
|
|
|
while (status == STATUS_BUFFER_OVERFLOW)
|
|
|
|
{
|
|
|
|
if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
|
|
|
|
if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
|
2005-08-26 09:40:37 +00:00
|
|
|
{
|
|
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
goto done;
|
|
|
|
}
|
2005-05-04 15:53:54 +00:00
|
|
|
info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
|
|
|
|
status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
|
|
|
|
buf_ptr, total_size, &total_size );
|
|
|
|
}
|
2005-04-30 21:11:34 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (status) goto done;
|
2005-04-30 21:11:34 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (value)
|
|
|
|
{
|
|
|
|
if (info->NameLength/sizeof(WCHAR) >= *val_count)
|
|
|
|
{
|
|
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
|
|
goto overflow;
|
|
|
|
}
|
|
|
|
memcpy( value, info->Name, info->NameLength );
|
|
|
|
*val_count = info->NameLength / sizeof(WCHAR);
|
|
|
|
value[*val_count] = 0;
|
|
|
|
}
|
2005-04-30 21:11:34 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (data)
|
|
|
|
{
|
|
|
|
if (total_size - info->DataOffset > *count)
|
|
|
|
{
|
|
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
|
|
goto overflow;
|
|
|
|
}
|
|
|
|
memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
|
|
|
|
if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
|
|
|
|
{
|
|
|
|
/* if the type is REG_SZ and data is not 0-terminated
|
|
|
|
* and there is enough space in the buffer NT appends a \0 */
|
|
|
|
WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
|
|
|
|
if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else status = STATUS_SUCCESS;
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
overflow:
|
|
|
|
if (type) *type = info->Type;
|
|
|
|
if (count) *count = info->DataLength;
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
done:
|
|
|
|
if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-05-04 15:53:54 +00:00
|
|
|
return RtlNtStatusToDosError(status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegFlushKey
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2001-07-01 17:54:07 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegFlushKey(HKEY hKey)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2003-07-12 00:03:42 +00:00
|
|
|
NTSTATUS Status;
|
2003-03-24 13:44:15 +00:00
|
|
|
|
2001-07-01 17:54:07 +00:00
|
|
|
if (hKey == HKEY_PERFORMANCE_DATA)
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2003-03-24 13:44:15 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = NtFlushKey (KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
return ERROR_SUCCESS;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegGetKeySecurity
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
2004-09-13 08:51:40 +00:00
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-03-24 13:44:15 +00:00
|
|
|
LONG STDCALL
|
2004-09-13 08:51:40 +00:00
|
|
|
RegGetKeySecurity(HKEY hKey,
|
|
|
|
SECURITY_INFORMATION SecurityInformation,
|
|
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
|
|
LPDWORD lpcbSecurityDescriptor)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2004-09-13 08:51:40 +00:00
|
|
|
HANDLE KeyHandle;
|
2003-07-12 00:03:42 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
2004-09-13 08:51:40 +00:00
|
|
|
if (hKey == HKEY_PERFORMANCE_DATA)
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
|
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
}
|
|
|
|
|
2004-09-13 08:51:40 +00:00
|
|
|
Status = MapDefaultKey(&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2005-12-29 21:01:51 +00:00
|
|
|
#ifndef __REACTOS__
|
2004-09-13 11:41:26 +00:00
|
|
|
Status = NtQuerySecurityObject(KeyHandle,
|
2004-09-13 08:51:40 +00:00
|
|
|
SecurityInformation,
|
|
|
|
pSecurityDescriptor,
|
|
|
|
*lpcbSecurityDescriptor,
|
|
|
|
lpcbSecurityDescriptor);
|
2005-12-29 21:01:51 +00:00
|
|
|
#endif
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-16 05:17:06 +00:00
|
|
|
WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegLoadKeyA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-03-24 13:44:15 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegLoadKeyA (HKEY hKey,
|
|
|
|
LPCSTR lpSubKey,
|
|
|
|
LPCSTR lpFile)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2003-03-24 13:44:15 +00:00
|
|
|
UNICODE_STRING FileName;
|
|
|
|
UNICODE_STRING KeyName;
|
2004-02-22 14:26:07 +00:00
|
|
|
LONG ErrorCode;
|
2003-03-24 13:44:15 +00:00
|
|
|
|
|
|
|
RtlCreateUnicodeStringFromAsciiz (&KeyName,
|
|
|
|
(LPSTR)lpSubKey);
|
|
|
|
RtlCreateUnicodeStringFromAsciiz (&FileName,
|
|
|
|
(LPSTR)lpFile);
|
|
|
|
|
|
|
|
ErrorCode = RegLoadKeyW (hKey,
|
|
|
|
KeyName.Buffer,
|
|
|
|
FileName.Buffer);
|
|
|
|
|
|
|
|
RtlFreeUnicodeString (&FileName);
|
|
|
|
RtlFreeUnicodeString (&KeyName);
|
|
|
|
|
|
|
|
return ErrorCode;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-22 21:36:37 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegLoadKeyW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-07-22 21:36:37 +00:00
|
|
|
*/
|
2003-03-24 13:44:15 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegLoadKeyW (HKEY hKey,
|
|
|
|
LPCWSTR lpSubKey,
|
|
|
|
LPCWSTR lpFile)
|
1999-07-22 21:36:37 +00:00
|
|
|
{
|
2003-03-24 13:44:15 +00:00
|
|
|
OBJECT_ATTRIBUTES FileObjectAttributes;
|
|
|
|
OBJECT_ATTRIBUTES KeyObjectAttributes;
|
|
|
|
UNICODE_STRING FileName;
|
|
|
|
UNICODE_STRING KeyName;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
NTSTATUS Status;
|
2005-08-26 09:40:37 +00:00
|
|
|
LONG ErrorCode = ERROR_SUCCESS;
|
2003-03-24 13:44:15 +00:00
|
|
|
|
|
|
|
if (hKey == HKEY_PERFORMANCE_DATA)
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
|
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
}
|
2003-03-24 13:44:15 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2005-12-17 15:45:59 +00:00
|
|
|
if (!RtlDosPathNameToNtPathName_U (lpFile,
|
2003-03-24 13:44:15 +00:00
|
|
|
&FileName,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = ERROR_BAD_PATHNAME;
|
|
|
|
goto Cleanup;
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
|
|
|
goto Cleanup;
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
return ErrorCode;
|
1999-07-22 21:36:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegNotifyChangeKeyValue
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @unimplemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-03-24 13:44:15 +00:00
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegNotifyChangeKeyValue (HKEY hKey,
|
|
|
|
BOOL bWatchSubtree,
|
|
|
|
DWORD dwNotifyFilter,
|
|
|
|
HANDLE hEvent,
|
|
|
|
BOOL fAsynchronous)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2003-03-24 13:44:15 +00:00
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
NTSTATUS Status;
|
2005-08-26 09:40:37 +00:00
|
|
|
LONG ErrorCode = ERROR_SUCCESS;
|
2003-03-24 13:44:15 +00:00
|
|
|
|
|
|
|
if (hKey == HKEY_PERFORMANCE_DATA)
|
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
return ERROR_INVALID_HANDLE;
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (fAsynchronous == TRUE && hEvent == NULL)
|
2003-03-24 13:44:15 +00:00
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
return ErrorCode;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-05-05 15:39:27 +00:00
|
|
|
/************************************************************************
|
|
|
|
* RegOpenCurrentUser
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegOpenCurrentUser (IN REGSAM samDesired,
|
|
|
|
OUT PHKEY phkResult)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
|
|
|
|
(PHANDLE)phkResult);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* NOTE - don't set the last error code! just return the error! */
|
|
|
|
return RtlNtStatusToDosError(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegOpenKeyA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
2005-05-04 15:53:54 +00:00
|
|
|
* 20050503 Fireball - imported from WINE
|
|
|
|
*
|
2003-07-10 15:05:55 +00:00
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2001-07-01 17:54:07 +00:00
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegOpenKeyA (HKEY hKey,
|
|
|
|
LPCSTR lpSubKey,
|
|
|
|
PHKEY phkResult)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey, lpSubKey, phkResult);
|
2005-04-28 20:26:06 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (!lpSubKey || !*lpSubKey)
|
|
|
|
{
|
|
|
|
*phkResult = hKey;
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2005-05-05 00:07:27 +00:00
|
|
|
return RegOpenKeyExA( hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-22 21:36:37 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegOpenKeyW
|
1999-07-22 21:36:37 +00:00
|
|
|
*
|
2002-12-08 16:14:28 +00:00
|
|
|
* 19981101 Ariadne
|
|
|
|
* 19990525 EA
|
2005-05-04 15:53:54 +00:00
|
|
|
* 20050503 Fireball - imported from WINE
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-07-22 21:36:37 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegOpenKeyW (HKEY hKey,
|
|
|
|
LPCWSTR lpSubKey,
|
|
|
|
PHKEY phkResult)
|
1999-07-22 21:36:37 +00:00
|
|
|
{
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey, lpSubKey, phkResult);
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (!lpSubKey || !*lpSubKey)
|
|
|
|
{
|
|
|
|
*phkResult = hKey;
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2005-05-05 00:07:27 +00:00
|
|
|
return RegOpenKeyExW(hKey, lpSubKey, 0, MAXIMUM_ALLOWED, phkResult);
|
1999-07-22 21:36:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegOpenKeyExA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2001-07-01 17:54:07 +00:00
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegOpenKeyExA (HKEY hKey,
|
|
|
|
LPCSTR lpSubKey,
|
|
|
|
DWORD ulOptions,
|
|
|
|
REGSAM samDesired,
|
|
|
|
PHKEY phkResult)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2005-05-04 15:53:54 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyString;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
NTSTATUS Status;
|
2005-08-26 09:40:37 +00:00
|
|
|
LONG ErrorCode = ERROR_SUCCESS;
|
2001-07-01 17:54:07 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
|
2005-05-04 15:53:54 +00:00
|
|
|
hKey, lpSubKey, ulOptions, samDesired, phkResult);
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
Status = MapDefaultKey (&KeyHandle, hKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2005-05-04 15:53:54 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
RtlCreateUnicodeStringFromAsciiz (&SubKeyString, (LPSTR)lpSubKey);
|
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
|
|
|
&SubKeyString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
KeyHandle,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
|
|
|
|
RtlFreeUnicodeString (&SubKeyString);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
2005-05-04 15:53:54 +00:00
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-05-04 15:53:54 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
return ErrorCode;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegOpenKeyExW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-07-22 21:36:37 +00:00
|
|
|
*/
|
2001-07-01 17:54:07 +00:00
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegOpenKeyExW (HKEY hKey,
|
|
|
|
LPCWSTR lpSubKey,
|
|
|
|
DWORD ulOptions,
|
|
|
|
REGSAM samDesired,
|
|
|
|
PHKEY phkResult)
|
1999-07-22 21:36:37 +00:00
|
|
|
{
|
2005-05-04 15:53:54 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyString;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
NTSTATUS Status;
|
2005-08-26 09:40:37 +00:00
|
|
|
LONG ErrorCode = ERROR_SUCCESS;
|
2001-07-01 17:54:07 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
|
2005-05-04 15:53:54 +00:00
|
|
|
hKey, lpSubKey, ulOptions, samDesired, phkResult);
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
Status = MapDefaultKey (&KeyHandle, hKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2005-05-04 15:53:54 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
if (lpSubKey != NULL)
|
|
|
|
RtlInitUnicodeString (&SubKeyString, (LPWSTR)lpSubKey);
|
|
|
|
else
|
|
|
|
RtlInitUnicodeString (&SubKeyString, (LPWSTR)L"");
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2005-05-04 15:53:54 +00:00
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
|
|
|
&SubKeyString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
KeyHandle,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtOpenKey ((PHANDLE)phkResult, samDesired, &ObjectAttributes);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
2005-05-04 15:53:54 +00:00
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-05-04 15:53:54 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
return ErrorCode;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
/************************************************************************
|
|
|
|
* RegOpenUserClassesRoot
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegOpenUserClassesRoot (IN HANDLE hToken,
|
|
|
|
IN DWORD dwOptions,
|
|
|
|
IN REGSAM samDesired,
|
|
|
|
OUT PHKEY phkResult)
|
|
|
|
{
|
|
|
|
const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
|
|
|
|
const WCHAR UserClassesKeySuffix[] = L"_Classes";
|
|
|
|
PTOKEN_USER TokenUserData;
|
|
|
|
ULONG RequiredLength;
|
|
|
|
UNICODE_STRING UserSidString, UserClassesKeyRoot;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
NTSTATUS Status;
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
/* check parameters */
|
|
|
|
if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
|
|
|
|
{
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
/*
|
|
|
|
* Get the user sid from the token
|
|
|
|
*/
|
|
|
|
|
|
|
|
ReadTokenSid:
|
|
|
|
/* determine how much memory we need */
|
|
|
|
Status = NtQueryInformationToken(hToken,
|
|
|
|
TokenUser,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
&RequiredLength);
|
|
|
|
if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
|
|
|
|
{
|
|
|
|
/* NOTE - as opposed to all other registry functions windows does indeed
|
|
|
|
change the last error code in case the caller supplied a invalid
|
|
|
|
handle for example! */
|
2005-08-26 09:53:00 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2005-05-05 17:45:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TokenUserData = RtlAllocateHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
RequiredLength);
|
|
|
|
if (TokenUserData == NULL)
|
|
|
|
{
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* attempt to read the information */
|
|
|
|
Status = NtQueryInformationToken(hToken,
|
|
|
|
TokenUser,
|
|
|
|
TokenUserData,
|
|
|
|
RequiredLength,
|
|
|
|
&RequiredLength);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
RtlFreeHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
TokenUserData);
|
|
|
|
if (Status == STATUS_BUFFER_TOO_SMALL)
|
|
|
|
{
|
|
|
|
/* the information appears to have changed?! try again */
|
|
|
|
goto ReadTokenSid;
|
|
|
|
}
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
/* NOTE - as opposed to all other registry functions windows does indeed
|
|
|
|
change the last error code in case the caller supplied a invalid
|
|
|
|
handle for example! */
|
2005-08-26 09:53:00 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2005-05-05 17:45:00 +00:00
|
|
|
}
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
/*
|
|
|
|
* Build the absolute path for the user's registry in the form
|
|
|
|
* "\Registry\User\<SID>_Classes"
|
|
|
|
*/
|
|
|
|
Status = RtlConvertSidToUnicodeString(&UserSidString,
|
|
|
|
TokenUserData->User.Sid,
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
/* we don't need the user data anymore, free it */
|
|
|
|
RtlFreeHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
TokenUserData);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return RtlNtStatusToDosError (Status);
|
|
|
|
}
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
/* allocate enough memory for the entire key string */
|
|
|
|
UserClassesKeyRoot.Length = 0;
|
|
|
|
UserClassesKeyRoot.MaximumLength = UserSidString.Length +
|
|
|
|
sizeof(UserClassesKeyPrefix) +
|
|
|
|
sizeof(UserClassesKeySuffix);
|
|
|
|
UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
|
|
|
|
0,
|
|
|
|
UserClassesKeyRoot.MaximumLength);
|
|
|
|
if (UserClassesKeyRoot.Buffer == NULL)
|
|
|
|
{
|
|
|
|
RtlFreeUnicodeString(&UserSidString);
|
|
|
|
return RtlNtStatusToDosError (Status);
|
|
|
|
}
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
/* build the string */
|
|
|
|
RtlAppendUnicodeToString(&UserClassesKeyRoot,
|
|
|
|
UserClassesKeyPrefix);
|
|
|
|
RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
|
|
|
|
&UserSidString);
|
|
|
|
RtlAppendUnicodeToString(&UserClassesKeyRoot,
|
|
|
|
UserClassesKeySuffix);
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
|
2005-05-05 17:45:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Open the key
|
|
|
|
*/
|
|
|
|
|
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
|
|
|
&UserClassesKeyRoot,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
Status = NtOpenKey((PHANDLE)phkResult,
|
|
|
|
samDesired,
|
|
|
|
&ObjectAttributes);
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
RtlFreeUnicodeString(&UserSidString);
|
|
|
|
RtlFreeUnicodeString(&UserClassesKeyRoot);
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return RtlNtStatusToDosError (Status);
|
|
|
|
}
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 17:45:00 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
/************************************************************************
|
|
|
|
* 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);
|
2003-08-30 14:46:29 +00:00
|
|
|
AnsiString.MaximumLength = *lpcbClass;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ErrorCode = RegQueryInfoKeyW (hKey,
|
|
|
|
UnicodeString.Buffer,
|
|
|
|
lpcbClass,
|
|
|
|
lpReserved,
|
|
|
|
lpcSubKeys,
|
|
|
|
lpcbMaxSubKeyLen,
|
|
|
|
lpcbMaxClassLen,
|
|
|
|
lpcValues,
|
|
|
|
lpcbMaxValueNameLen,
|
|
|
|
lpcbMaxValueLen,
|
|
|
|
lpcbSecurityDescriptor,
|
|
|
|
lpftLastWriteTime);
|
|
|
|
if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
|
|
|
|
{
|
|
|
|
AnsiString.Buffer = lpClass;
|
2003-08-30 14:46:29 +00:00
|
|
|
AnsiString.Length = 0;
|
|
|
|
UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
|
2003-07-12 00:03:42 +00:00
|
|
|
RtlUnicodeStringToAnsiString (&AnsiString,
|
|
|
|
&UnicodeString,
|
|
|
|
FALSE);
|
|
|
|
*lpcbClass = AnsiString.Length;
|
2003-08-30 14:46:29 +00:00
|
|
|
lpClass[AnsiString.Length] = 0;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ErrorCode;
|
1999-07-22 21:36:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegQueryInfoKeyW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-07-22 21:36:37 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
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)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2001-09-01 15:36:45 +00:00
|
|
|
KEY_FULL_INFORMATION FullInfoBuffer;
|
|
|
|
PKEY_FULL_INFORMATION FullInfo;
|
|
|
|
ULONG FullInfoSize;
|
2004-07-03 17:40:27 +00:00
|
|
|
ULONG ClassLength = 0;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2001-09-01 15:36:45 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG Length;
|
2005-05-05 16:15:08 +00:00
|
|
|
LONG ErrorCode = ERROR_SUCCESS;
|
2001-09-01 15:36:45 +00:00
|
|
|
|
2003-03-24 13:44:15 +00:00
|
|
|
if ((lpClass) && (!lpcbClass))
|
|
|
|
{
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
2001-09-01 15:36:45 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
|
|
|
hKey);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
2001-09-01 15:36:45 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (lpClass != NULL)
|
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
if (*lpcbClass > 0)
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
|
|
|
ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
|
2003-08-30 14:46:29 +00:00
|
|
|
}
|
|
|
|
else
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
ClassLength = 0;
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
|
|
|
|
FullInfo = RtlAllocateHeap (ProcessHeap,
|
2003-07-12 00:03:42 +00:00
|
|
|
0,
|
|
|
|
FullInfoSize);
|
|
|
|
if (FullInfo == NULL)
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = ERROR_OUTOFMEMORY;
|
|
|
|
goto Cleanup;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
FullInfo->ClassLength = ClassLength;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FullInfoSize = sizeof(KEY_FULL_INFORMATION);
|
|
|
|
FullInfo = &FullInfoBuffer;
|
2003-08-30 14:46:29 +00:00
|
|
|
FullInfo->ClassLength = 0;
|
2002-12-08 16:14:28 +00:00
|
|
|
}
|
2001-09-01 15:36:45 +00:00
|
|
|
FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
|
1999-03-12 06:29:00 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = NtQueryKey (KeyHandle,
|
|
|
|
KeyFullInformation,
|
|
|
|
FullInfo,
|
|
|
|
FullInfoSize,
|
|
|
|
&Length);
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("NtQueryKey() returned status 0x%X\n", Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2004-02-22 14:26:07 +00:00
|
|
|
if (lpClass != NULL)
|
|
|
|
{
|
|
|
|
RtlFreeHeap (ProcessHeap,
|
|
|
|
0,
|
|
|
|
FullInfo);
|
|
|
|
}
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
|
|
|
goto Cleanup;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("SubKeys %d\n", FullInfo->SubKeys);
|
2004-02-22 14:26:07 +00:00
|
|
|
if (lpcSubKeys != NULL)
|
|
|
|
{
|
|
|
|
*lpcSubKeys = FullInfo->SubKeys;
|
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
|
2004-02-22 14:26:07 +00:00
|
|
|
if (lpcbMaxSubKeyLen != NULL)
|
|
|
|
{
|
|
|
|
*lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
|
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
|
2004-02-22 14:26:07 +00:00
|
|
|
if (lpcbMaxClassLen != NULL)
|
|
|
|
{
|
|
|
|
*lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
|
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("Values %lu\n", FullInfo->Values);
|
2004-02-22 14:26:07 +00:00
|
|
|
if (lpcValues != NULL)
|
|
|
|
{
|
|
|
|
*lpcValues = FullInfo->Values;
|
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
|
2004-02-22 14:26:07 +00:00
|
|
|
if (lpcbMaxValueNameLen != NULL)
|
|
|
|
{
|
|
|
|
*lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
|
|
|
|
}
|
2003-08-30 14:46:29 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
|
2004-02-22 14:26:07 +00:00
|
|
|
if (lpcbMaxValueLen != NULL)
|
|
|
|
{
|
|
|
|
*lpcbMaxValueLen = FullInfo->MaxValueDataLen;
|
|
|
|
}
|
2005-12-29 20:31:22 +00:00
|
|
|
#ifndef __REACTOS__
|
2004-02-22 14:26:07 +00:00
|
|
|
if (lpcbSecurityDescriptor != NULL)
|
|
|
|
{
|
2004-09-13 14:42:37 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
|
|
|
goto Cleanup;
|
2004-09-13 14:42:37 +00:00
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
}
|
2005-12-29 20:31:22 +00:00
|
|
|
#endif
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2004-02-22 14:26:07 +00:00
|
|
|
if (lpftLastWriteTime != NULL)
|
|
|
|
{
|
|
|
|
lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
|
|
|
|
lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (lpClass != NULL)
|
|
|
|
{
|
2004-02-22 14:26:07 +00:00
|
|
|
if (FullInfo->ClassLength > ClassLength)
|
|
|
|
{
|
|
|
|
ErrorCode = ERROR_BUFFER_OVERFLOW;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RtlCopyMemory (lpClass,
|
|
|
|
FullInfo->Class,
|
|
|
|
FullInfo->ClassLength);
|
|
|
|
*lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
|
|
|
|
lpClass[*lpcbClass] = 0;
|
|
|
|
}
|
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
RtlFreeHeap (ProcessHeap,
|
2004-02-22 14:26:07 +00:00
|
|
|
0,
|
2003-07-12 00:03:42 +00:00
|
|
|
FullInfo);
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
return ErrorCode;
|
2002-11-10 13:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegQueryMultipleValuesA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
2004-10-10 10:43:23 +00:00
|
|
|
* @implemented
|
2002-11-10 13:44:48 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegQueryMultipleValuesA (HKEY hKey,
|
|
|
|
PVALENTA val_list,
|
|
|
|
DWORD num_vals,
|
|
|
|
LPSTR lpValueBuf,
|
|
|
|
LPDWORD ldwTotsize)
|
2002-11-10 13:44:48 +00:00
|
|
|
{
|
2004-10-10 10:43:23 +00:00
|
|
|
ULONG i;
|
|
|
|
DWORD maxBytes = *ldwTotsize;
|
|
|
|
LPSTR bufptr = (LPSTR)lpValueBuf;
|
|
|
|
LONG ErrorCode;
|
|
|
|
|
|
|
|
if (maxBytes >= (1024*1024))
|
|
|
|
return ERROR_TRANSFER_TOO_LONG;
|
|
|
|
|
|
|
|
*ldwTotsize = 0;
|
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
|
2004-10-10 10:43:23 +00:00
|
|
|
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,
|
2004-12-25 11:22:37 +00:00
|
|
|
(LPBYTE)bufptr,
|
2004-10-10 10:43:23 +00:00
|
|
|
&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;
|
2002-11-10 13:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegQueryMultipleValuesW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
2003-07-21 00:32:23 +00:00
|
|
|
* @implemented
|
2002-11-10 13:44:48 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegQueryMultipleValuesW (HKEY hKey,
|
|
|
|
PVALENTW val_list,
|
|
|
|
DWORD num_vals,
|
|
|
|
LPWSTR lpValueBuf,
|
|
|
|
LPDWORD ldwTotsize)
|
2002-11-10 13:44:48 +00:00
|
|
|
{
|
2003-07-24 19:00:42 +00:00
|
|
|
ULONG i;
|
2003-07-21 00:32:23 +00:00
|
|
|
DWORD maxBytes = *ldwTotsize;
|
|
|
|
LPSTR bufptr = (LPSTR)lpValueBuf;
|
2004-02-22 14:26:07 +00:00
|
|
|
LONG ErrorCode;
|
2003-07-21 00:32:23 +00:00
|
|
|
|
2004-02-22 14:26:07 +00:00
|
|
|
if (maxBytes >= (1024*1024))
|
2003-07-21 00:32:23 +00:00
|
|
|
return ERROR_TRANSFER_TOO_LONG;
|
|
|
|
|
|
|
|
*ldwTotsize = 0;
|
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
|
2004-02-22 14:26:07 +00:00
|
|
|
hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
|
2003-07-21 00:32:23 +00:00
|
|
|
|
2004-10-10 10:43:23 +00:00
|
|
|
for (i = 0; i < num_vals; i++)
|
2003-07-21 00:32:23 +00:00
|
|
|
{
|
2004-02-22 14:26:07 +00:00
|
|
|
val_list[i].ve_valuelen = 0;
|
|
|
|
ErrorCode = RegQueryValueExW (hKey,
|
|
|
|
val_list[i].ve_valuename,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&val_list[i].ve_valuelen);
|
2004-06-17 09:07:12 +00:00
|
|
|
if (ErrorCode != ERROR_SUCCESS)
|
2003-07-21 00:32:23 +00:00
|
|
|
{
|
2004-02-22 14:26:07 +00:00
|
|
|
return ErrorCode;
|
2003-07-21 00:32:23 +00:00
|
|
|
}
|
|
|
|
|
2004-06-17 09:07:12 +00:00
|
|
|
if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
|
2003-07-21 00:32:23 +00:00
|
|
|
{
|
2004-02-22 14:26:07 +00:00
|
|
|
ErrorCode = RegQueryValueExW (hKey,
|
|
|
|
val_list[i].ve_valuename,
|
|
|
|
NULL,
|
|
|
|
&val_list[i].ve_type,
|
2004-12-25 11:22:37 +00:00
|
|
|
(LPBYTE)bufptr,
|
2004-02-22 14:26:07 +00:00
|
|
|
&val_list[i].ve_valuelen);
|
|
|
|
if (ErrorCode != ERROR_SUCCESS)
|
2003-07-21 00:32:23 +00:00
|
|
|
{
|
2004-02-22 14:26:07 +00:00
|
|
|
return ErrorCode;
|
2003-07-21 00:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
|
|
|
|
|
|
|
|
bufptr += val_list[i].ve_valuelen;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ldwTotsize += val_list[i].ve_valuelen;
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
|
|
|
|
return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
|
2002-11-10 13:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegQueryValueExW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2002-11-10 13:44:48 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegQueryValueExW (HKEY hKey,
|
|
|
|
LPCWSTR lpValueName,
|
|
|
|
LPDWORD lpReserved,
|
|
|
|
LPDWORD lpType,
|
|
|
|
LPBYTE lpData,
|
|
|
|
LPDWORD lpcbData)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2002-12-08 16:14:28 +00:00
|
|
|
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
|
|
|
|
UNICODE_STRING ValueName;
|
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG BufferSize;
|
|
|
|
ULONG ResultSize;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2005-05-05 16:15:08 +00:00
|
|
|
LONG ErrorCode = ERROR_SUCCESS;
|
2004-07-17 16:09:07 +00:00
|
|
|
ULONG MaxCopy = lpcbData != NULL && lpData != NULL ? *lpcbData : 0;
|
2001-09-01 15:36:45 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
|
2003-07-12 00:03:42 +00:00
|
|
|
hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
|
|
|
|
|
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
|
|
|
hKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lpData != NULL && lpcbData == NULL)
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = ERROR_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RtlInitUnicodeString (&ValueName,
|
|
|
|
lpValueName);
|
2004-10-10 10:10:52 +00:00
|
|
|
BufferSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MaxCopy;
|
2003-08-30 14:46:29 +00:00
|
|
|
ValueInfo = RtlAllocateHeap (ProcessHeap,
|
2003-12-24 21:23:03 +00:00
|
|
|
0,
|
2003-07-12 00:03:42 +00:00
|
|
|
BufferSize);
|
|
|
|
if (ValueInfo == NULL)
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = ERROR_OUTOFMEMORY;
|
|
|
|
goto Cleanup;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
2005-05-05 00:07:27 +00:00
|
|
|
Status = NtQueryValueKey (KeyHandle,
|
2003-07-12 00:03:42 +00:00
|
|
|
&ValueName,
|
|
|
|
KeyValuePartialInformation,
|
|
|
|
ValueInfo,
|
|
|
|
BufferSize,
|
|
|
|
&ResultSize);
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("Status 0x%X\n", Status);
|
2004-10-08 21:19:12 +00:00
|
|
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
|
|
|
/* Return ERROR_SUCCESS and the buffer space needed for a successful call */
|
2003-12-28 08:47:28 +00:00
|
|
|
MaxCopy = 0;
|
2003-12-28 09:28:39 +00:00
|
|
|
ErrorCode = lpData ? ERROR_MORE_DATA : ERROR_SUCCESS;
|
2001-09-01 15:36:45 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
else if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
2003-12-28 08:47:28 +00:00
|
|
|
MaxCopy = 0;
|
2004-04-01 13:53:08 +00:00
|
|
|
if (lpcbData != NULL)
|
|
|
|
{
|
2004-10-10 10:10:52 +00:00
|
|
|
ResultSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + *lpcbData;
|
2004-04-01 13:53:08 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2003-12-28 08:47:28 +00:00
|
|
|
|
|
|
|
if (lpType != NULL)
|
2003-07-12 00:03:42 +00:00
|
|
|
{
|
2003-12-28 08:47:28 +00:00
|
|
|
*lpType = ValueInfo->Type;
|
2002-11-10 13:44:48 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2004-04-01 13:53:08 +00:00
|
|
|
if (NT_SUCCESS(Status) && lpData != NULL)
|
|
|
|
{
|
|
|
|
RtlMoveMemory (lpData,
|
|
|
|
ValueInfo->Data,
|
|
|
|
min(ValueInfo->DataLength, MaxCopy));
|
|
|
|
}
|
2003-12-28 08:47:28 +00:00
|
|
|
|
|
|
|
if ((ValueInfo->Type == REG_SZ) ||
|
|
|
|
(ValueInfo->Type == REG_MULTI_SZ) ||
|
|
|
|
(ValueInfo->Type == REG_EXPAND_SZ))
|
|
|
|
{
|
2004-04-01 13:53:08 +00:00
|
|
|
if (lpData != NULL && MaxCopy > ValueInfo->DataLength)
|
|
|
|
{
|
|
|
|
((PWSTR)lpData)[ValueInfo->DataLength / sizeof(WCHAR)] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lpcbData != NULL)
|
|
|
|
{
|
2004-10-10 10:10:52 +00:00
|
|
|
*lpcbData = (ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]));
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("(string) Returning Size: %lu\n", *lpcbData);
|
2004-04-01 13:53:08 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2003-12-28 08:47:28 +00:00
|
|
|
else
|
2004-04-01 13:53:08 +00:00
|
|
|
{
|
|
|
|
if (lpcbData != NULL)
|
|
|
|
{
|
2004-10-10 10:10:52 +00:00
|
|
|
*lpcbData = ResultSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("(other) Returning Size: %lu\n", *lpcbData);
|
2004-04-01 13:53:08 +00:00
|
|
|
}
|
2003-12-28 08:47:28 +00:00
|
|
|
}
|
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("Type %d Size %d\n", ValueInfo->Type, ValueInfo->DataLength);
|
2003-12-28 08:47:28 +00:00
|
|
|
|
2003-08-30 14:46:29 +00:00
|
|
|
RtlFreeHeap (ProcessHeap,
|
2003-07-12 00:03:42 +00:00
|
|
|
0,
|
|
|
|
ValueInfo);
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
return ErrorCode;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegQueryValueExA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
2003-10-14 18:18:27 +00:00
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2004-02-22 14:26:07 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegQueryValueExA (HKEY hKey,
|
|
|
|
LPCSTR lpValueName,
|
|
|
|
LPDWORD lpReserved,
|
|
|
|
LPDWORD lpType,
|
|
|
|
LPBYTE lpData,
|
|
|
|
LPDWORD lpcbData)
|
1999-07-22 21:36:37 +00:00
|
|
|
{
|
2001-09-01 15:36:45 +00:00
|
|
|
UNICODE_STRING ValueName;
|
|
|
|
UNICODE_STRING ValueData;
|
|
|
|
ANSI_STRING AnsiString;
|
|
|
|
LONG ErrorCode;
|
2003-12-24 21:51:38 +00:00
|
|
|
DWORD Length;
|
2003-12-28 23:22:30 +00:00
|
|
|
DWORD Type;
|
2003-10-14 18:18:27 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
|
2004-12-18 22:54:37 +00:00
|
|
|
hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
|
|
|
|
|
2004-04-01 13:53:08 +00:00
|
|
|
if (lpData != NULL && lpcbData == NULL)
|
2003-10-14 18:18:27 +00:00
|
|
|
{
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lpData)
|
|
|
|
{
|
2004-12-02 14:08:27 +00:00
|
|
|
ValueData.Length = 0;
|
|
|
|
ValueData.MaximumLength = (*lpcbData + 1) * sizeof(WCHAR);
|
2004-02-22 14:26:07 +00:00
|
|
|
ValueData.Buffer = RtlAllocateHeap (ProcessHeap,
|
|
|
|
0,
|
|
|
|
ValueData.MaximumLength);
|
2003-10-14 18:18:27 +00:00
|
|
|
if (!ValueData.Buffer)
|
2004-04-01 13:53:08 +00:00
|
|
|
{
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
}
|
2003-10-14 18:18:27 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ValueData.Buffer = NULL;
|
2003-12-28 23:22:30 +00:00
|
|
|
ValueData.Length = 0;
|
|
|
|
ValueData.MaximumLength = 0;
|
2001-09-01 15:36:45 +00:00
|
|
|
}
|
2003-10-14 18:18:27 +00:00
|
|
|
|
2004-02-22 14:26:07 +00:00
|
|
|
RtlCreateUnicodeStringFromAsciiz (&ValueName,
|
|
|
|
(LPSTR)lpValueName);
|
2003-10-14 18:18:27 +00:00
|
|
|
|
2004-12-02 14:08:27 +00:00
|
|
|
Length = (lpcbData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
|
2004-02-22 14:26:07 +00:00
|
|
|
ErrorCode = RegQueryValueExW (hKey,
|
|
|
|
ValueName.Buffer,
|
|
|
|
lpReserved,
|
|
|
|
&Type,
|
2004-12-02 14:08:27 +00:00
|
|
|
(lpData == NULL) ? NULL : (LPBYTE)ValueData.Buffer,
|
|
|
|
&Length);
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("ErrorCode %lu\n", ErrorCode);
|
2004-11-22 16:11:25 +00:00
|
|
|
RtlFreeUnicodeString(&ValueName);
|
2004-02-22 14:26:07 +00:00
|
|
|
|
2004-04-01 13:53:08 +00:00
|
|
|
if (ErrorCode == ERROR_SUCCESS ||
|
|
|
|
ErrorCode == ERROR_MORE_DATA)
|
2003-10-14 18:18:27 +00:00
|
|
|
{
|
2004-04-01 13:53:08 +00:00
|
|
|
if (lpType != NULL)
|
|
|
|
{
|
|
|
|
*lpType = Type;
|
|
|
|
}
|
|
|
|
|
2003-12-13 23:59:45 +00:00
|
|
|
if ((Type == REG_SZ) || (Type == REG_MULTI_SZ) || (Type == REG_EXPAND_SZ))
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2004-04-01 13:53:08 +00:00
|
|
|
if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
|
|
|
|
{
|
|
|
|
RtlInitAnsiString(&AnsiString, NULL);
|
2004-12-25 11:22:37 +00:00
|
|
|
AnsiString.Buffer = (LPSTR)lpData;
|
2004-04-01 13:53:08 +00:00
|
|
|
AnsiString.MaximumLength = *lpcbData;
|
|
|
|
ValueData.Length = Length;
|
|
|
|
ValueData.MaximumLength = ValueData.Length + sizeof(WCHAR);
|
|
|
|
RtlUnicodeStringToAnsiString(&AnsiString, &ValueData, FALSE);
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
Length = Length / sizeof(WCHAR);
|
|
|
|
}
|
2004-12-02 14:08:27 +00:00
|
|
|
else if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
2004-12-26 23:09:51 +00:00
|
|
|
if (*lpcbData < Length)
|
|
|
|
{
|
|
|
|
ErrorCode = ERROR_MORE_DATA;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RtlMoveMemory(lpData, ValueData.Buffer, Length);
|
|
|
|
}
|
2004-02-22 14:26:07 +00:00
|
|
|
}
|
2003-12-29 23:04:55 +00:00
|
|
|
|
2004-04-01 13:53:08 +00:00
|
|
|
if (lpcbData != NULL)
|
|
|
|
{
|
|
|
|
*lpcbData = Length;
|
|
|
|
}
|
2003-12-29 23:04:55 +00:00
|
|
|
}
|
2003-10-14 18:18:27 +00:00
|
|
|
|
2004-04-01 13:53:08 +00:00
|
|
|
if (ValueData.Buffer != NULL)
|
2003-10-14 18:18:27 +00:00
|
|
|
{
|
|
|
|
RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
|
|
|
|
}
|
|
|
|
|
2001-09-01 15:36:45 +00:00
|
|
|
return ErrorCode;
|
1999-07-22 21:36:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-08 22:55:14 +00:00
|
|
|
/************************************************************************
|
2003-07-12 00:03:42 +00:00
|
|
|
* RegQueryValueA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2000-09-08 22:55:14 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegQueryValueA (HKEY hKey,
|
|
|
|
LPCSTR lpSubKey,
|
|
|
|
LPSTR lpValue,
|
|
|
|
PLONG lpcbValue)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
WCHAR SubKeyNameBuffer[MAX_PATH+1];
|
|
|
|
UNICODE_STRING SubKeyName;
|
|
|
|
UNICODE_STRING Value;
|
|
|
|
ANSI_STRING AnsiString;
|
|
|
|
LONG ValueSize;
|
|
|
|
LONG ErrorCode;
|
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
|
2004-12-18 22:54:37 +00:00
|
|
|
hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (lpValue != NULL &&
|
|
|
|
lpcbValue == NULL)
|
|
|
|
{
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
2002-12-08 16:14:28 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
|
|
|
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;
|
2003-08-30 14:46:29 +00:00
|
|
|
Value.Buffer = RtlAllocateHeap (ProcessHeap,
|
2003-07-12 00:03:42 +00:00
|
|
|
0,
|
|
|
|
ValueSize);
|
|
|
|
if (Value.Buffer == NULL)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
RtlFreeHeap (ProcessHeap,
|
2003-07-12 00:03:42 +00:00
|
|
|
0,
|
|
|
|
Value.Buffer);
|
|
|
|
}
|
|
|
|
|
2002-11-10 13:44:48 +00:00
|
|
|
return ErrorCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
2003-07-12 00:03:42 +00:00
|
|
|
* RegQueryValueW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2002-11-10 13:44:48 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegQueryValueW (HKEY hKey,
|
|
|
|
LPCWSTR lpSubKey,
|
|
|
|
LPWSTR lpValue,
|
|
|
|
PLONG lpcbValue)
|
2002-11-10 13:44:48 +00:00
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyString;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2003-07-12 00:03:42 +00:00
|
|
|
HANDLE RealKey;
|
2002-11-10 13:44:48 +00:00
|
|
|
LONG ErrorCode;
|
2003-07-12 00:03:42 +00:00
|
|
|
BOOL CloseRealKey;
|
|
|
|
NTSTATUS Status;
|
2002-11-10 13:44:48 +00:00
|
|
|
|
2005-08-16 05:17:06 +00:00
|
|
|
TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
|
2004-12-18 22:54:37 +00:00
|
|
|
hKey, lpSubKey, lpValue, lpcbValue ? *lpcbValue : 0);
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2002-11-10 13:44:48 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
|
|
|
if (lpSubKey != NULL &&
|
|
|
|
wcslen(lpSubKey) != 0)
|
|
|
|
{
|
|
|
|
RtlInitUnicodeString (&SubKeyString,
|
|
|
|
(LPWSTR)lpSubKey);
|
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
|
|
|
&SubKeyString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
KeyHandle,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenKey (&RealKey,
|
2005-05-05 00:07:27 +00:00
|
|
|
KEY_QUERY_VALUE,
|
2003-07-12 00:03:42 +00:00
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
|
|
|
goto Cleanup;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
CloseRealKey = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RealKey = hKey;
|
|
|
|
CloseRealKey = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorCode = RegQueryValueExW (RealKey,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
(LPBYTE)lpValue,
|
|
|
|
(LPDWORD)lpcbValue);
|
|
|
|
if (CloseRealKey)
|
|
|
|
{
|
|
|
|
NtClose (RealKey);
|
|
|
|
}
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2001-09-01 15:36:45 +00:00
|
|
|
return ErrorCode;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegReplaceKeyA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
2003-07-21 00:32:23 +00:00
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegReplaceKeyA (HKEY hKey,
|
|
|
|
LPCSTR lpSubKey,
|
|
|
|
LPCSTR lpNewFile,
|
|
|
|
LPCSTR lpOldFile)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2004-02-22 14:26:07 +00:00
|
|
|
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;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-08 22:55:14 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegReplaceKeyW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @unimplemented
|
2000-09-08 22:55:14 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegReplaceKeyW (HKEY hKey,
|
|
|
|
LPCWSTR lpSubKey,
|
|
|
|
LPCWSTR lpNewFile,
|
|
|
|
LPCWSTR lpOldFile)
|
2000-09-08 22:55:14 +00:00
|
|
|
{
|
2004-02-25 14:25:11 +00:00
|
|
|
OBJECT_ATTRIBUTES KeyObjectAttributes;
|
|
|
|
OBJECT_ATTRIBUTES NewObjectAttributes;
|
|
|
|
OBJECT_ATTRIBUTES OldObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyName;
|
|
|
|
UNICODE_STRING NewFileName;
|
|
|
|
UNICODE_STRING OldFileName;
|
|
|
|
BOOLEAN CloseRealKey;
|
|
|
|
HANDLE RealKeyHandle;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
NTSTATUS Status;
|
2005-08-26 09:40:37 +00:00
|
|
|
LONG ErrorCode = ERROR_SUCCESS;
|
2004-02-25 14:25:11 +00:00
|
|
|
|
|
|
|
if (hKey == HKEY_PERFORMANCE_DATA)
|
|
|
|
{
|
|
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2004-02-25 14:25:11 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2004-02-25 14:25:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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,
|
2005-05-05 00:07:27 +00:00
|
|
|
MAXIMUM_ALLOWED,
|
2004-02-25 14:25:11 +00:00
|
|
|
&KeyObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
|
|
|
goto Cleanup;
|
2004-02-25 14:25:11 +00:00
|
|
|
}
|
|
|
|
CloseRealKey = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RealKeyHandle = KeyHandle;
|
|
|
|
CloseRealKey = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert new file name */
|
2005-12-17 15:45:59 +00:00
|
|
|
if (!RtlDosPathNameToNtPathName_U (lpNewFile,
|
2004-02-25 14:25:11 +00:00
|
|
|
&NewFileName,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
if (CloseRealKey)
|
|
|
|
{
|
|
|
|
NtClose (RealKeyHandle);
|
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = ERROR_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
2004-02-25 14:25:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
InitializeObjectAttributes (&NewObjectAttributes,
|
|
|
|
&NewFileName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* Convert old file name */
|
2005-12-17 15:45:59 +00:00
|
|
|
if (!RtlDosPathNameToNtPathName_U (lpOldFile,
|
2004-02-25 14:25:11 +00:00
|
|
|
&OldFileName,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
RtlFreeUnicodeString (&NewFileName);
|
|
|
|
if (CloseRealKey)
|
|
|
|
{
|
|
|
|
NtClose (RealKeyHandle);
|
|
|
|
}
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = ERROR_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
2004-02-25 14:25:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2004-02-25 14:25:11 +00:00
|
|
|
}
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
return ErrorCode;
|
2000-09-08 22:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegRestoreKeyA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
2003-07-21 00:32:23 +00:00
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegRestoreKeyA (HKEY hKey,
|
|
|
|
LPCSTR lpFile,
|
|
|
|
DWORD dwFlags)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2004-02-22 14:26:07 +00:00
|
|
|
UNICODE_STRING FileName;
|
|
|
|
LONG ErrorCode;
|
|
|
|
|
|
|
|
RtlCreateUnicodeStringFromAsciiz (&FileName,
|
|
|
|
(PCSZ)lpFile);
|
|
|
|
|
|
|
|
ErrorCode = RegRestoreKeyW (hKey,
|
|
|
|
FileName.Buffer,
|
|
|
|
dwFlags);
|
2003-07-21 00:32:23 +00:00
|
|
|
|
2004-02-22 14:26:07 +00:00
|
|
|
RtlFreeUnicodeString (&FileName);
|
|
|
|
|
|
|
|
return ErrorCode;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-08 22:55:14 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegRestoreKeyW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
2004-02-22 14:26:07 +00:00
|
|
|
* @implemented
|
2000-09-08 22:55:14 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegRestoreKeyW (HKEY hKey,
|
|
|
|
LPCWSTR lpFile,
|
|
|
|
DWORD dwFlags)
|
2000-09-08 22:55:14 +00:00
|
|
|
{
|
2004-02-22 14:26:07 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
UNICODE_STRING FileName;
|
|
|
|
HANDLE FileHandle;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
if (hKey == HKEY_PERFORMANCE_DATA)
|
|
|
|
{
|
|
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2004-02-22 14:26:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2004-02-22 14:26:07 +00:00
|
|
|
}
|
|
|
|
|
2005-12-17 15:45:59 +00:00
|
|
|
if (!RtlDosPathNameToNtPathName_U (lpFile,
|
2004-02-22 14:26:07 +00:00
|
|
|
&FileName,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
2004-02-22 14:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
goto Cleanup;
|
2004-02-22 14:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status = NtRestoreKey (KeyHandle,
|
|
|
|
FileHandle,
|
|
|
|
(ULONG)dwFlags);
|
|
|
|
NtClose (FileHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2004-02-22 14:26:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2004-02-22 14:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
2000-09-08 22:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-03-24 13:44:15 +00:00
|
|
|
/************************************************************************
|
|
|
|
* RegSaveKeyA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
2003-07-21 00:32:23 +00:00
|
|
|
* @implemented
|
2003-03-24 13:44:15 +00:00
|
|
|
*/
|
|
|
|
LONG STDCALL
|
2004-02-25 14:25:11 +00:00
|
|
|
RegSaveKeyA (HKEY hKey,
|
|
|
|
LPCSTR lpFile,
|
|
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
2003-03-24 13:44:15 +00:00
|
|
|
{
|
|
|
|
UNICODE_STRING FileName;
|
|
|
|
LONG ErrorCode;
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
RtlCreateUnicodeStringFromAsciiz (&FileName,
|
|
|
|
(LPSTR)lpFile);
|
|
|
|
ErrorCode = RegSaveKeyW (hKey,
|
|
|
|
FileName.Buffer,
|
|
|
|
lpSecurityAttributes);
|
|
|
|
RtlFreeUnicodeString (&FileName);
|
|
|
|
|
|
|
|
return ErrorCode;
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-08 22:55:14 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegSaveKeyW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2000-09-08 22:55:14 +00:00
|
|
|
*/
|
2001-09-03 23:11:59 +00:00
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegSaveKeyW (HKEY hKey,
|
|
|
|
LPCWSTR lpFile,
|
|
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2001-09-03 23:11:59 +00:00
|
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
2004-02-22 14:26:07 +00:00
|
|
|
UNICODE_STRING FileName;
|
2001-09-03 23:11:59 +00:00
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
HANDLE FileHandle;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2001-09-03 23:11:59 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
2003-03-24 13:44:15 +00:00
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2005-12-17 15:45:59 +00:00
|
|
|
if (!RtlDosPathNameToNtPathName_U (lpFile,
|
2004-02-22 14:26:07 +00:00
|
|
|
&FileName,
|
2003-03-24 13:44:15 +00:00
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2001-09-03 23:11:59 +00:00
|
|
|
if (lpSecurityAttributes != NULL)
|
2003-03-24 13:44:15 +00:00
|
|
|
{
|
2002-12-08 16:14:28 +00:00
|
|
|
SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
2004-02-22 14:26:07 +00:00
|
|
|
&FileName,
|
2003-03-24 13:44:15 +00:00
|
|
|
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);
|
2004-02-22 14:26:07 +00:00
|
|
|
RtlFreeUnicodeString (&FileName);
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
goto Cleanup;
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
Status = NtSaveKey (KeyHandle,
|
|
|
|
FileHandle);
|
|
|
|
NtClose (FileHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-03-24 13:44:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
2002-11-10 13:44:48 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
return ERROR_SUCCESS;
|
2002-11-10 13:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegSetKeySecurity
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegSetKeySecurity (HKEY hKey,
|
|
|
|
SECURITY_INFORMATION SecurityInformation,
|
|
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2004-02-22 14:26:07 +00:00
|
|
|
NTSTATUS Status;
|
2002-12-08 16:14:28 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (hKey == HKEY_PERFORMANCE_DATA)
|
2004-02-22 14:26:07 +00:00
|
|
|
{
|
|
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status = NtSetSecurityObject (KeyHandle,
|
|
|
|
SecurityInformation,
|
|
|
|
pSecurityDescriptor);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
2002-12-08 16:14:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegSetValueExA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegSetValueExA (HKEY hKey,
|
|
|
|
LPCSTR lpValueName,
|
|
|
|
DWORD Reserved,
|
|
|
|
DWORD dwType,
|
|
|
|
CONST BYTE* lpData,
|
|
|
|
DWORD cbData)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2001-09-01 15:36:45 +00:00
|
|
|
UNICODE_STRING ValueName;
|
|
|
|
LPWSTR pValueName;
|
|
|
|
ANSI_STRING AnsiString;
|
|
|
|
UNICODE_STRING Data;
|
|
|
|
LONG ErrorCode;
|
|
|
|
LPBYTE pData;
|
|
|
|
DWORD DataSize;
|
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (lpValueName != NULL &&
|
|
|
|
strlen(lpValueName) != 0)
|
|
|
|
{
|
|
|
|
RtlCreateUnicodeStringFromAsciiz (&ValueName,
|
2004-02-25 14:25:11 +00:00
|
|
|
(PSTR)lpValueName);
|
2003-07-12 00:03:42 +00:00
|
|
|
pValueName = (LPWSTR)ValueName.Buffer;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pValueName = NULL;
|
|
|
|
}
|
|
|
|
|
2005-05-05 02:46:17 +00:00
|
|
|
if (((dwType == REG_SZ) ||
|
|
|
|
(dwType == REG_MULTI_SZ) ||
|
|
|
|
(dwType == REG_EXPAND_SZ)) &&
|
|
|
|
(cbData != 0))
|
|
|
|
{
|
|
|
|
/* NT adds one if the caller forgot the NULL-termination character */
|
|
|
|
if (lpData[cbData - 1] != '\0')
|
|
|
|
{
|
|
|
|
cbData++;
|
|
|
|
}
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
RtlInitAnsiString (&AnsiString,
|
|
|
|
NULL);
|
2004-02-25 14:25:11 +00:00
|
|
|
AnsiString.Buffer = (PSTR)lpData;
|
2005-05-05 02:46:17 +00:00
|
|
|
AnsiString.Length = cbData - 1;
|
2003-07-12 00:03:42 +00:00
|
|
|
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)
|
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
RtlFreeHeap (ProcessHeap,
|
2003-07-12 00:03:42 +00:00
|
|
|
0,
|
|
|
|
ValueName.Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Data.Buffer != NULL)
|
|
|
|
{
|
2003-08-30 14:46:29 +00:00
|
|
|
RtlFreeHeap (ProcessHeap,
|
2003-07-12 00:03:42 +00:00
|
|
|
0,
|
|
|
|
Data.Buffer);
|
|
|
|
}
|
|
|
|
|
2001-09-01 15:36:45 +00:00
|
|
|
return ErrorCode;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-06 19:59:54 +00:00
|
|
|
/************************************************************************
|
2003-07-12 00:03:42 +00:00
|
|
|
* RegSetValueExW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2000-09-06 19:59:54 +00:00
|
|
|
*/
|
2003-07-12 00:03:42 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegSetValueExW (HKEY hKey,
|
|
|
|
LPCWSTR lpValueName,
|
|
|
|
DWORD Reserved,
|
|
|
|
DWORD dwType,
|
|
|
|
CONST BYTE* lpData,
|
|
|
|
DWORD cbData)
|
2000-09-06 19:59:54 +00:00
|
|
|
{
|
2003-07-12 00:03:42 +00:00
|
|
|
UNICODE_STRING ValueName;
|
|
|
|
PUNICODE_STRING pValueName;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2003-07-12 00:03:42 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2002-12-08 16:14:28 +00:00
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
|
|
|
if (lpValueName != NULL)
|
|
|
|
{
|
|
|
|
RtlInitUnicodeString (&ValueName,
|
|
|
|
lpValueName);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-12-23 21:18:31 +00:00
|
|
|
RtlInitUnicodeString (&ValueName, L"");
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
2003-12-23 21:18:31 +00:00
|
|
|
pValueName = &ValueName;
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 02:46:17 +00:00
|
|
|
if (((dwType == REG_SZ) ||
|
|
|
|
(dwType == REG_MULTI_SZ) ||
|
|
|
|
(dwType == REG_EXPAND_SZ)) &&
|
|
|
|
(cbData != 0) && (*(((PWCHAR)lpData) + (cbData / sizeof(WCHAR)) - 1) != L'\0'))
|
|
|
|
{
|
|
|
|
/* NT adds one if the caller forgot the NULL-termination character */
|
|
|
|
cbData += sizeof(WCHAR);
|
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
|
|
|
Status = NtSetValueKey (KeyHandle,
|
|
|
|
pValueName,
|
|
|
|
0,
|
|
|
|
dwType,
|
|
|
|
(PVOID)lpData,
|
|
|
|
(ULONG)cbData);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
2000-09-06 19:59:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-10 13:44:48 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegSetValueA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2002-11-10 13:44:48 +00:00
|
|
|
*/
|
2003-03-24 13:44:15 +00:00
|
|
|
LONG STDCALL
|
2003-07-12 00:03:42 +00:00
|
|
|
RegSetValueA (HKEY hKey,
|
|
|
|
LPCSTR lpSubKey,
|
|
|
|
DWORD dwType,
|
|
|
|
LPCSTR lpData,
|
|
|
|
DWORD cbData)
|
2002-11-10 13:44:48 +00:00
|
|
|
{
|
2005-05-05 02:46:17 +00:00
|
|
|
LONG ret;
|
|
|
|
HKEY hSubKey;
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 02:46:17 +00:00
|
|
|
if (dwType != REG_SZ)
|
|
|
|
{
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 02:46:17 +00:00
|
|
|
if (lpSubKey != NULL && lpSubKey[0] != '\0')
|
|
|
|
{
|
|
|
|
ret = RegCreateKeyA(hKey,
|
|
|
|
lpSubKey,
|
|
|
|
&hSubKey);
|
|
|
|
|
|
|
|
if (ret != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
hSubKey = hKey;
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 02:46:17 +00:00
|
|
|
ret = RegSetValueExA(hSubKey,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
REG_SZ,
|
2005-05-08 03:09:14 +00:00
|
|
|
(CONST BYTE*)lpData,
|
2005-05-05 02:46:17 +00:00
|
|
|
strlen(lpData) + 1);
|
2005-05-09 01:43:41 +00:00
|
|
|
|
2005-05-05 02:46:17 +00:00
|
|
|
if (hSubKey != hKey)
|
|
|
|
{
|
|
|
|
RegCloseKey(hSubKey);
|
|
|
|
}
|
2003-07-12 00:03:42 +00:00
|
|
|
|
2005-05-05 02:46:17 +00:00
|
|
|
return ret;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* RegSetValueW
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegSetValueW (HKEY hKey,
|
|
|
|
LPCWSTR lpSubKey,
|
|
|
|
DWORD dwType,
|
|
|
|
LPCWSTR lpData,
|
|
|
|
DWORD cbData)
|
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING SubKeyString;
|
2004-06-17 09:07:12 +00:00
|
|
|
HANDLE KeyHandle;
|
2003-07-12 00:03:42 +00:00
|
|
|
HANDLE RealKey;
|
|
|
|
BOOL CloseRealKey;
|
|
|
|
NTSTATUS Status;
|
2005-05-05 16:15:08 +00:00
|
|
|
LONG ErrorCode;
|
2003-07-12 00:03:42 +00:00
|
|
|
|
|
|
|
Status = MapDefaultKey (&KeyHandle,
|
2005-08-26 09:40:37 +00:00
|
|
|
hKey);
|
2003-07-12 00:03:42 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((lpSubKey) && (wcslen(lpSubKey) != 0))
|
|
|
|
{
|
|
|
|
RtlInitUnicodeString (&SubKeyString,
|
|
|
|
(LPWSTR)lpSubKey);
|
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
|
|
|
&SubKeyString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
KeyHandle,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenKey (&RealKey,
|
2005-05-05 00:07:27 +00:00
|
|
|
KEY_SET_VALUE,
|
2003-07-12 00:03:42 +00:00
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-08-26 09:40:37 +00:00
|
|
|
ErrorCode = RtlNtStatusToDosError (Status);
|
|
|
|
goto Cleanup;
|
2003-07-12 00:03:42 +00:00
|
|
|
}
|
|
|
|
CloseRealKey = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RealKey = hKey;
|
|
|
|
CloseRealKey = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorCode = RegSetValueExW (RealKey,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
dwType,
|
|
|
|
(LPBYTE)lpData,
|
|
|
|
cbData);
|
|
|
|
if (CloseRealKey == TRUE)
|
|
|
|
{
|
|
|
|
NtClose (RealKey);
|
|
|
|
}
|
|
|
|
|
2005-08-26 09:40:37 +00:00
|
|
|
Cleanup:
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2002-11-10 13:44:48 +00:00
|
|
|
return ErrorCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-26 05:24:21 +00:00
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegUnLoadKeyA
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-03-12 06:29:00 +00:00
|
|
|
*/
|
2003-03-24 13:44:15 +00:00
|
|
|
LONG STDCALL
|
|
|
|
RegUnLoadKeyA (HKEY hKey,
|
|
|
|
LPCSTR lpSubKey)
|
1999-03-12 06:29:00 +00:00
|
|
|
{
|
2003-03-24 13:44:15 +00:00
|
|
|
UNICODE_STRING KeyName;
|
|
|
|
DWORD ErrorCode;
|
|
|
|
|
|
|
|
RtlCreateUnicodeStringFromAsciiz (&KeyName,
|
|
|
|
(LPSTR)lpSubKey);
|
|
|
|
|
|
|
|
ErrorCode = RegUnLoadKeyW (hKey,
|
|
|
|
KeyName.Buffer);
|
|
|
|
|
|
|
|
RtlFreeUnicodeString (&KeyName);
|
|
|
|
|
|
|
|
return ErrorCode;
|
1999-03-12 06:29:00 +00:00
|
|
|
}
|
|
|
|
|
2000-09-08 22:55:14 +00:00
|
|
|
|
|
|
|
/************************************************************************
|
2002-12-08 16:14:28 +00:00
|
|
|
* RegUnLoadKeyW
|
2003-07-10 15:05:55 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2000-09-08 22:55:14 +00:00
|
|
|
*/
|
2003-03-24 13:44:15 +00:00
|
|
|
LONG STDCALL
|
2004-02-25 14:25:11 +00:00
|
|
|
RegUnLoadKeyW (HKEY hKey,
|
2003-03-24 13:44:15 +00:00
|
|
|
LPCWSTR lpSubKey)
|
2000-09-08 22:55:14 +00:00
|
|
|
{
|
2003-03-24 13:44:15 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING KeyName;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
if (hKey == HKEY_PERFORMANCE_DATA)
|
2004-09-13 11:41:26 +00:00
|
|
|
{
|
|
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
}
|
2003-03-24 13:44:15 +00:00
|
|
|
|
|
|
|
Status = MapDefaultKey (&KeyHandle, hKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RtlInitUnicodeString (&KeyName,
|
|
|
|
(LPWSTR)lpSubKey);
|
|
|
|
|
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
|
|
|
&KeyName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
KeyHandle,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtUnloadKey (&ObjectAttributes);
|
2005-08-26 09:40:37 +00:00
|
|
|
|
2005-09-26 18:05:57 +00:00
|
|
|
ClosePredefKey(KeyHandle);
|
2003-03-24 13:44:15 +00:00
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-05-05 16:15:08 +00:00
|
|
|
return RtlNtStatusToDosError (Status);
|
2003-03-24 13:44:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
2000-09-08 22:55:14 +00:00
|
|
|
}
|
|
|
|
|
2005-08-26 09:48:13 +00:00
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* RegLoadMUIStringW
|
|
|
|
*
|
2005-08-26 09:49:19 +00:00
|
|
|
* @unimplemented
|
2005-08-26 09:48:13 +00:00
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegLoadMUIStringW(IN HKEY hKey,
|
|
|
|
IN LPCWSTR pszValue OPTIONAL,
|
|
|
|
OUT LPWSTR pszOutBuf,
|
|
|
|
IN ULONG cbOutBuf,
|
|
|
|
IN ULONG Reserved,
|
|
|
|
IN LPCWSTR pszDirectory OPTIONAL)
|
|
|
|
{
|
|
|
|
DPRINT1("RegLoadMUIStringW(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
|
|
|
|
hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
|
|
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* RegLoadMUIStringA
|
|
|
|
*
|
2005-08-26 09:49:19 +00:00
|
|
|
* @unimplemented
|
2005-08-26 09:48:13 +00:00
|
|
|
*/
|
|
|
|
LONG STDCALL
|
|
|
|
RegLoadMUIStringA(IN HKEY hKey,
|
|
|
|
IN LPCSTR pszValue OPTIONAL,
|
|
|
|
OUT LPSTR pszOutBuf,
|
|
|
|
IN ULONG cbOutBuf,
|
|
|
|
IN ULONG Reserved,
|
|
|
|
IN LPCSTR pszDirectory OPTIONAL)
|
|
|
|
{
|
2005-08-26 09:53:00 +00:00
|
|
|
DPRINT1("RegLoadMUIStringA(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
|
2005-08-26 09:48:13 +00:00
|
|
|
hKey, pszValue, pszOutBuf, cbOutBuf, Reserved, pszDirectory);
|
|
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-03-12 06:29:00 +00:00
|
|
|
/* EOF */
|