1999-11-23 20:41:34 +01:00
/*
* Registry management
*
* Copyright ( C ) 1999 Alexandre Julliard
*
* Based on misc / registry . c code
* Copyright ( C ) 1996 Marcus Meissner
* Copyright ( C ) 1998 Matthew Becker
* Copyright ( C ) 1999 Sylvain St - Germain
*
2002-03-10 00:29:33 +01:00
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
2006-05-18 14:49:52 +02:00
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
1999-11-23 20:41:34 +01:00
*/
# include <stdlib.h>
2003-09-06 01:08:26 +02:00
# include <stdarg.h>
2000-02-10 23:15:21 +01:00
# include <stdio.h>
1999-11-23 20:41:34 +01:00
2005-11-28 17:32:54 +01:00
# include "ntstatus.h"
# define WIN32_NO_STATUS
2003-09-06 01:08:26 +02:00
# include "windef.h"
1999-11-23 20:41:34 +01:00
# include "winbase.h"
# include "winreg.h"
# include "winerror.h"
2005-05-16 16:08:11 +02:00
# include "winternl.h"
2006-02-14 10:41:18 +01:00
# include "winuser.h"
2014-08-28 15:42:22 +02:00
# include "advapi32_misc.h"
2005-05-16 16:08:11 +02:00
2000-08-14 16:41:19 +02:00
# include "wine/unicode.h"
2002-03-10 00:29:33 +01:00
# include "wine/debug.h"
1999-11-23 20:41:34 +01:00
2002-03-10 00:29:33 +01:00
WINE_DEFAULT_DEBUG_CHANNEL ( reg ) ;
1999-11-23 20:41:34 +01:00
2002-09-13 23:42:28 +02:00
# define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
# define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
static const WCHAR name_CLASSES_ROOT [ ] =
{ ' M ' , ' a ' , ' c ' , ' h ' , ' i ' , ' n ' , ' e ' , ' \\ ' ,
' S ' , ' o ' , ' f ' , ' t ' , ' w ' , ' a ' , ' r ' , ' e ' , ' \\ ' ,
' C ' , ' l ' , ' a ' , ' s ' , ' s ' , ' e ' , ' s ' , 0 } ;
static const WCHAR name_LOCAL_MACHINE [ ] =
{ ' M ' , ' a ' , ' c ' , ' h ' , ' i ' , ' n ' , ' e ' , 0 } ;
static const WCHAR name_USERS [ ] =
{ ' U ' , ' s ' , ' e ' , ' r ' , 0 } ;
static const WCHAR name_PERFORMANCE_DATA [ ] =
{ ' P ' , ' e ' , ' r ' , ' f ' , ' D ' , ' a ' , ' t ' , ' a ' , 0 } ;
static const WCHAR name_CURRENT_CONFIG [ ] =
{ ' M ' , ' a ' , ' c ' , ' h ' , ' i ' , ' n ' , ' e ' , ' \\ ' ,
' S ' , ' y ' , ' s ' , ' t ' , ' e ' , ' m ' , ' \\ ' ,
' C ' , ' u ' , ' r ' , ' r ' , ' e ' , ' n ' , ' t ' , ' C ' , ' o ' , ' n ' , ' t ' , ' r ' , ' o ' , ' l ' , ' S ' , ' e ' , ' t ' , ' \\ ' ,
2004-08-26 20:22:58 +02:00
' H ' , ' a ' , ' r ' , ' d ' , ' w ' , ' a ' , ' r ' , ' e ' , ' ' , ' P ' , ' r ' , ' o ' , ' f ' , ' i ' , ' l ' , ' e ' , ' s ' , ' \\ ' ,
2002-09-13 23:42:28 +02:00
' C ' , ' u ' , ' r ' , ' r ' , ' e ' , ' n ' , ' t ' , 0 } ;
static const WCHAR name_DYN_DATA [ ] =
{ ' D ' , ' y ' , ' n ' , ' D ' , ' a ' , ' t ' , ' a ' , 0 } ;
2011-03-07 11:06:51 +01:00
static const WCHAR * const root_key_names [ ] =
2002-09-13 23:42:28 +02:00
{
2006-10-18 14:08:13 +02:00
name_CLASSES_ROOT ,
NULL , /* HKEY_CURRENT_USER is determined dynamically */
name_LOCAL_MACHINE ,
name_USERS ,
name_PERFORMANCE_DATA ,
name_CURRENT_CONFIG ,
name_DYN_DATA
2002-09-13 23:42:28 +02:00
} ;
2011-03-07 11:06:51 +01:00
# define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names) / sizeof(root_key_names[0]))
static HKEY special_root_keys [ NB_SPECIAL_ROOT_KEYS ] ;
static BOOL hkcu_cache_disabled ;
2013-09-25 15:01:43 +02:00
static const BOOL is_win64 = ( sizeof ( void * ) > sizeof ( int ) ) ;
1999-11-23 20:41:34 +01:00
/* check if value type needs string conversion (Ansi<->Unicode) */
2013-10-04 11:43:20 +02:00
static inline BOOL is_string ( DWORD type )
1999-11-23 20:41:34 +01:00
{
return ( type = = REG_SZ ) | | ( type = = REG_EXPAND_SZ ) | | ( type = = REG_MULTI_SZ ) ;
}
2002-03-21 02:24:52 +01:00
/* check if current version is NT or Win95 */
2013-10-04 11:43:20 +02:00
static inline BOOL is_version_nt ( void )
2002-03-21 02:24:52 +01:00
{
return ! ( GetVersion ( ) & 0x80000000 ) ;
}
1999-11-23 20:41:34 +01:00
2010-04-02 11:51:15 +02:00
static BOOL is_wow6432node ( const UNICODE_STRING * name )
{
static const WCHAR wow6432nodeW [ ] = { ' W ' , ' o ' , ' w ' , ' 6 ' , ' 4 ' , ' 3 ' , ' 2 ' , ' N ' , ' o ' , ' d ' , ' e ' } ;
return ( name - > Length = = sizeof ( wow6432nodeW ) & &
! memicmpW ( name - > Buffer , wow6432nodeW , sizeof ( wow6432nodeW ) / sizeof ( WCHAR ) ) ) ;
}
/* open the Wow6432Node subkey of the specified key */
2014-12-18 16:21:36 +01:00
static HANDLE open_wow6432node ( HANDLE key )
2010-04-02 11:51:15 +02:00
{
static const WCHAR wow6432nodeW [ ] = { ' W ' , ' o ' , ' w ' , ' 6 ' , ' 4 ' , ' 3 ' , ' 2 ' , ' N ' , ' o ' , ' d ' , ' e ' , 0 } ;
OBJECT_ATTRIBUTES attr ;
UNICODE_STRING nameW ;
HANDLE ret ;
attr . Length = sizeof ( attr ) ;
attr . RootDirectory = key ;
attr . ObjectName = & nameW ;
attr . Attributes = 0 ;
attr . SecurityDescriptor = NULL ;
attr . SecurityQualityOfService = NULL ;
RtlInitUnicodeString ( & nameW , wow6432nodeW ) ;
if ( NtOpenKey ( & ret , MAXIMUM_ALLOWED , & attr ) ) ret = 0 ;
return ret ;
}
2010-03-01 14:12:12 +01:00
/* wrapper for NtCreateKey that creates the key recursively if necessary */
static NTSTATUS create_key ( HKEY * retkey , ACCESS_MASK access , OBJECT_ATTRIBUTES * attr ,
const UNICODE_STRING * class , ULONG options , PULONG dispos )
{
2010-04-02 11:51:15 +02:00
BOOL force_wow32 = is_win64 & & ( access & KEY_WOW64_32KEY ) ;
NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND ;
2015-01-18 14:04:02 +01:00
HANDLE subkey , root = attr - > RootDirectory ;
2010-04-02 11:51:15 +02:00
2015-01-18 14:04:02 +01:00
if ( ! force_wow32 ) status = NtCreateKey ( & subkey , access , attr , 0 , class , options , dispos ) ;
2010-03-01 14:12:12 +01:00
if ( status = = STATUS_OBJECT_NAME_NOT_FOUND )
{
2010-04-02 11:51:15 +02:00
WCHAR * buffer = attr - > ObjectName - > Buffer ;
DWORD attrs , pos = 0 , i = 0 , len = attr - > ObjectName - > Length / sizeof ( WCHAR ) ;
UNICODE_STRING str ;
while ( i < len & & buffer [ i ] ! = ' \\ ' ) i + + ;
if ( i = = len & & ! force_wow32 ) return status ;
2010-03-01 14:12:12 +01:00
attrs = attr - > Attributes ;
2010-04-02 11:51:15 +02:00
attr - > ObjectName = & str ;
2010-03-01 14:12:12 +01:00
2013-10-04 16:44:21 +02:00
for ( ; ; )
2010-03-01 14:12:12 +01:00
{
2010-04-02 11:51:15 +02:00
str . Buffer = buffer + pos ;
str . Length = ( i - pos ) * sizeof ( WCHAR ) ;
if ( force_wow32 & & pos )
{
if ( is_wow6432node ( & str ) ) force_wow32 = FALSE ;
2014-12-18 16:21:36 +01:00
else if ( ( subkey = open_wow6432node ( attr - > RootDirectory ) ) )
2010-04-02 11:51:15 +02:00
{
if ( attr - > RootDirectory ! = root ) NtClose ( attr - > RootDirectory ) ;
attr - > RootDirectory = subkey ;
force_wow32 = FALSE ;
}
}
2013-10-04 16:44:21 +02:00
if ( i = = len )
{
attr - > Attributes = attrs ;
2015-01-18 14:04:02 +01:00
status = NtCreateKey ( & subkey , access , attr , 0 , class , options , dispos ) ;
2013-10-04 16:44:21 +02:00
}
else
{
attr - > Attributes = attrs & ~ OBJ_OPENLINK ;
status = NtCreateKey ( & subkey , access , attr , 0 , class ,
options & ~ REG_OPTION_CREATE_LINK , dispos ) ;
}
2010-04-02 11:51:15 +02:00
if ( attr - > RootDirectory ! = root ) NtClose ( attr - > RootDirectory ) ;
2010-03-01 14:12:12 +01:00
if ( status ) return status ;
2013-10-04 16:44:21 +02:00
if ( i = = len ) break ;
2010-04-02 11:51:15 +02:00
attr - > RootDirectory = subkey ;
while ( i < len & & buffer [ i ] = = ' \\ ' ) i + + ;
pos = i ;
while ( i < len & & buffer [ i ] ! = ' \\ ' ) i + + ;
2010-03-01 14:12:12 +01:00
}
}
2015-01-18 14:04:02 +01:00
attr - > RootDirectory = subkey ;
if ( force_wow32 & & ( subkey = open_wow6432node ( attr - > RootDirectory ) ) )
{
if ( attr - > RootDirectory ! = root ) NtClose ( attr - > RootDirectory ) ;
attr - > RootDirectory = subkey ;
}
* retkey = attr - > RootDirectory ;
2010-03-01 14:12:12 +01:00
return status ;
}
2010-04-02 12:14:21 +02:00
/* wrapper for NtOpenKey to handle Wow6432 nodes */
static NTSTATUS open_key ( HKEY * retkey , ACCESS_MASK access , OBJECT_ATTRIBUTES * attr )
{
NTSTATUS status ;
BOOL force_wow32 = is_win64 & & ( access & KEY_WOW64_32KEY ) ;
HANDLE subkey , root = attr - > RootDirectory ;
WCHAR * buffer = attr - > ObjectName - > Buffer ;
DWORD attrs , pos = 0 , i = 0 , len = attr - > ObjectName - > Length / sizeof ( WCHAR ) ;
UNICODE_STRING str ;
if ( ! force_wow32 ) return NtOpenKey ( ( HANDLE * ) retkey , access , attr ) ;
if ( len & & buffer [ 0 ] = = ' \\ ' ) return STATUS_OBJECT_PATH_INVALID ;
while ( i < len & & buffer [ i ] ! = ' \\ ' ) i + + ;
attrs = attr - > Attributes ;
attr - > ObjectName = & str ;
2013-10-04 16:44:21 +02:00
for ( ; ; )
2010-04-02 12:14:21 +02:00
{
str . Buffer = buffer + pos ;
str . Length = ( i - pos ) * sizeof ( WCHAR ) ;
if ( force_wow32 & & pos )
{
if ( is_wow6432node ( & str ) ) force_wow32 = FALSE ;
2014-12-18 16:21:36 +01:00
else if ( ( subkey = open_wow6432node ( attr - > RootDirectory ) ) )
2010-04-02 12:14:21 +02:00
{
if ( attr - > RootDirectory ! = root ) NtClose ( attr - > RootDirectory ) ;
attr - > RootDirectory = subkey ;
force_wow32 = FALSE ;
}
}
2013-10-04 16:44:21 +02:00
if ( i = = len )
{
attr - > Attributes = attrs ;
2015-01-18 14:04:02 +01:00
status = NtOpenKey ( & subkey , access , attr ) ;
2013-10-04 16:44:21 +02:00
}
else
{
attr - > Attributes = attrs & ~ OBJ_OPENLINK ;
status = NtOpenKey ( & subkey , access , attr ) ;
}
2010-04-02 12:14:21 +02:00
if ( attr - > RootDirectory ! = root ) NtClose ( attr - > RootDirectory ) ;
if ( status ) return status ;
attr - > RootDirectory = subkey ;
2015-01-18 14:04:02 +01:00
if ( i = = len ) break ;
2010-04-02 12:14:21 +02:00
while ( i < len & & buffer [ i ] = = ' \\ ' ) i + + ;
pos = i ;
while ( i < len & & buffer [ i ] ! = ' \\ ' ) i + + ;
}
2015-01-18 14:04:02 +01:00
if ( force_wow32 & & ( subkey = open_wow6432node ( attr - > RootDirectory ) ) )
{
if ( attr - > RootDirectory ! = root ) NtClose ( attr - > RootDirectory ) ;
attr - > RootDirectory = subkey ;
}
* retkey = attr - > RootDirectory ;
2010-04-02 12:14:21 +02:00
return status ;
}
2002-09-13 23:42:28 +02:00
/* create one of the HKEY_* special root keys */
2010-03-01 14:12:12 +01:00
static HKEY create_special_root_hkey ( HKEY hkey , DWORD access )
2002-09-13 23:42:28 +02:00
{
HKEY ret = 0 ;
2013-01-23 17:55:08 +01:00
int idx = HandleToUlong ( hkey ) - HandleToUlong ( HKEY_SPECIAL_ROOT_FIRST ) ;
2002-09-13 23:42:28 +02:00
2013-01-23 17:55:08 +01:00
if ( HandleToUlong ( hkey ) = = HandleToUlong ( HKEY_CURRENT_USER ) )
2002-09-13 23:42:28 +02:00
{
2010-03-01 14:12:12 +01:00
if ( RtlOpenCurrentUser ( access , ( HANDLE * ) & hkey ) ) return 0 ;
2002-10-25 21:17:33 +02:00
TRACE ( " HKEY_CURRENT_USER -> %p \n " , hkey ) ;
2006-06-30 12:06:48 +02:00
/* don't cache the key in the table if caching is disabled */
if ( hkcu_cache_disabled )
return hkey ;
2002-09-13 23:42:28 +02:00
}
else
{
OBJECT_ATTRIBUTES attr ;
2006-10-18 14:08:13 +02:00
UNICODE_STRING name ;
2002-09-13 23:42:28 +02:00
attr . Length = sizeof ( attr ) ;
attr . RootDirectory = 0 ;
2006-10-18 14:08:13 +02:00
attr . ObjectName = & name ;
2002-09-13 23:42:28 +02:00
attr . Attributes = 0 ;
attr . SecurityDescriptor = NULL ;
attr . SecurityQualityOfService = NULL ;
2006-10-18 14:08:13 +02:00
RtlInitUnicodeString ( & name , root_key_names [ idx ] ) ;
2010-03-01 14:12:12 +01:00
if ( create_key ( & hkey , access , & attr , NULL , 0 , NULL ) ) return 0 ;
2002-10-25 21:17:33 +02:00
TRACE ( " %s -> %p \n " , debugstr_w ( attr . ObjectName - > Buffer ) , hkey ) ;
2002-09-13 23:42:28 +02:00
}
2013-10-04 16:44:28 +02:00
if ( ! ( access & ( KEY_WOW64_64KEY | KEY_WOW64_32KEY ) ) )
{
if ( ! ( ret = InterlockedCompareExchangePointer ( ( void * * ) & special_root_keys [ idx ] , hkey , 0 ) ) )
ret = hkey ;
else
NtClose ( hkey ) ; /* somebody beat us to it */
}
2002-09-13 23:42:28 +02:00
else
2013-10-04 16:44:28 +02:00
ret = hkey ;
2002-09-13 23:42:28 +02:00
return ret ;
}
/* map the hkey from special root to normal key if necessary */
2013-10-04 16:44:28 +02:00
static inline HKEY get_special_root_hkey ( HKEY hkey , REGSAM access )
2002-09-13 23:42:28 +02:00
{
HKEY ret = hkey ;
2013-01-23 17:55:08 +01:00
if ( ( HandleToUlong ( hkey ) > = HandleToUlong ( HKEY_SPECIAL_ROOT_FIRST ) )
& & ( HandleToUlong ( hkey ) < = HandleToUlong ( HKEY_SPECIAL_ROOT_LAST ) ) )
2002-09-13 23:42:28 +02:00
{
2013-10-04 16:44:28 +02:00
REGSAM mask = 0 ;
if ( HandleToUlong ( hkey ) = = HandleToUlong ( HKEY_CLASSES_ROOT ) )
mask = KEY_WOW64_32KEY | KEY_WOW64_64KEY ;
if ( ( access & mask ) | |
! ( ret = special_root_keys [ HandleToUlong ( hkey ) - HandleToUlong ( HKEY_SPECIAL_ROOT_FIRST ) ] ) )
ret = create_special_root_hkey ( hkey , MAXIMUM_ALLOWED | ( access & mask ) ) ;
2002-09-13 23:42:28 +02:00
}
return ret ;
}
2002-05-09 21:39:10 +02:00
2008-03-11 19:48:57 +01:00
/******************************************************************************
* RegOverridePredefKey [ ADVAPI32 . @ ]
*/
LSTATUS WINAPI RegOverridePredefKey ( HKEY hkey , HKEY override )
{
HKEY old_key ;
int idx ;
2012-11-22 12:40:40 +01:00
TRACE ( " (%p %p) \n " , hkey , override ) ;
2013-01-23 17:55:08 +01:00
if ( ( HandleToUlong ( hkey ) < HandleToUlong ( HKEY_SPECIAL_ROOT_FIRST ) )
| | ( HandleToUlong ( hkey ) > HandleToUlong ( HKEY_SPECIAL_ROOT_LAST ) ) )
2008-03-11 19:48:57 +01:00
return ERROR_INVALID_PARAMETER ;
2013-01-23 17:55:08 +01:00
idx = HandleToUlong ( hkey ) - HandleToUlong ( HKEY_SPECIAL_ROOT_FIRST ) ;
2008-03-11 19:48:57 +01:00
if ( override )
{
NTSTATUS status = NtDuplicateObject ( GetCurrentProcess ( ) , override ,
GetCurrentProcess ( ) , ( HANDLE * ) & override ,
0 , 0 , DUPLICATE_SAME_ACCESS ) ;
if ( status ) return RtlNtStatusToDosError ( status ) ;
}
old_key = InterlockedExchangePointer ( ( void * * ) & special_root_keys [ idx ] , override ) ;
if ( old_key ) NtClose ( old_key ) ;
return ERROR_SUCCESS ;
}
1999-11-23 20:41:34 +01:00
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegCreateKeyExW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2004-04-23 23:32:34 +02:00
* See RegCreateKeyExA .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegCreateKeyExW ( HKEY hkey , LPCWSTR name , DWORD reserved , LPWSTR class ,
2006-07-08 15:26:16 +02:00
DWORD options , REGSAM access , SECURITY_ATTRIBUTES * sa ,
PHKEY retkey , LPDWORD dispos )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
OBJECT_ATTRIBUTES attr ;
UNICODE_STRING nameW , classW ;
1999-11-23 20:41:34 +01:00
if ( reserved ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , access ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
2000-10-01 03:44:50 +02:00
attr . Length = sizeof ( attr ) ;
attr . RootDirectory = hkey ;
attr . ObjectName = & nameW ;
attr . Attributes = 0 ;
attr . SecurityDescriptor = NULL ;
attr . SecurityQualityOfService = NULL ;
2010-02-15 21:07:36 +01:00
if ( options & REG_OPTION_OPEN_LINK ) attr . Attributes | = OBJ_OPENLINK ;
2000-10-01 03:44:50 +02:00
RtlInitUnicodeString ( & nameW , name ) ;
RtlInitUnicodeString ( & classW , class ) ;
2010-03-01 14:12:12 +01:00
return RtlNtStatusToDosError ( create_key ( retkey , access , & attr , & classW , options , dispos ) ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegCreateKeyExA [ ADVAPI32 . @ ]
2002-05-09 21:39:10 +02:00
*
2004-04-23 23:32:34 +02:00
* Open a registry key , creating it if it doesn ' t exist .
*
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of the parent registry key
* name [ I ] Name of the new key to open or create
* reserved [ I ] Reserved , pass 0
* class [ I ] The object type of the new key
* options [ I ] Flags controlling the key creation ( REG_OPTION_ * flags from " winnt.h " )
* access [ I ] Access level desired
* sa [ I ] Security attributes for the key
* retkey [ O ] Destination for the resulting handle
* dispos [ O ] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2004-04-23 23:32:34 +02:00
*
* RETURNS
2004-07-14 01:33:14 +02:00
* Success : ERROR_SUCCESS .
* Failure : A standard Win32 error code . retkey remains untouched .
2004-04-23 23:32:34 +02:00
*
* FIXME
2004-07-14 01:33:14 +02:00
* MAXIMUM_ALLOWED in access mask not supported by server
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegCreateKeyExA ( HKEY hkey , LPCSTR name , DWORD reserved , LPSTR class ,
2006-07-08 15:26:16 +02:00
DWORD options , REGSAM access , SECURITY_ATTRIBUTES * sa ,
PHKEY retkey , LPDWORD dispos )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
OBJECT_ATTRIBUTES attr ;
2001-03-23 20:12:01 +01:00
UNICODE_STRING classW ;
2000-10-01 03:44:50 +02:00
ANSI_STRING nameA , classA ;
NTSTATUS status ;
1999-11-23 20:41:34 +01:00
if ( reserved ) return ERROR_INVALID_PARAMETER ;
2005-12-08 13:49:02 +01:00
if ( ! is_version_nt ( ) )
{
2009-12-04 16:07:27 +01:00
access = MAXIMUM_ALLOWED ; /* Win95 ignores the access mask */
2005-12-08 13:49:02 +01:00
if ( name & & * name = = ' \\ ' ) name + + ; /* win9x,ME ignores one (and only one) beginning backslash */
}
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , access ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
2000-10-01 03:44:50 +02:00
attr . Length = sizeof ( attr ) ;
attr . RootDirectory = hkey ;
2001-03-23 20:12:01 +01:00
attr . ObjectName = & NtCurrentTeb ( ) - > StaticUnicodeString ;
2000-10-01 03:44:50 +02:00
attr . Attributes = 0 ;
attr . SecurityDescriptor = NULL ;
attr . SecurityQualityOfService = NULL ;
2010-02-15 21:07:36 +01:00
if ( options & REG_OPTION_OPEN_LINK ) attr . Attributes | = OBJ_OPENLINK ;
2000-10-01 03:44:50 +02:00
RtlInitAnsiString ( & nameA , name ) ;
RtlInitAnsiString ( & classA , class ) ;
2001-03-23 20:12:01 +01:00
if ( ! ( status = RtlAnsiStringToUnicodeString ( & NtCurrentTeb ( ) - > StaticUnicodeString ,
& nameA , FALSE ) ) )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
if ( ! ( status = RtlAnsiStringToUnicodeString ( & classW , & classA , TRUE ) ) )
{
2010-03-01 14:12:12 +01:00
status = create_key ( retkey , access , & attr , & classW , options , dispos ) ;
2000-10-01 03:44:50 +02:00
RtlFreeUnicodeString ( & classW ) ;
}
1999-11-23 20:41:34 +01:00
}
2000-10-01 03:44:50 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegCreateKeyW [ ADVAPI32 . @ ]
*
* Creates the specified reg key .
*
* PARAMS
* hKey [ I ] Handle to an open key .
* lpSubKey [ I ] Name of a key that will be opened or created .
* phkResult [ O ] Receives a handle to the opened or created key .
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code defined in Winerror . h
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegCreateKeyW ( HKEY hkey , LPCWSTR lpSubKey , PHKEY phkResult )
1999-11-23 20:41:34 +01:00
{
/* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
/* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
2004-07-14 01:33:14 +02:00
return RegCreateKeyExW ( hkey , lpSubKey , 0 , NULL , REG_OPTION_NON_VOLATILE ,
2009-12-04 16:07:27 +01:00
MAXIMUM_ALLOWED , NULL , phkResult , NULL ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegCreateKeyA [ ADVAPI32 . @ ]
*
2005-11-04 12:43:27 +01:00
* See RegCreateKeyW .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegCreateKeyA ( HKEY hkey , LPCSTR lpSubKey , PHKEY phkResult )
1999-11-23 20:41:34 +01:00
{
2004-07-14 01:33:14 +02:00
return RegCreateKeyExA ( hkey , lpSubKey , 0 , NULL , REG_OPTION_NON_VOLATILE ,
2009-12-04 16:07:27 +01:00
MAXIMUM_ALLOWED , NULL , phkResult , NULL ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegOpenKeyExW [ ADVAPI32 . @ ]
*
2004-04-23 23:32:34 +02:00
* See RegOpenKeyExA .
1999-11-23 20:41:34 +01:00
*/
2010-02-15 21:07:36 +01:00
LSTATUS WINAPI RegOpenKeyExW ( HKEY hkey , LPCWSTR name , DWORD options , REGSAM access , PHKEY retkey )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
OBJECT_ATTRIBUTES attr ;
UNICODE_STRING nameW ;
2008-11-22 02:03:51 +01:00
/* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
2013-01-23 17:55:08 +01:00
if ( HandleToUlong ( hkey ) = = HandleToUlong ( HKEY_CLASSES_ROOT ) & & name & & * name = = ' \\ ' ) name + + ;
2008-11-22 02:03:51 +01:00
2010-02-16 14:32:26 +01:00
if ( ! retkey ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , access ) ) ) return ERROR_INVALID_HANDLE ;
2002-09-13 23:42:28 +02:00
2000-10-01 03:44:50 +02:00
attr . Length = sizeof ( attr ) ;
attr . RootDirectory = hkey ;
attr . ObjectName = & nameW ;
attr . Attributes = 0 ;
attr . SecurityDescriptor = NULL ;
attr . SecurityQualityOfService = NULL ;
2010-02-15 21:07:36 +01:00
if ( options & REG_OPTION_OPEN_LINK ) attr . Attributes | = OBJ_OPENLINK ;
2000-10-01 03:44:50 +02:00
RtlInitUnicodeString ( & nameW , name ) ;
2010-04-02 12:14:21 +02:00
return RtlNtStatusToDosError ( open_key ( retkey , access , & attr ) ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegOpenKeyExA [ ADVAPI32 . @ ]
2004-04-23 23:32:34 +02:00
*
* Open a registry key .
*
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of open key
* name [ I ] Name of subkey to open
2010-02-15 21:07:36 +01:00
* options [ I ] Open options ( can be set to REG_OPTION_OPEN_LINK )
2004-07-14 01:33:14 +02:00
* access [ I ] Security access mask
* retkey [ O ] Handle to open key
2004-04-23 23:32:34 +02:00
*
* RETURNS
2004-07-14 01:33:14 +02:00
* Success : ERROR_SUCCESS
* Failure : A standard Win32 error code . retkey is set to 0.
2004-04-23 23:32:34 +02:00
*
* NOTES
2004-07-14 01:33:14 +02:00
* Unlike RegCreateKeyExA ( ) , this function will not create the key if it
* does not exist .
1999-11-23 20:41:34 +01:00
*/
2010-02-15 21:07:36 +01:00
LSTATUS WINAPI RegOpenKeyExA ( HKEY hkey , LPCSTR name , DWORD options , REGSAM access , PHKEY retkey )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
OBJECT_ATTRIBUTES attr ;
STRING nameA ;
NTSTATUS status ;
2009-12-04 16:07:27 +01:00
if ( ! is_version_nt ( ) ) access = MAXIMUM_ALLOWED ; /* Win95 ignores the access mask */
2008-11-22 02:03:51 +01:00
else
{
/* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
2013-01-23 17:55:08 +01:00
if ( HandleToUlong ( hkey ) = = HandleToUlong ( HKEY_CLASSES_ROOT ) & & name & & * name = = ' \\ ' ) name + + ;
2008-11-22 02:03:51 +01:00
}
2002-03-21 02:24:52 +01:00
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , access ) ) ) return ERROR_INVALID_HANDLE ;
2002-09-13 23:42:28 +02:00
2000-10-01 03:44:50 +02:00
attr . Length = sizeof ( attr ) ;
attr . RootDirectory = hkey ;
2001-03-23 20:12:01 +01:00
attr . ObjectName = & NtCurrentTeb ( ) - > StaticUnicodeString ;
2000-10-01 03:44:50 +02:00
attr . Attributes = 0 ;
attr . SecurityDescriptor = NULL ;
attr . SecurityQualityOfService = NULL ;
2010-02-15 21:07:36 +01:00
if ( options & REG_OPTION_OPEN_LINK ) attr . Attributes | = OBJ_OPENLINK ;
2000-10-01 03:44:50 +02:00
RtlInitAnsiString ( & nameA , name ) ;
2001-03-23 20:12:01 +01:00
if ( ! ( status = RtlAnsiStringToUnicodeString ( & NtCurrentTeb ( ) - > StaticUnicodeString ,
& nameA , FALSE ) ) )
2000-10-01 03:44:50 +02:00
{
2010-04-02 12:14:21 +02:00
status = open_key ( retkey , access , & attr ) ;
2000-10-01 03:44:50 +02:00
}
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegOpenKeyW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2004-04-23 23:32:34 +02:00
* See RegOpenKeyA .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegOpenKeyW ( HKEY hkey , LPCWSTR name , PHKEY retkey )
1999-11-23 20:41:34 +01:00
{
2009-06-28 20:40:04 +02:00
if ( ! retkey )
return ERROR_INVALID_PARAMETER ;
2005-02-25 17:52:10 +01:00
if ( ! name | | ! * name )
{
* retkey = hkey ;
return ERROR_SUCCESS ;
}
2009-12-04 16:07:27 +01:00
return RegOpenKeyExW ( hkey , name , 0 , MAXIMUM_ALLOWED , retkey ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegOpenKeyA [ ADVAPI32 . @ ]
2004-04-23 23:32:34 +02:00
*
* Open a registry key .
*
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of parent key to open the new key under
* name [ I ] Name of the key under hkey to open
* retkey [ O ] Destination for the resulting Handle
2004-04-23 23:32:34 +02:00
*
* RETURNS
2004-07-14 01:33:14 +02:00
* Success : ERROR_SUCCESS
2009-06-28 20:40:04 +02:00
* Failure : A standard Win32 error code . When retkey is valid , * retkey is set to 0.
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegOpenKeyA ( HKEY hkey , LPCSTR name , PHKEY retkey )
1999-11-23 20:41:34 +01:00
{
2009-06-28 20:40:04 +02:00
if ( ! retkey )
return ERROR_INVALID_PARAMETER ;
2005-02-25 17:52:10 +01:00
if ( ! name | | ! * name )
{
* retkey = hkey ;
return ERROR_SUCCESS ;
}
2009-12-04 16:07:27 +01:00
return RegOpenKeyExA ( hkey , name , 0 , MAXIMUM_ALLOWED , retkey ) ;
1999-11-23 20:41:34 +01:00
}
2000-10-29 02:24:54 +01:00
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegOpenCurrentUser [ ADVAPI32 . @ ]
2005-11-12 20:12:03 +01:00
*
* Get a handle to the HKEY_CURRENT_USER key for the user
* the current thread is impersonating .
*
* PARAMS
* access [ I ] Desired access rights to the key
* retkey [ O ] Handle to the opened key
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
*
* FIXME
* This function is supposed to retrieve a handle to the
* HKEY_CURRENT_USER for the user the current thread is impersonating .
* Since Wine does not currently allow threads to impersonate other users ,
* this stub should work fine .
2000-10-29 02:24:54 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegOpenCurrentUser ( REGSAM access , PHKEY retkey )
2000-10-29 02:24:54 +01:00
{
return RegOpenKeyExA ( HKEY_CURRENT_USER , " " , 0 , access , retkey ) ;
}
1999-11-23 20:41:34 +01:00
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegEnumKeyExW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2005-11-12 20:12:03 +01:00
* Enumerate subkeys of the specified open registry key .
*
1999-11-23 20:41:34 +01:00
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle to key to enumerate
* index [ I ] Index of subkey to enumerate
* name [ O ] Buffer for subkey name
* name_len [ O ] Size of subkey buffer
* reserved [ I ] Reserved
* class [ O ] Buffer for class string
* class_len [ O ] Size of class buffer
* ft [ O ] Time key last written to
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : System error code . If there are no more subkeys available , the
* function returns ERROR_NO_MORE_ITEMS .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegEnumKeyExW ( HKEY hkey , DWORD index , LPWSTR name , LPDWORD name_len ,
2006-07-08 15:26:16 +02:00
LPDWORD reserved , LPWSTR class , LPDWORD class_len , FILETIME * ft )
1999-11-23 20:41:34 +01:00
{
2000-10-02 05:46:58 +02:00
NTSTATUS status ;
char buffer [ 256 ] , * buf_ptr = buffer ;
KEY_NODE_INFORMATION * info = ( KEY_NODE_INFORMATION * ) buffer ;
DWORD total_size ;
1999-11-23 20:41:34 +01:00
2008-07-21 23:12:04 +02:00
TRACE ( " (%p,%d,%p,%p(%u),%p,%p,%p,%p) \n " , hkey , index , name , name_len ,
name_len ? * name_len : 0 , reserved , class , class_len , ft ) ;
1999-11-23 20:41:34 +01:00
if ( reserved ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
2002-07-05 03:21:13 +02:00
2000-10-02 05:46:58 +02:00
status = NtEnumerateKey ( hkey , index , KeyNodeInformation ,
buffer , sizeof ( buffer ) , & total_size ) ;
1999-11-23 20:41:34 +01:00
2000-10-02 05:46:58 +02:00
while ( status = = STATUS_BUFFER_OVERFLOW )
{
/* retry with a dynamically allocated buffer */
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
if ( ! ( buf_ptr = heap_alloc ( total_size ) ) )
2000-10-02 05:46:58 +02:00
return ERROR_NOT_ENOUGH_MEMORY ;
info = ( KEY_NODE_INFORMATION * ) buf_ptr ;
status = NtEnumerateKey ( hkey , index , KeyNodeInformation ,
buf_ptr , total_size , & total_size ) ;
}
1999-11-23 20:41:34 +01:00
2000-10-02 05:46:58 +02:00
if ( ! status )
1999-11-23 20:41:34 +01:00
{
2000-10-02 05:46:58 +02:00
DWORD len = info - > NameLength / sizeof ( WCHAR ) ;
DWORD cls_len = info - > ClassLength / sizeof ( WCHAR ) ;
2001-11-23 19:44:43 +01:00
if ( ft ) * ft = * ( FILETIME * ) & info - > LastWriteTime ;
2000-10-02 05:46:58 +02:00
2002-02-05 20:45:55 +01:00
if ( len > = * name_len | | ( class & & class_len & & ( cls_len > = * class_len ) ) )
2000-10-02 05:46:58 +02:00
status = STATUS_BUFFER_OVERFLOW ;
else
{
* name_len = len ;
memcpy ( name , info - > Name , info - > NameLength ) ;
name [ len ] = 0 ;
if ( class_len )
{
* class_len = cls_len ;
if ( class )
{
memcpy ( class , buf_ptr + info - > ClassOffset , info - > ClassLength ) ;
class [ cls_len ] = 0 ;
}
}
}
1999-11-23 20:41:34 +01:00
}
2000-10-02 05:46:58 +02:00
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
2000-10-02 05:46:58 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegEnumKeyExA [ ADVAPI32 . @ ]
*
2005-11-04 12:43:27 +01:00
* See RegEnumKeyExW .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegEnumKeyExA ( HKEY hkey , DWORD index , LPSTR name , LPDWORD name_len ,
2006-07-08 15:26:16 +02:00
LPDWORD reserved , LPSTR class , LPDWORD class_len , FILETIME * ft )
1999-11-23 20:41:34 +01:00
{
2000-10-02 05:46:58 +02:00
NTSTATUS status ;
char buffer [ 256 ] , * buf_ptr = buffer ;
KEY_NODE_INFORMATION * info = ( KEY_NODE_INFORMATION * ) buffer ;
DWORD total_size ;
1999-11-23 20:41:34 +01:00
2008-07-21 23:12:04 +02:00
TRACE ( " (%p,%d,%p,%p(%u),%p,%p,%p,%p) \n " , hkey , index , name , name_len ,
name_len ? * name_len : 0 , reserved , class , class_len , ft ) ;
1999-11-23 20:41:34 +01:00
if ( reserved ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
2002-07-05 03:21:13 +02:00
2000-10-02 05:46:58 +02:00
status = NtEnumerateKey ( hkey , index , KeyNodeInformation ,
buffer , sizeof ( buffer ) , & total_size ) ;
1999-11-23 20:41:34 +01:00
2000-10-02 05:46:58 +02:00
while ( status = = STATUS_BUFFER_OVERFLOW )
{
/* retry with a dynamically allocated buffer */
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
if ( ! ( buf_ptr = heap_alloc ( total_size ) ) )
2000-10-02 05:46:58 +02:00
return ERROR_NOT_ENOUGH_MEMORY ;
info = ( KEY_NODE_INFORMATION * ) buf_ptr ;
status = NtEnumerateKey ( hkey , index , KeyNodeInformation ,
buf_ptr , total_size , & total_size ) ;
}
1999-11-23 20:41:34 +01:00
2000-10-02 05:46:58 +02:00
if ( ! status )
1999-11-23 20:41:34 +01:00
{
2001-12-05 23:18:48 +01:00
DWORD len , cls_len ;
2000-10-02 05:46:58 +02:00
2001-12-05 23:18:48 +01:00
RtlUnicodeToMultiByteSize ( & len , info - > Name , info - > NameLength ) ;
RtlUnicodeToMultiByteSize ( & cls_len , ( WCHAR * ) ( buf_ptr + info - > ClassOffset ) ,
info - > ClassLength ) ;
2001-11-23 19:44:43 +01:00
if ( ft ) * ft = * ( FILETIME * ) & info - > LastWriteTime ;
2000-10-02 05:46:58 +02:00
2002-02-05 20:45:55 +01:00
if ( len > = * name_len | | ( class & & class_len & & ( cls_len > = * class_len ) ) )
2000-10-02 05:46:58 +02:00
status = STATUS_BUFFER_OVERFLOW ;
else
{
* name_len = len ;
2001-12-05 23:18:48 +01:00
RtlUnicodeToMultiByteN ( name , len , NULL , info - > Name , info - > NameLength ) ;
2000-10-02 05:46:58 +02:00
name [ len ] = 0 ;
if ( class_len )
{
* class_len = cls_len ;
if ( class )
{
2001-12-05 23:18:48 +01:00
RtlUnicodeToMultiByteN ( class , cls_len , NULL ,
( WCHAR * ) ( buf_ptr + info - > ClassOffset ) ,
info - > ClassLength ) ;
2000-10-02 05:46:58 +02:00
class [ cls_len ] = 0 ;
}
}
}
1999-11-23 20:41:34 +01:00
}
2000-10-02 05:46:58 +02:00
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
2000-10-02 05:46:58 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegEnumKeyW [ ADVAPI32 . @ ]
*
2007-04-07 01:46:59 +02:00
* Enumerates subkeys of the specified open reg key .
2004-07-14 01:33:14 +02:00
*
* PARAMS
* hKey [ I ] Handle to an open key .
* dwIndex [ I ] Index of the subkey of hKey to retrieve .
* lpName [ O ] Name of the subkey .
* cchName [ I ] Size of lpName in TCHARS .
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : system error code . If there are no more subkeys available , the
* function returns ERROR_NO_MORE_ITEMS .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegEnumKeyW ( HKEY hkey , DWORD index , LPWSTR name , DWORD name_len )
1999-11-23 20:41:34 +01:00
{
return RegEnumKeyExW ( hkey , index , name , & name_len , NULL , NULL , NULL , NULL ) ;
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegEnumKeyA [ ADVAPI32 . @ ]
*
2005-11-04 12:43:27 +01:00
* See RegEnumKeyW .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegEnumKeyA ( HKEY hkey , DWORD index , LPSTR name , DWORD name_len )
1999-11-23 20:41:34 +01:00
{
return RegEnumKeyExA ( hkey , index , name , & name_len , NULL , NULL , NULL , NULL ) ;
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegQueryInfoKeyW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2005-11-04 12:43:27 +01:00
* Retrieves information about the specified registry key .
*
1999-11-23 20:41:34 +01:00
* PARAMS
* hkey [ I ] Handle to key to query
* class [ O ] Buffer for class string
* class_len [ O ] Size of class string buffer
* reserved [ I ] Reserved
* subkeys [ O ] Buffer for number of subkeys
* max_subkey [ O ] Buffer for longest subkey name length
* max_class [ O ] Buffer for longest class string length
* values [ O ] Buffer for number of value entries
* max_value [ O ] Buffer for longest value name length
* max_data [ O ] Buffer for longest value data length
* security [ O ] Buffer for security descriptor length
* modif [ O ] Modification time
*
2005-11-04 12:43:27 +01:00
* RETURNS
* Success : ERROR_SUCCESS
* Failure : system error code .
*
* NOTES
* - win95 allows class to be valid and class_len to be NULL
* - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
* - both allow class to be NULL and class_len to be NULL
* ( it ' s hard to test validity , so test ! NULL instead )
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegQueryInfoKeyW ( HKEY hkey , LPWSTR class , LPDWORD class_len , LPDWORD reserved ,
2006-07-08 15:26:16 +02:00
LPDWORD subkeys , LPDWORD max_subkey , LPDWORD max_class ,
LPDWORD values , LPDWORD max_value , LPDWORD max_data ,
LPDWORD security , FILETIME * modif )
1999-11-23 20:41:34 +01:00
{
2000-10-02 05:46:58 +02:00
NTSTATUS status ;
char buffer [ 256 ] , * buf_ptr = buffer ;
KEY_FULL_INFORMATION * info = ( KEY_FULL_INFORMATION * ) buffer ;
DWORD total_size ;
1999-11-23 20:41:34 +01:00
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p) \n " , hkey , class , class_len ? * class_len : 0 ,
1999-11-23 20:41:34 +01:00
reserved , subkeys , max_subkey , values , max_value , max_data , security , modif ) ;
2002-03-21 02:24:52 +01:00
if ( class & & ! class_len & & is_version_nt ( ) ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
2000-10-02 05:46:58 +02:00
status = NtQueryKey ( hkey , KeyFullInformation , buffer , sizeof ( buffer ) , & total_size ) ;
2001-02-14 22:45:52 +01:00
if ( status & & status ! = STATUS_BUFFER_OVERFLOW ) goto done ;
1999-11-23 20:41:34 +01:00
2015-05-19 16:03:41 +02:00
if ( class & & class_len & & * class_len )
1999-11-23 20:41:34 +01:00
{
2000-10-02 05:46:58 +02:00
/* retry with a dynamically allocated buffer */
while ( status = = STATUS_BUFFER_OVERFLOW )
1999-11-23 20:41:34 +01:00
{
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
if ( ! ( buf_ptr = heap_alloc ( total_size ) ) )
2000-10-02 05:46:58 +02:00
return ERROR_NOT_ENOUGH_MEMORY ;
info = ( KEY_FULL_INFORMATION * ) buf_ptr ;
status = NtQueryKey ( hkey , KeyFullInformation , buf_ptr , total_size , & total_size ) ;
}
2001-02-14 22:45:52 +01:00
if ( status ) goto done ;
if ( class_len & & ( info - > ClassLength / sizeof ( WCHAR ) + 1 > * class_len ) )
2000-10-02 05:46:58 +02:00
{
2015-05-19 15:59:09 +02:00
status = STATUS_BUFFER_TOO_SMALL ;
2001-02-14 22:45:52 +01:00
}
else
{
memcpy ( class , buf_ptr + info - > ClassOffset , info - > ClassLength ) ;
class [ info - > ClassLength / sizeof ( WCHAR ) ] = 0 ;
1999-11-23 20:41:34 +01:00
}
}
2001-02-14 22:45:52 +01:00
else status = STATUS_SUCCESS ;
2000-10-02 05:46:58 +02:00
2001-02-14 22:45:52 +01:00
if ( class_len ) * class_len = info - > ClassLength / sizeof ( WCHAR ) ;
if ( subkeys ) * subkeys = info - > SubKeys ;
if ( max_subkey ) * max_subkey = info - > MaxNameLen ;
if ( max_class ) * max_class = info - > MaxClassLen ;
if ( values ) * values = info - > Values ;
if ( max_value ) * max_value = info - > MaxValueNameLen ;
if ( max_data ) * max_data = info - > MaxValueDataLen ;
2001-11-23 19:44:43 +01:00
if ( modif ) * modif = * ( FILETIME * ) & info - > LastWriteTime ;
2000-10-02 05:46:58 +02:00
2001-02-14 22:45:52 +01:00
done :
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
2000-10-02 05:46:58 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
2002-07-20 22:02:55 +02:00
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegQueryMultipleValuesA [ ADVAPI32 . @ ]
*
* Retrieves the type and data for a list of value names associated with a key .
*
* PARAMS
* hKey [ I ] Handle to an open key .
* val_list [ O ] Array of VALENT structures that describes the entries .
* num_vals [ I ] Number of elements in val_list .
* lpValueBuf [ O ] Pointer to a buffer that receives the data for each value .
* ldwTotsize [ I / O ] Size of lpValueBuf .
*
* RETURNS
* Success : ERROR_SUCCESS . ldwTotsize contains num bytes copied .
* Failure : nonzero error code from Winerror . h ldwTotsize contains num needed
* bytes .
2002-07-20 22:02:55 +02:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegQueryMultipleValuesA ( HKEY hkey , PVALENTA val_list , DWORD num_vals ,
2006-07-08 15:26:16 +02:00
LPSTR lpValueBuf , LPDWORD ldwTotsize )
2002-07-20 22:02:55 +02:00
{
2004-09-03 01:00:53 +02:00
unsigned int i ;
2002-07-20 22:02:55 +02:00
DWORD maxBytes = * ldwTotsize ;
HRESULT status ;
LPSTR bufptr = lpValueBuf ;
* ldwTotsize = 0 ;
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%p,%d,%p,%p=%d) \n " , hkey , val_list , num_vals , lpValueBuf , ldwTotsize , * ldwTotsize ) ;
2002-07-20 22:02:55 +02:00
for ( i = 0 ; i < num_vals ; + + i )
{
val_list [ i ] . ve_valuelen = 0 ;
status = RegQueryValueExA ( hkey , val_list [ i ] . ve_valuename , NULL , NULL , NULL , & val_list [ i ] . ve_valuelen ) ;
if ( status ! = ERROR_SUCCESS )
{
return status ;
}
if ( lpValueBuf ! = NULL & & * ldwTotsize + val_list [ i ] . ve_valuelen < = maxBytes )
{
status = RegQueryValueExA ( hkey , val_list [ i ] . ve_valuename , NULL , & val_list [ i ] . ve_type ,
2005-07-07 14:08:42 +02:00
( LPBYTE ) bufptr , & val_list [ i ] . ve_valuelen ) ;
2002-07-20 22:02:55 +02:00
if ( status ! = ERROR_SUCCESS )
{
return status ;
}
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 ;
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegQueryMultipleValuesW [ ADVAPI32 . @ ]
*
2005-11-04 12:43:27 +01:00
* See RegQueryMultipleValuesA .
2002-07-20 22:02:55 +02:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegQueryMultipleValuesW ( HKEY hkey , PVALENTW val_list , DWORD num_vals ,
2006-07-08 15:26:16 +02:00
LPWSTR lpValueBuf , LPDWORD ldwTotsize )
2002-07-20 22:02:55 +02:00
{
2004-09-03 01:00:53 +02:00
unsigned int i ;
2002-07-20 22:02:55 +02:00
DWORD maxBytes = * ldwTotsize ;
HRESULT status ;
LPSTR bufptr = ( LPSTR ) lpValueBuf ;
* ldwTotsize = 0 ;
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%p,%d,%p,%p=%d) \n " , hkey , val_list , num_vals , lpValueBuf , ldwTotsize , * ldwTotsize ) ;
2002-07-20 22:02:55 +02:00
for ( i = 0 ; i < num_vals ; + + i )
{
val_list [ i ] . ve_valuelen = 0 ;
status = RegQueryValueExW ( hkey , val_list [ i ] . ve_valuename , NULL , NULL , NULL , & val_list [ i ] . ve_valuelen ) ;
if ( status ! = ERROR_SUCCESS )
{
return status ;
}
if ( lpValueBuf ! = NULL & & * ldwTotsize + val_list [ i ] . ve_valuelen < = maxBytes )
{
status = RegQueryValueExW ( hkey , val_list [ i ] . ve_valuename , NULL , & val_list [ i ] . ve_type ,
2005-07-07 14:08:42 +02:00
( LPBYTE ) bufptr , & val_list [ i ] . ve_valuelen ) ;
2002-07-20 22:02:55 +02:00
if ( status ! = ERROR_SUCCESS )
{
return status ;
}
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 ;
}
1999-11-23 20:41:34 +01:00
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegQueryInfoKeyA [ ADVAPI32 . @ ]
*
* Retrieves information about a registry key .
*
* PARAMS
* hKey [ I ] Handle to an open key .
* lpClass [ O ] Class string of the key .
* lpcClass [ I / O ] size of lpClass .
* lpReserved [ I ] Reserved ; must be NULL .
* lpcSubKeys [ O ] Number of subkeys contained by the key .
* lpcMaxSubKeyLen [ O ] Size of the key ' s subkey with the longest name .
* lpcMaxClassLen [ O ] Size of the longest string specifying a subkey
* class in TCHARS .
* lpcValues [ O ] Number of values associated with the key .
* lpcMaxValueNameLen [ O ] Size of the key ' s longest value name in TCHARS .
* lpcMaxValueLen [ O ] Longest data component among the key ' s values
* lpcbSecurityDescriptor [ O ] Size of the key ' s security descriptor .
2007-04-07 01:46:59 +02:00
* lpftLastWriteTime [ O ] FILETIME structure that is the last write time .
2004-07-14 01:33:14 +02:00
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegQueryInfoKeyA ( HKEY hkey , LPSTR class , LPDWORD class_len , LPDWORD reserved ,
2006-07-08 15:26:16 +02:00
LPDWORD subkeys , LPDWORD max_subkey , LPDWORD max_class ,
LPDWORD values , LPDWORD max_value , LPDWORD max_data ,
LPDWORD security , FILETIME * modif )
1999-11-23 20:41:34 +01:00
{
2000-10-02 05:46:58 +02:00
NTSTATUS status ;
char buffer [ 256 ] , * buf_ptr = buffer ;
KEY_FULL_INFORMATION * info = ( KEY_FULL_INFORMATION * ) buffer ;
2001-02-14 22:45:52 +01:00
DWORD total_size , len ;
1999-11-23 20:41:34 +01:00
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p) \n " , hkey , class , class_len ? * class_len : 0 ,
1999-11-23 20:41:34 +01:00
reserved , subkeys , max_subkey , values , max_value , max_data , security , modif ) ;
2002-03-21 02:24:52 +01:00
if ( class & & ! class_len & & is_version_nt ( ) ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
2000-10-02 05:46:58 +02:00
status = NtQueryKey ( hkey , KeyFullInformation , buffer , sizeof ( buffer ) , & total_size ) ;
2001-02-14 22:45:52 +01:00
if ( status & & status ! = STATUS_BUFFER_OVERFLOW ) goto done ;
1999-11-23 20:41:34 +01:00
2000-10-02 05:46:58 +02:00
if ( class | | class_len )
1999-11-23 20:41:34 +01:00
{
2000-10-02 05:46:58 +02:00
/* retry with a dynamically allocated buffer */
while ( status = = STATUS_BUFFER_OVERFLOW )
{
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
if ( ! ( buf_ptr = heap_alloc ( total_size ) ) )
2000-10-02 05:46:58 +02:00
return ERROR_NOT_ENOUGH_MEMORY ;
info = ( KEY_FULL_INFORMATION * ) buf_ptr ;
status = NtQueryKey ( hkey , KeyFullInformation , buf_ptr , total_size , & total_size ) ;
}
2001-02-14 22:45:52 +01:00
if ( status ) goto done ;
2015-05-19 16:05:01 +02:00
len = 0 ;
if ( class & & class_len ) len = * class_len ;
RtlUnicodeToMultiByteN ( class , len , class_len ,
( WCHAR * ) ( buf_ptr + info - > ClassOffset ) , info - > ClassLength ) ;
if ( len )
1999-11-23 20:41:34 +01:00
{
2015-05-19 16:05:01 +02:00
class [ len - 1 ] = 0 ;
if ( * class_len + 1 > len )
{
status = STATUS_BUFFER_OVERFLOW ;
* class_len - = 1 ;
}
1999-11-23 20:41:34 +01:00
}
}
2001-02-14 22:45:52 +01:00
else status = STATUS_SUCCESS ;
2000-10-02 05:46:58 +02:00
2001-02-14 22:45:52 +01:00
if ( subkeys ) * subkeys = info - > SubKeys ;
if ( max_subkey ) * max_subkey = info - > MaxNameLen ;
if ( max_class ) * max_class = info - > MaxClassLen ;
if ( values ) * values = info - > Values ;
if ( max_value ) * max_value = info - > MaxValueNameLen ;
if ( max_data ) * max_data = info - > MaxValueDataLen ;
2001-11-23 19:44:43 +01:00
if ( modif ) * modif = * ( FILETIME * ) & info - > LastWriteTime ;
2000-10-02 05:46:58 +02:00
2001-02-14 22:45:52 +01:00
done :
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
2000-10-02 05:46:58 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegCloseKey [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2004-04-23 23:32:34 +02:00
* Close an open registry key .
1999-11-23 20:41:34 +01:00
*
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of key to close
1999-11-23 20:41:34 +01:00
*
* RETURNS
2004-07-14 01:33:14 +02:00
* Success : ERROR_SUCCESS
* Failure : Error code
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegCloseKey ( HKEY hkey )
1999-11-23 20:41:34 +01:00
{
2005-02-25 17:52:10 +01:00
if ( ! hkey ) return ERROR_INVALID_HANDLE ;
2005-02-21 21:37:26 +01:00
if ( hkey > = ( HKEY ) 0x80000000 ) return ERROR_SUCCESS ;
2000-10-01 03:44:50 +02:00
return RtlNtStatusToDosError ( NtClose ( hkey ) ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2010-02-18 13:12:31 +01:00
* RegDeleteKeyExW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
2010-02-18 13:12:31 +01:00
LSTATUS WINAPI RegDeleteKeyExW ( HKEY hkey , LPCWSTR name , REGSAM access , DWORD reserved )
1999-11-23 20:41:34 +01:00
{
DWORD ret ;
2000-10-01 03:44:50 +02:00
HKEY tmp ;
1999-11-23 20:41:34 +01:00
2005-04-16 12:49:10 +02:00
if ( ! name ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , access ) ) ) return ERROR_INVALID_HANDLE ;
2002-09-13 23:42:28 +02:00
2010-02-18 13:12:31 +01:00
access & = KEY_WOW64_64KEY | KEY_WOW64_32KEY ;
if ( ! ( ret = RegOpenKeyExW ( hkey , name , 0 , access | DELETE , & tmp ) ) )
2002-06-15 01:35:37 +02:00
{
2000-10-01 03:44:50 +02:00
ret = RtlNtStatusToDosError ( NtDeleteKey ( tmp ) ) ;
RegCloseKey ( tmp ) ;
}
2006-10-03 15:48:41 +02:00
TRACE ( " %s ret=%08x \n " , debugstr_w ( name ) , ret ) ;
2000-10-01 03:44:50 +02:00
return ret ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2010-02-18 13:12:31 +01:00
* RegDeleteKeyW [ ADVAPI32 . @ ]
2005-05-05 18:47:33 +02:00
*
2010-02-18 13:12:31 +01:00
* See RegDeleteKeyA .
1999-11-23 20:41:34 +01:00
*/
2010-02-18 13:12:31 +01:00
LSTATUS WINAPI RegDeleteKeyW ( HKEY hkey , LPCWSTR name )
{
return RegDeleteKeyExW ( hkey , name , 0 , 0 ) ;
}
/******************************************************************************
* RegDeleteKeyExA [ ADVAPI32 . @ ]
*/
LSTATUS WINAPI RegDeleteKeyExA ( HKEY hkey , LPCSTR name , REGSAM access , DWORD reserved )
1999-11-23 20:41:34 +01:00
{
DWORD ret ;
2000-10-01 03:44:50 +02:00
HKEY tmp ;
1999-11-23 20:41:34 +01:00
2005-04-16 12:49:10 +02:00
if ( ! name ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , access ) ) ) return ERROR_INVALID_HANDLE ;
2002-09-13 23:42:28 +02:00
2010-02-18 13:12:31 +01:00
access & = KEY_WOW64_64KEY | KEY_WOW64_32KEY ;
if ( ! ( ret = RegOpenKeyExA ( hkey , name , 0 , access | DELETE , & tmp ) ) )
2002-06-15 01:35:37 +02:00
{
if ( ! is_version_nt ( ) ) /* win95 does recursive key deletes */
{
2012-04-15 13:21:54 +02:00
CHAR sub [ MAX_PATH ] ;
2002-06-15 01:35:37 +02:00
2012-04-15 13:21:54 +02:00
while ( ! RegEnumKeyA ( tmp , 0 , sub , sizeof ( sub ) ) )
2002-06-15 01:35:37 +02:00
{
2012-04-15 13:21:54 +02:00
if ( RegDeleteKeyExA ( tmp , sub , access , reserved ) ) /* recurse */
2002-06-15 01:35:37 +02:00
break ;
}
}
2000-10-01 03:44:50 +02:00
ret = RtlNtStatusToDosError ( NtDeleteKey ( tmp ) ) ;
RegCloseKey ( tmp ) ;
}
2006-10-03 15:48:41 +02:00
TRACE ( " %s ret=%08x \n " , debugstr_a ( name ) , ret ) ;
2000-10-01 03:44:50 +02:00
return ret ;
1999-11-23 20:41:34 +01:00
}
2010-02-18 13:12:31 +01:00
/******************************************************************************
* RegDeleteKeyA [ ADVAPI32 . @ ]
*
* Delete a registry key .
*
* PARAMS
* hkey [ I ] Handle to parent key containing the key to delete
* name [ I ] Name of the key user hkey to delete
*
* NOTES
*
* MSDN is wrong when it says that hkey must be opened with the DELETE access
* right . In reality , it opens a new handle with DELETE access .
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : Error code
*/
LSTATUS WINAPI RegDeleteKeyA ( HKEY hkey , LPCSTR name )
{
return RegDeleteKeyExA ( hkey , name , 0 , 0 ) ;
}
1999-11-23 20:41:34 +01:00
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegSetValueExW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2004-04-23 23:32:34 +02:00
* Set the data and contents of a registry value .
1999-11-23 20:41:34 +01:00
*
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of key to set value for
* name [ I ] Name of value to set
* reserved [ I ] Reserved , must be zero
* type [ I ] Type of the value being set
* data [ I ] The new contents of the value to set
* count [ I ] Size of data
1999-11-23 20:41:34 +01:00
*
* RETURNS
2004-07-14 01:33:14 +02:00
* Success : ERROR_SUCCESS
* Failure : Error code
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegSetValueExW ( HKEY hkey , LPCWSTR name , DWORD reserved ,
2013-09-23 00:22:48 +02:00
DWORD type , const BYTE * data , DWORD count )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
UNICODE_STRING nameW ;
1999-11-23 20:41:34 +01:00
2004-07-24 04:32:50 +02:00
/* no need for version check, not implemented on win9x anyway */
2012-08-20 18:12:18 +02:00
2015-01-05 13:18:50 +01:00
if ( ( data & & ( ( ULONG_PTR ) data > > 16 ) = = 0 ) | | ( ! data & & count ) ) return ERROR_NOACCESS ;
2012-08-20 18:12:18 +02:00
2004-07-24 04:32:50 +02:00
if ( count & & is_string ( type ) )
1999-11-23 20:41:34 +01:00
{
LPCWSTR str = ( LPCWSTR ) data ;
/* if user forgot to count terminating null, add it (yes NT does this) */
if ( str [ count / sizeof ( WCHAR ) - 1 ] & & ! str [ count / sizeof ( WCHAR ) ] )
count + = sizeof ( WCHAR ) ;
}
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
2000-05-15 00:57:57 +02:00
2000-10-01 03:44:50 +02:00
RtlInitUnicodeString ( & nameW , name ) ;
return RtlNtStatusToDosError ( NtSetValueKey ( hkey , & nameW , 0 , type , data , count ) ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegSetValueExA [ ADVAPI32 . @ ]
*
2005-11-04 12:43:27 +01:00
* See RegSetValueExW .
2004-07-24 04:32:50 +02:00
*
* NOTES
* win95 does not care about count for REG_SZ and finds out the len by itself ( js )
* NT does definitely care ( aj )
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegSetValueExA ( HKEY hkey , LPCSTR name , DWORD reserved , DWORD type ,
2013-09-23 00:22:48 +02:00
const BYTE * data , DWORD count )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
ANSI_STRING nameA ;
2010-04-02 11:50:12 +02:00
UNICODE_STRING nameW ;
2000-10-01 03:44:50 +02:00
WCHAR * dataW = NULL ;
NTSTATUS status ;
1999-11-23 20:41:34 +01:00
2002-03-21 02:24:52 +01:00
if ( ! is_version_nt ( ) ) /* win95 */
2001-04-10 23:30:24 +02:00
{
2004-07-24 04:32:50 +02:00
if ( type = = REG_SZ )
{
if ( ! data ) return ERROR_INVALID_PARAMETER ;
2005-08-27 12:00:38 +02:00
count = strlen ( ( const char * ) data ) + 1 ;
2004-07-24 04:32:50 +02:00
}
2001-04-10 23:30:24 +02:00
}
else if ( count & & is_string ( type ) )
1999-11-23 20:41:34 +01:00
{
/* if user forgot to count terminating null, add it (yes NT does this) */
if ( data [ count - 1 ] & & ! data [ count ] ) count + + ;
}
2000-05-15 00:57:57 +02:00
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
2002-09-13 23:42:28 +02:00
2000-10-01 03:44:50 +02:00
if ( is_string ( type ) ) /* need to convert to Unicode */
2000-05-15 00:57:57 +02:00
{
2001-12-05 23:18:48 +01:00
DWORD lenW ;
2005-08-27 12:00:38 +02:00
RtlMultiByteToUnicodeSize ( & lenW , ( const char * ) data , count ) ;
2014-08-28 15:42:22 +02:00
if ( ! ( dataW = heap_alloc ( lenW ) ) ) return ERROR_OUTOFMEMORY ;
2005-08-27 12:00:38 +02:00
RtlMultiByteToUnicodeN ( dataW , lenW , NULL , ( const char * ) data , count ) ;
2001-12-05 23:18:48 +01:00
count = lenW ;
2000-10-01 03:44:50 +02:00
data = ( BYTE * ) dataW ;
}
2000-05-15 00:57:57 +02:00
2000-10-01 03:44:50 +02:00
RtlInitAnsiString ( & nameA , name ) ;
2010-04-02 11:50:12 +02:00
if ( ! ( status = RtlAnsiStringToUnicodeString ( & nameW , & nameA , TRUE ) ) )
2000-10-01 03:44:50 +02:00
{
2010-04-02 11:50:12 +02:00
status = NtSetValueKey ( hkey , & nameW , 0 , type , data , count ) ;
RtlFreeUnicodeString ( & nameW ) ;
2000-05-15 00:57:57 +02:00
}
2014-08-28 15:42:22 +02:00
heap_free ( dataW ) ;
2000-10-01 03:44:50 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegSetValueW [ ADVAPI32 . @ ]
*
* Sets the data for the default or unnamed value of a reg key .
*
* PARAMS
2014-07-02 19:23:27 +02:00
* hkey [ I ] Handle to an open key .
* subkey [ I ] Name of a subkey of hKey .
* type [ I ] Type of information to store .
* data [ I ] String that contains the data to set for the default value .
* count [ I ] Ignored .
2004-07-14 01:33:14 +02:00
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
1999-11-23 20:41:34 +01:00
*/
2014-07-02 19:23:27 +02:00
LSTATUS WINAPI RegSetValueW ( HKEY hkey , LPCWSTR subkey , DWORD type , LPCWSTR data , DWORD count )
1999-11-23 20:41:34 +01:00
{
2014-07-02 19:23:27 +02:00
TRACE ( " (%p,%s,%d,%s,%d) \n " , hkey , debugstr_w ( subkey ) , type , debugstr_w ( data ) , count ) ;
1999-11-23 20:41:34 +01:00
2008-02-16 16:36:00 +01:00
if ( type ! = REG_SZ | | ! data ) return ERROR_INVALID_PARAMETER ;
1999-11-23 20:41:34 +01:00
2014-07-02 19:23:27 +02:00
return RegSetKeyValueW ( hkey , subkey , NULL , type , data , ( strlenW ( data ) + 1 ) * sizeof ( WCHAR ) ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegSetValueA [ ADVAPI32 . @ ]
*
2005-11-04 12:43:27 +01:00
* See RegSetValueW .
1999-11-23 20:41:34 +01:00
*/
2014-07-02 19:23:27 +02:00
LSTATUS WINAPI RegSetValueA ( HKEY hkey , LPCSTR subkey , DWORD type , LPCSTR data , DWORD count )
1999-11-23 20:41:34 +01:00
{
2014-07-02 19:23:27 +02:00
TRACE ( " (%p,%s,%d,%s,%d) \n " , hkey , debugstr_a ( subkey ) , type , debugstr_a ( data ) , count ) ;
1999-11-23 20:41:34 +01:00
2008-02-16 16:36:00 +01:00
if ( type ! = REG_SZ | | ! data ) return ERROR_INVALID_PARAMETER ;
1999-11-23 20:41:34 +01:00
2014-07-02 19:23:27 +02:00
return RegSetKeyValueA ( hkey , subkey , NULL , type , data , strlen ( data ) + 1 ) ;
}
/******************************************************************************
* RegSetKeyValueW [ ADVAPI32 . @ ]
*/
LONG WINAPI RegSetKeyValueW ( HKEY hkey , LPCWSTR subkey , LPCWSTR name , DWORD type , const void * data , DWORD len )
{
HKEY hsubkey = NULL ;
DWORD ret ;
TRACE ( " (%p,%s,%s,%d,%p,%d) \n " , hkey , debugstr_w ( subkey ) , debugstr_w ( name ) , type , data , len ) ;
if ( subkey & & subkey [ 0 ] ) /* need to create the subkey */
1999-11-23 20:41:34 +01:00
{
2014-07-02 19:23:27 +02:00
if ( ( ret = RegCreateKeyW ( hkey , subkey , & hsubkey ) ) ! = ERROR_SUCCESS ) return ret ;
hkey = hsubkey ;
1999-11-23 20:41:34 +01:00
}
2014-07-02 19:23:27 +02:00
ret = RegSetValueExW ( hkey , name , 0 , type , ( const BYTE * ) data , len ) ;
if ( hsubkey ) RegCloseKey ( hsubkey ) ;
1999-11-23 20:41:34 +01:00
return ret ;
}
2014-07-02 19:23:27 +02:00
/******************************************************************************
* RegSetKeyValueA [ ADVAPI32 . @ ]
*/
LONG WINAPI RegSetKeyValueA ( HKEY hkey , LPCSTR subkey , LPCSTR name , DWORD type , const void * data , DWORD len )
{
HKEY hsubkey = NULL ;
DWORD ret ;
TRACE ( " (%p,%s,%s,%d,%p,%d) \n " , hkey , debugstr_a ( subkey ) , debugstr_a ( name ) , type , data , len ) ;
1999-11-23 20:41:34 +01:00
2014-07-02 19:23:27 +02:00
if ( subkey & & subkey [ 0 ] ) /* need to create the subkey */
{
if ( ( ret = RegCreateKeyA ( hkey , subkey , & hsubkey ) ) ! = ERROR_SUCCESS ) return ret ;
hkey = hsubkey ;
}
ret = RegSetValueExA ( hkey , name , 0 , type , ( const BYTE * ) data , len ) ;
if ( hsubkey ) RegCloseKey ( hsubkey ) ;
return ret ;
}
1999-11-23 20:41:34 +01:00
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegQueryValueExW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2004-04-23 23:32:34 +02:00
* See RegQueryValueExA .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegQueryValueExW ( HKEY hkey , LPCWSTR name , LPDWORD reserved , LPDWORD type ,
2006-07-08 15:26:16 +02:00
LPBYTE data , LPDWORD count )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
NTSTATUS status ;
UNICODE_STRING name_str ;
DWORD total_size ;
2000-10-02 05:46:58 +02:00
char buffer [ 256 ] , * buf_ptr = buffer ;
2000-10-01 03:44:50 +02:00
KEY_VALUE_PARTIAL_INFORMATION * info = ( KEY_VALUE_PARTIAL_INFORMATION * ) buffer ;
2002-07-05 23:30:38 +02:00
static const int info_size = offsetof ( KEY_VALUE_PARTIAL_INFORMATION , Data ) ;
1999-11-23 20:41:34 +01:00
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%s,%p,%p,%p,%p=%d) \n " ,
2003-12-13 02:34:40 +01:00
hkey , debugstr_w ( name ) , reserved , type , data , count ,
( count & & data ) ? * count : 0 ) ;
1999-11-23 20:41:34 +01:00
1999-11-25 23:05:46 +01:00
if ( ( data & & ! count ) | | reserved ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
2000-10-01 03:44:50 +02:00
RtlInitUnicodeString ( & name_str , name ) ;
if ( data ) total_size = min ( sizeof ( buffer ) , * count + info_size ) ;
2006-08-16 14:00:59 +02:00
else
{
total_size = info_size ;
if ( count ) * count = 0 ;
}
2000-10-01 03:44:50 +02:00
status = NtQueryValueKey ( hkey , & name_str , KeyValuePartialInformation ,
buffer , total_size , & total_size ) ;
if ( status & & status ! = STATUS_BUFFER_OVERFLOW ) goto done ;
2000-05-15 00:57:57 +02:00
if ( data )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
/* retry with a dynamically allocated buffer */
while ( status = = STATUS_BUFFER_OVERFLOW & & total_size - info_size < = * count )
2000-05-15 00:57:57 +02:00
{
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
if ( ! ( buf_ptr = heap_alloc ( total_size ) ) )
2000-10-02 05:46:58 +02:00
return ERROR_NOT_ENOUGH_MEMORY ;
info = ( KEY_VALUE_PARTIAL_INFORMATION * ) buf_ptr ;
status = NtQueryValueKey ( hkey , & name_str , KeyValuePartialInformation ,
buf_ptr , total_size , & total_size ) ;
2000-10-01 03:44:50 +02:00
}
if ( ! status )
{
memcpy ( data , buf_ptr + info_size , total_size - info_size ) ;
/* 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 ( total_size - info_size < = * count - sizeof ( WCHAR ) & & is_string ( info - > Type ) )
2000-05-15 00:57:57 +02:00
{
2000-10-01 03:44:50 +02:00
WCHAR * ptr = ( WCHAR * ) ( data + total_size - info_size ) ;
if ( ptr > ( WCHAR * ) data & & ptr [ - 1 ] ) * ptr = 0 ;
2000-05-15 00:57:57 +02:00
}
}
2000-10-02 05:46:58 +02:00
else if ( status ! = STATUS_BUFFER_OVERFLOW ) goto done ;
1999-11-23 20:41:34 +01:00
}
2001-02-14 22:45:52 +01:00
else status = STATUS_SUCCESS ;
2000-10-01 03:44:50 +02:00
if ( type ) * type = info - > Type ;
if ( count ) * count = total_size - info_size ;
done :
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
2000-10-01 03:44:50 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegQueryValueExA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2004-04-23 23:32:34 +02:00
* Get the type and contents of a specified value under with a key .
*
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of the key to query
* name [ I ] Name of value under hkey to query
* reserved [ I ] Reserved - must be NULL
* type [ O ] Destination for the value type , or NULL if not required
* data [ O ] Destination for the values contents , or NULL if not required
* count [ I / O ] Size of data , updated with the number of bytes returned
2004-04-23 23:32:34 +02:00
*
* RETURNS
* Success : ERROR_SUCCESS . * count is updated with the number of bytes copied to data .
* Failure : ERROR_INVALID_HANDLE , if hkey is invalid .
* ERROR_INVALID_PARAMETER , if any other parameter is invalid .
* ERROR_MORE_DATA , if on input * count is too small to hold the contents .
*
* NOTES
* MSDN states that if data is too small it is partially filled . In reality
* it remains untouched .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegQueryValueExA ( HKEY hkey , LPCSTR name , LPDWORD reserved , LPDWORD type ,
2006-07-08 15:26:16 +02:00
LPBYTE data , LPDWORD count )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
NTSTATUS status ;
ANSI_STRING nameA ;
2010-04-02 11:50:12 +02:00
UNICODE_STRING nameW ;
2007-12-14 06:48:28 +01:00
DWORD total_size , datalen = 0 ;
2000-10-02 05:46:58 +02:00
char buffer [ 256 ] , * buf_ptr = buffer ;
2000-10-01 03:44:50 +02:00
KEY_VALUE_PARTIAL_INFORMATION * info = ( KEY_VALUE_PARTIAL_INFORMATION * ) buffer ;
2002-07-05 23:30:38 +02:00
static const int info_size = offsetof ( KEY_VALUE_PARTIAL_INFORMATION , Data ) ;
1999-11-23 20:41:34 +01:00
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%s,%p,%p,%p,%p=%d) \n " ,
1999-11-23 20:41:34 +01:00
hkey , debugstr_a ( name ) , reserved , type , data , count , count ? * count : 0 ) ;
1999-11-25 23:05:46 +01:00
if ( ( data & & ! count ) | | reserved ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
2007-12-14 06:48:28 +01:00
if ( count ) datalen = * count ;
2006-08-16 14:00:59 +02:00
if ( ! data & & count ) * count = 0 ;
/* this matches Win9x behaviour - NT sets *type to a random value */
if ( type ) * type = REG_NONE ;
2000-10-01 03:44:50 +02:00
RtlInitAnsiString ( & nameA , name ) ;
2010-04-02 11:50:12 +02:00
if ( ( status = RtlAnsiStringToUnicodeString ( & nameW , & nameA , TRUE ) ) )
2000-10-02 05:46:58 +02:00
return RtlNtStatusToDosError ( status ) ;
2000-05-15 00:57:57 +02:00
2010-04-02 11:50:12 +02:00
status = NtQueryValueKey ( hkey , & nameW , KeyValuePartialInformation ,
buffer , sizeof ( buffer ) , & total_size ) ;
2000-10-01 03:44:50 +02:00
if ( status & & status ! = STATUS_BUFFER_OVERFLOW ) goto done ;
2000-05-15 00:57:57 +02:00
2000-10-01 03:44:50 +02: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 ( data | | is_string ( info - > Type ) )
1999-11-23 20:41:34 +01:00
{
2000-10-01 03:44:50 +02:00
/* retry with a dynamically allocated buffer */
while ( status = = STATUS_BUFFER_OVERFLOW )
2000-05-15 00:57:57 +02:00
{
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
if ( ! ( buf_ptr = heap_alloc ( total_size ) ) )
2000-10-02 05:46:58 +02:00
{
2000-10-01 03:44:50 +02:00
status = STATUS_NO_MEMORY ;
2000-10-02 05:46:58 +02:00
goto done ;
}
info = ( KEY_VALUE_PARTIAL_INFORMATION * ) buf_ptr ;
2010-04-02 11:50:12 +02:00
status = NtQueryValueKey ( hkey , & nameW , KeyValuePartialInformation ,
buf_ptr , total_size , & total_size ) ;
2000-10-01 03:44:50 +02:00
}
2001-02-14 22:45:52 +01:00
if ( status ) goto done ;
if ( is_string ( info - > Type ) )
2000-10-01 03:44:50 +02:00
{
2001-12-05 23:18:48 +01:00
DWORD len ;
RtlUnicodeToMultiByteSize ( & len , ( WCHAR * ) ( buf_ptr + info_size ) ,
total_size - info_size ) ;
2001-02-14 22:45:52 +01:00
if ( data & & len )
2000-05-15 00:57:57 +02:00
{
2007-12-14 06:48:28 +01:00
if ( len > datalen ) status = STATUS_BUFFER_OVERFLOW ;
2001-02-14 22:45:52 +01:00
else
2000-10-01 03:44:50 +02:00
{
2005-08-27 12:00:38 +02:00
RtlUnicodeToMultiByteN ( ( char * ) data , len , NULL , ( WCHAR * ) ( buf_ptr + info_size ) ,
2001-12-05 23:18:48 +01:00
total_size - info_size ) ;
2001-02-14 22:45:52 +01:00
/* if the type is REG_SZ and data is not 0-terminated
* and there is enough space in the buffer NT appends a \ 0 */
2007-12-14 06:48:28 +01:00
if ( len < datalen & & data [ len - 1 ] ) data [ len ] = 0 ;
2000-10-01 03:44:50 +02:00
}
2000-10-15 02:40:25 +02:00
}
2001-02-14 22:45:52 +01:00
total_size = len + info_size ;
}
else if ( data )
{
2007-12-14 06:48:28 +01:00
if ( total_size - info_size > datalen ) status = STATUS_BUFFER_OVERFLOW ;
2001-02-14 22:45:52 +01:00
else memcpy ( data , buf_ptr + info_size , total_size - info_size ) ;
2000-05-15 00:57:57 +02:00
}
1999-11-23 20:41:34 +01:00
}
2001-02-14 22:45:52 +01:00
else status = STATUS_SUCCESS ;
2000-05-15 00:57:57 +02:00
2000-10-01 03:44:50 +02:00
if ( type ) * type = info - > Type ;
if ( count ) * count = total_size - info_size ;
done :
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
2010-04-02 11:50:12 +02:00
RtlFreeUnicodeString ( & nameW ) ;
2000-10-01 03:44:50 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegQueryValueW [ ADVAPI32 . @ ]
*
* Retrieves the data associated with the default or unnamed value of a key .
*
* PARAMS
2004-10-19 23:14:09 +02:00
* hkey [ I ] Handle to an open key .
* name [ I ] Name of the subkey of hKey .
* data [ O ] Receives the string associated with the default value
2004-07-14 01:33:14 +02:00
* of the key .
2004-10-19 23:14:09 +02:00
* count [ I / O ] Size of lpValue in bytes .
2004-07-14 01:33:14 +02:00
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegQueryValueW ( HKEY hkey , LPCWSTR name , LPWSTR data , LPLONG count )
1999-11-23 20:41:34 +01:00
{
DWORD ret ;
HKEY subkey = hkey ;
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%s,%p,%d) \n " , hkey , debugstr_w ( name ) , data , count ? * count : 0 ) ;
1999-11-23 20:41:34 +01:00
if ( name & & name [ 0 ] )
{
if ( ( ret = RegOpenKeyW ( hkey , name , & subkey ) ) ! = ERROR_SUCCESS ) return ret ;
}
2005-08-27 12:00:38 +02:00
ret = RegQueryValueExW ( subkey , NULL , NULL , NULL , ( LPBYTE ) data , ( LPDWORD ) count ) ;
1999-11-23 20:41:34 +01:00
if ( subkey ! = hkey ) RegCloseKey ( subkey ) ;
if ( ret = = ERROR_FILE_NOT_FOUND )
{
/* return empty string if default value not found */
if ( data ) * data = 0 ;
2004-10-19 23:14:09 +02:00
if ( count ) * count = sizeof ( WCHAR ) ;
1999-11-23 20:41:34 +01:00
ret = ERROR_SUCCESS ;
}
return ret ;
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegQueryValueA [ ADVAPI32 . @ ]
*
2005-11-04 12:43:27 +01:00
* See RegQueryValueW .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegQueryValueA ( HKEY hkey , LPCSTR name , LPSTR data , LPLONG count )
1999-11-23 20:41:34 +01:00
{
DWORD ret ;
HKEY subkey = hkey ;
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%s,%p,%d) \n " , hkey , debugstr_a ( name ) , data , count ? * count : 0 ) ;
1999-11-23 20:41:34 +01:00
if ( name & & name [ 0 ] )
{
if ( ( ret = RegOpenKeyA ( hkey , name , & subkey ) ) ! = ERROR_SUCCESS ) return ret ;
}
2005-08-27 12:00:38 +02:00
ret = RegQueryValueExA ( subkey , NULL , NULL , NULL , ( LPBYTE ) data , ( LPDWORD ) count ) ;
1999-11-23 20:41:34 +01:00
if ( subkey ! = hkey ) RegCloseKey ( subkey ) ;
if ( ret = = ERROR_FILE_NOT_FOUND )
{
/* return empty string if default value not found */
if ( data ) * data = 0 ;
if ( count ) * count = 1 ;
ret = ERROR_SUCCESS ;
}
return ret ;
}
2005-07-18 17:10:22 +02:00
/******************************************************************************
* ADVAPI_ApplyRestrictions [ internal ]
*
* Helper function for RegGetValueA / W .
*/
2006-10-11 20:13:04 +02:00
static VOID ADVAPI_ApplyRestrictions ( DWORD dwFlags , DWORD dwType ,
DWORD cbData , PLONG ret )
2005-07-18 17:10:22 +02:00
{
/* Check if the type is restricted by the passed flags */
if ( * ret = = ERROR_SUCCESS | | * ret = = ERROR_MORE_DATA )
{
DWORD dwMask = 0 ;
switch ( dwType )
{
case REG_NONE : dwMask = RRF_RT_REG_NONE ; break ;
case REG_SZ : dwMask = RRF_RT_REG_SZ ; break ;
case REG_EXPAND_SZ : dwMask = RRF_RT_REG_EXPAND_SZ ; break ;
case REG_MULTI_SZ : dwMask = RRF_RT_REG_MULTI_SZ ; break ;
case REG_BINARY : dwMask = RRF_RT_REG_BINARY ; break ;
case REG_DWORD : dwMask = RRF_RT_REG_DWORD ; break ;
case REG_QWORD : dwMask = RRF_RT_REG_QWORD ; break ;
}
if ( dwFlags & dwMask )
{
/* Type is not restricted, check for size mismatch */
if ( dwType = = REG_BINARY )
{
DWORD cbExpect = 0 ;
2010-02-01 11:09:26 +01:00
if ( ( dwFlags & RRF_RT_ANY ) = = RRF_RT_DWORD )
2005-07-18 17:10:22 +02:00
cbExpect = 4 ;
2010-02-01 11:09:26 +01:00
else if ( ( dwFlags & RRF_RT_ANY ) = = RRF_RT_QWORD )
2005-07-18 17:10:22 +02:00
cbExpect = 8 ;
if ( cbExpect & & cbData ! = cbExpect )
* ret = ERROR_DATATYPE_MISMATCH ;
}
}
else * ret = ERROR_UNSUPPORTED_TYPE ;
}
}
/******************************************************************************
* RegGetValueW [ ADVAPI32 . @ ]
*
2008-01-11 09:49:48 +01:00
* Retrieves the type and data for a value name associated with a key ,
* optionally expanding its content and restricting its type .
2005-07-18 17:10:22 +02:00
*
* PARAMS
* hKey [ I ] Handle to an open key .
* pszSubKey [ I ] Name of the subkey of hKey .
* pszValue [ I ] Name of value under hKey / szSubKey to query .
* dwFlags [ I ] Flags restricting the value type to retrieve .
* pdwType [ O ] Destination for the values type , may be NULL .
* pvData [ O ] Destination for the values content , may be NULL .
2008-01-11 09:49:48 +01:00
* pcbData [ I / O ] Size of pvData , updated with the size in bytes required to
* retrieve the whole content , including the trailing ' \0 '
* for strings .
2005-07-18 17:10:22 +02:00
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
*
* NOTES
2008-01-11 09:49:48 +01:00
* - Unless RRF_NOEXPAND is specified , REG_EXPAND_SZ values are automatically
* expanded and pdwType is set to REG_SZ instead .
2005-07-18 17:10:22 +02:00
* - Restrictions are applied after expanding , using RRF_RT_REG_EXPAND_SZ
* without RRF_NOEXPAND is thus not allowed .
2008-07-19 18:54:20 +02:00
* An exception is the case where RRF_RT_ANY is specified , because then
* RRF_NOEXPAND is allowed .
2005-07-18 17:10:22 +02:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegGetValueW ( HKEY hKey , LPCWSTR pszSubKey , LPCWSTR pszValue ,
2005-07-18 17:10:22 +02:00
DWORD dwFlags , LPDWORD pdwType , PVOID pvData ,
LPDWORD pcbData )
{
DWORD dwType , cbData = pcbData ? * pcbData : 0 ;
PVOID pvBuf = NULL ;
LONG ret ;
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%s,%s,%d,%p,%p,%p=%d) \n " ,
2005-07-18 17:10:22 +02:00
hKey , debugstr_w ( pszSubKey ) , debugstr_w ( pszValue ) , dwFlags , pdwType ,
pvData , pcbData , cbData ) ;
2007-06-21 02:12:30 +02:00
if ( pvData & & ! pcbData )
return ERROR_INVALID_PARAMETER ;
2008-07-19 18:54:20 +02:00
if ( ( dwFlags & RRF_RT_REG_EXPAND_SZ ) & & ! ( dwFlags & RRF_NOEXPAND ) & &
( ( dwFlags & RRF_RT_ANY ) ! = RRF_RT_ANY ) )
2005-07-18 17:10:22 +02:00
return ERROR_INVALID_PARAMETER ;
if ( pszSubKey & & pszSubKey [ 0 ] )
{
ret = RegOpenKeyExW ( hKey , pszSubKey , 0 , KEY_QUERY_VALUE , & hKey ) ;
if ( ret ! = ERROR_SUCCESS ) return ret ;
}
ret = RegQueryValueExW ( hKey , pszValue , NULL , & dwType , pvData , & cbData ) ;
/* If we are going to expand we need to read in the whole the value even
* if the passed buffer was too small as the expanded string might be
* smaller than the unexpanded one and could fit into cbData bytes . */
if ( ( ret = = ERROR_SUCCESS | | ret = = ERROR_MORE_DATA ) & &
2007-06-21 02:12:30 +02:00
dwType = = REG_EXPAND_SZ & & ! ( dwFlags & RRF_NOEXPAND ) )
2005-07-18 17:10:22 +02:00
{
do {
2014-08-28 15:42:22 +02:00
heap_free ( pvBuf ) ;
2005-07-18 17:10:22 +02:00
2014-08-28 15:42:22 +02:00
pvBuf = heap_alloc ( cbData ) ;
2005-07-18 17:10:22 +02:00
if ( ! pvBuf )
{
ret = ERROR_NOT_ENOUGH_MEMORY ;
break ;
}
2007-06-21 02:12:30 +02:00
if ( ret = = ERROR_MORE_DATA | | ! pvData )
2005-07-18 17:10:22 +02:00
ret = RegQueryValueExW ( hKey , pszValue , NULL ,
& dwType , pvBuf , & cbData ) ;
else
{
/* Even if cbData was large enough we have to copy the
* string since ExpandEnvironmentStrings can ' t handle
* overlapping buffers . */
CopyMemory ( pvBuf , pvData , cbData ) ;
}
/* Both the type or the value itself could have been modified in
* between so we have to keep retrying until the buffer is large
* enough or we no longer have to expand the value . */
} while ( dwType = = REG_EXPAND_SZ & & ret = = ERROR_MORE_DATA ) ;
if ( ret = = ERROR_SUCCESS )
{
2007-06-21 02:12:30 +02:00
/* Recheck dwType in case it changed since the first call */
2005-07-18 17:10:22 +02:00
if ( dwType = = REG_EXPAND_SZ )
{
cbData = ExpandEnvironmentStringsW ( pvBuf , pvData ,
2008-01-11 09:52:05 +01:00
pcbData ? * pcbData : 0 ) * sizeof ( WCHAR ) ;
2005-07-18 17:10:22 +02:00
dwType = REG_SZ ;
2008-01-11 09:49:48 +01:00
if ( pvData & & pcbData & & cbData > * pcbData )
2005-07-18 17:10:22 +02:00
ret = ERROR_MORE_DATA ;
}
2007-06-21 02:12:30 +02:00
else if ( pvData )
2005-07-18 17:10:22 +02:00
CopyMemory ( pvData , pvBuf , * pcbData ) ;
}
2014-08-28 15:42:22 +02:00
heap_free ( pvBuf ) ;
2005-07-18 17:10:22 +02:00
}
if ( pszSubKey & & pszSubKey [ 0 ] )
RegCloseKey ( hKey ) ;
ADVAPI_ApplyRestrictions ( dwFlags , dwType , cbData , & ret ) ;
2007-06-21 02:12:30 +02:00
if ( pvData & & ret ! = ERROR_SUCCESS & & ( dwFlags & RRF_ZEROONFAILURE ) )
2005-07-18 17:10:22 +02:00
ZeroMemory ( pvData , * pcbData ) ;
if ( pdwType ) * pdwType = dwType ;
if ( pcbData ) * pcbData = cbData ;
return ret ;
}
/******************************************************************************
* RegGetValueA [ ADVAPI32 . @ ]
*
* See RegGetValueW .
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegGetValueA ( HKEY hKey , LPCSTR pszSubKey , LPCSTR pszValue ,
2005-07-18 17:10:22 +02:00
DWORD dwFlags , LPDWORD pdwType , PVOID pvData ,
LPDWORD pcbData )
{
DWORD dwType , cbData = pcbData ? * pcbData : 0 ;
PVOID pvBuf = NULL ;
LONG ret ;
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%s,%s,%d,%p,%p,%p=%d) \n " ,
2011-09-19 23:27:06 +02:00
hKey , debugstr_a ( pszSubKey ) , debugstr_a ( pszValue ) , dwFlags ,
pdwType , pvData , pcbData , cbData ) ;
2005-07-18 17:10:22 +02:00
2007-06-21 02:12:30 +02:00
if ( pvData & & ! pcbData )
return ERROR_INVALID_PARAMETER ;
2008-07-19 18:54:20 +02:00
if ( ( dwFlags & RRF_RT_REG_EXPAND_SZ ) & & ! ( dwFlags & RRF_NOEXPAND ) & &
( ( dwFlags & RRF_RT_ANY ) ! = RRF_RT_ANY ) )
2005-07-18 17:10:22 +02:00
return ERROR_INVALID_PARAMETER ;
if ( pszSubKey & & pszSubKey [ 0 ] )
{
ret = RegOpenKeyExA ( hKey , pszSubKey , 0 , KEY_QUERY_VALUE , & hKey ) ;
if ( ret ! = ERROR_SUCCESS ) return ret ;
}
ret = RegQueryValueExA ( hKey , pszValue , NULL , & dwType , pvData , & cbData ) ;
/* If we are going to expand we need to read in the whole the value even
* if the passed buffer was too small as the expanded string might be
* smaller than the unexpanded one and could fit into cbData bytes . */
if ( ( ret = = ERROR_SUCCESS | | ret = = ERROR_MORE_DATA ) & &
2007-06-21 02:12:30 +02:00
dwType = = REG_EXPAND_SZ & & ! ( dwFlags & RRF_NOEXPAND ) )
2005-07-18 17:10:22 +02:00
{
do {
2014-08-28 15:42:22 +02:00
heap_free ( pvBuf ) ;
2005-07-18 17:10:22 +02:00
2014-08-28 15:42:22 +02:00
pvBuf = heap_alloc ( cbData ) ;
2005-07-18 17:10:22 +02:00
if ( ! pvBuf )
{
ret = ERROR_NOT_ENOUGH_MEMORY ;
break ;
}
2007-06-21 02:12:30 +02:00
if ( ret = = ERROR_MORE_DATA | | ! pvData )
2005-07-18 17:10:22 +02:00
ret = RegQueryValueExA ( hKey , pszValue , NULL ,
& dwType , pvBuf , & cbData ) ;
else
{
/* Even if cbData was large enough we have to copy the
* string since ExpandEnvironmentStrings can ' t handle
* overlapping buffers . */
CopyMemory ( pvBuf , pvData , cbData ) ;
}
/* Both the type or the value itself could have been modified in
* between so we have to keep retrying until the buffer is large
* enough or we no longer have to expand the value . */
} while ( dwType = = REG_EXPAND_SZ & & ret = = ERROR_MORE_DATA ) ;
if ( ret = = ERROR_SUCCESS )
{
2007-06-21 02:12:30 +02:00
/* Recheck dwType in case it changed since the first call */
2005-07-18 17:10:22 +02:00
if ( dwType = = REG_EXPAND_SZ )
{
cbData = ExpandEnvironmentStringsA ( pvBuf , pvData ,
pcbData ? * pcbData : 0 ) ;
dwType = REG_SZ ;
2008-01-11 09:49:48 +01:00
if ( pvData & & pcbData & & cbData > * pcbData )
2005-07-18 17:10:22 +02:00
ret = ERROR_MORE_DATA ;
}
2007-06-21 02:12:30 +02:00
else if ( pvData )
2005-07-18 17:10:22 +02:00
CopyMemory ( pvData , pvBuf , * pcbData ) ;
}
2014-08-28 15:42:22 +02:00
heap_free ( pvBuf ) ;
2005-07-18 17:10:22 +02:00
}
if ( pszSubKey & & pszSubKey [ 0 ] )
RegCloseKey ( hKey ) ;
ADVAPI_ApplyRestrictions ( dwFlags , dwType , cbData , & ret ) ;
2007-06-21 02:12:30 +02:00
if ( pvData & & ret ! = ERROR_SUCCESS & & ( dwFlags & RRF_ZEROONFAILURE ) )
2005-07-18 17:10:22 +02:00
ZeroMemory ( pvData , * pcbData ) ;
if ( pdwType ) * pdwType = dwType ;
if ( pcbData ) * pcbData = cbData ;
return ret ;
}
1999-11-23 20:41:34 +01:00
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegEnumValueW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2005-11-04 12:43:27 +01:00
* Enumerates the values for the specified open registry key .
*
1999-11-23 20:41:34 +01:00
* PARAMS
2004-07-14 01:33:14 +02:00
* 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
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegEnumValueW ( HKEY hkey , DWORD index , LPWSTR value , LPDWORD val_count ,
2006-07-08 15:26:16 +02:00
LPDWORD reserved , LPDWORD type , LPBYTE data , LPDWORD count )
1999-11-23 20:41:34 +01:00
{
2000-12-15 21:57:00 +01:00
NTSTATUS status ;
DWORD total_size ;
char buffer [ 256 ] , * buf_ptr = buffer ;
KEY_VALUE_FULL_INFORMATION * info = ( KEY_VALUE_FULL_INFORMATION * ) buffer ;
2002-07-05 23:30:38 +02:00
static const int info_size = offsetof ( KEY_VALUE_FULL_INFORMATION , Name ) ;
1999-11-23 20:41:34 +01:00
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%d,%p,%p,%p,%p,%p,%p) \n " ,
1999-11-23 20:41:34 +01:00
hkey , index , value , val_count , reserved , type , data , count ) ;
2015-06-30 14:38:06 +02:00
if ( ( data & & ! count ) | | reserved | | ! value | | ! val_count )
return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
2000-12-15 21:57:00 +01:00
total_size = info_size + ( MAX_PATH + 1 ) * sizeof ( WCHAR ) ;
if ( data ) total_size + = * count ;
total_size = min ( sizeof ( buffer ) , total_size ) ;
1999-11-23 20:41:34 +01:00
2000-12-15 21:57:00 +01:00
status = NtEnumerateValueKey ( hkey , index , KeyValueFullInformation ,
buffer , total_size , & total_size ) ;
2015-06-22 22:23:54 +02:00
if ( status & & status ! = STATUS_BUFFER_OVERFLOW ) goto done ;
1999-11-23 20:41:34 +01:00
2015-06-22 22:23:54 +02:00
if ( value | | data )
2015-06-21 18:25:48 +02:00
{
2015-06-22 22:23:54 +02:00
/* retry with a dynamically allocated buffer */
while ( status = = STATUS_BUFFER_OVERFLOW )
2000-12-15 21:57:00 +01:00
{
2015-06-22 22:23:54 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
if ( ! ( buf_ptr = heap_alloc ( total_size ) ) )
return ERROR_NOT_ENOUGH_MEMORY ;
info = ( KEY_VALUE_FULL_INFORMATION * ) buf_ptr ;
status = NtEnumerateValueKey ( hkey , index , KeyValueFullInformation ,
buf_ptr , total_size , & total_size ) ;
2000-12-15 21:57:00 +01:00
}
2015-06-22 22:23:54 +02:00
if ( status ) goto done ;
if ( value )
2000-05-15 00:57:57 +02:00
{
2015-06-22 22:23:54 +02:00
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 ;
2015-06-21 18:25:48 +02:00
}
2015-06-22 22:23:54 +02:00
if ( data )
2015-06-21 18:25:48 +02:00
{
2015-06-22 22:23:54 +02:00
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 ;
}
2000-05-15 00:57:57 +02:00
}
}
2015-06-22 22:23:54 +02:00
else status = STATUS_SUCCESS ;
2000-12-15 21:57:00 +01:00
2002-07-10 05:27:35 +02:00
overflow :
2000-12-15 21:57:00 +01:00
if ( type ) * type = info - > Type ;
if ( count ) * count = info - > DataLength ;
done :
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
2000-12-15 21:57:00 +01:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegEnumValueA [ ADVAPI32 . @ ]
*
2005-11-04 12:43:27 +01:00
* See RegEnumValueW .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegEnumValueA ( HKEY hkey , DWORD index , LPSTR value , LPDWORD val_count ,
2006-07-08 15:26:16 +02:00
LPDWORD reserved , LPDWORD type , LPBYTE data , LPDWORD count )
1999-11-23 20:41:34 +01:00
{
2000-12-15 21:57:00 +01:00
NTSTATUS status ;
DWORD total_size ;
char buffer [ 256 ] , * buf_ptr = buffer ;
KEY_VALUE_FULL_INFORMATION * info = ( KEY_VALUE_FULL_INFORMATION * ) buffer ;
2002-07-05 23:30:38 +02:00
static const int info_size = offsetof ( KEY_VALUE_FULL_INFORMATION , Name ) ;
1999-11-23 20:41:34 +01:00
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%d,%p,%p,%p,%p,%p,%p) \n " ,
1999-11-23 20:41:34 +01:00
hkey , index , value , val_count , reserved , type , data , count ) ;
2015-06-30 14:38:06 +02:00
if ( ( data & & ! count ) | | reserved | | ! value | | ! val_count )
return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
2000-12-15 21:57:00 +01:00
total_size = info_size + ( MAX_PATH + 1 ) * sizeof ( WCHAR ) ;
if ( data ) total_size + = * count ;
total_size = min ( sizeof ( buffer ) , total_size ) ;
1999-11-23 20:41:34 +01:00
2000-12-15 21:57:00 +01:00
status = NtEnumerateValueKey ( hkey , index , KeyValueFullInformation ,
buffer , total_size , & total_size ) ;
if ( status & & status ! = STATUS_BUFFER_OVERFLOW ) goto done ;
2000-05-15 00:57:57 +02:00
2000-12-15 21:57:00 +01: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 ) )
2000-05-15 00:57:57 +02:00
{
2000-12-15 21:57:00 +01:00
/* retry with a dynamically allocated buffer */
while ( status = = STATUS_BUFFER_OVERFLOW )
2000-05-15 00:57:57 +02:00
{
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
if ( ! ( buf_ptr = heap_alloc ( total_size ) ) )
2000-12-15 21:57:00 +01:00
return ERROR_NOT_ENOUGH_MEMORY ;
info = ( KEY_VALUE_FULL_INFORMATION * ) buf_ptr ;
status = NtEnumerateValueKey ( hkey , index , KeyValueFullInformation ,
buf_ptr , total_size , & total_size ) ;
}
if ( status ) goto done ;
if ( is_string ( info - > Type ) )
{
2001-12-05 23:18:48 +01:00
DWORD len ;
RtlUnicodeToMultiByteSize ( & len , ( WCHAR * ) ( buf_ptr + info - > DataOffset ) ,
total_size - info - > DataOffset ) ;
2000-12-15 21:57:00 +01:00
if ( data & & len )
{
2002-07-10 05:27:35 +02:00
if ( len > * count ) status = STATUS_BUFFER_OVERFLOW ;
else
2000-12-15 21:57:00 +01:00
{
2005-08-27 12:00:38 +02:00
RtlUnicodeToMultiByteN ( ( char * ) data , len , NULL , ( WCHAR * ) ( buf_ptr + info - > DataOffset ) ,
2002-07-10 05:27:35 +02: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 ;
2000-12-15 21:57:00 +01:00
}
2000-05-15 00:57:57 +02:00
}
2000-12-15 21:57:00 +01:00
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 ) ;
2000-05-15 00:57:57 +02:00
}
2002-07-10 05:27:35 +02: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 ;
}
}
2000-05-15 00:57:57 +02:00
}
2001-02-14 22:45:52 +01:00
else status = STATUS_SUCCESS ;
2000-05-15 00:57:57 +02:00
2000-12-15 21:57:00 +01:00
if ( type ) * type = info - > Type ;
if ( count ) * count = info - > DataLength ;
done :
2014-08-28 15:42:22 +02:00
if ( buf_ptr ! = buffer ) heap_free ( buf_ptr ) ;
2000-12-15 21:57:00 +01:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegDeleteValueW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2003-03-18 19:35:48 +01:00
* See RegDeleteValueA .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegDeleteValueW ( HKEY hkey , LPCWSTR name )
1999-11-23 20:41:34 +01:00
{
2014-06-28 18:15:47 +02:00
return RegDeleteKeyValueW ( hkey , NULL , name ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegDeleteValueA [ ADVAPI32 . @ ]
2003-03-18 19:35:48 +01:00
*
* Delete a value from the registry .
*
* PARAMS
* hkey [ I ] Registry handle of the key holding the value
* name [ I ] Name of the value under hkey to delete
*
* RETURNS
2004-07-14 01:33:14 +02:00
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegDeleteValueA ( HKEY hkey , LPCSTR name )
1999-11-23 20:41:34 +01:00
{
2014-06-28 18:15:47 +02:00
return RegDeleteKeyValueA ( hkey , NULL , name ) ;
}
/******************************************************************************
* RegDeleteKeyValueW [ ADVAPI32 . @ ]
*/
LONG WINAPI RegDeleteKeyValueW ( HKEY hkey , LPCWSTR subkey , LPCWSTR name )
{
2010-04-02 11:50:12 +02:00
UNICODE_STRING nameW ;
2014-06-28 18:15:47 +02:00
HKEY hsubkey = 0 ;
LONG ret ;
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
if ( subkey )
{
if ( ( ret = RegOpenKeyExW ( hkey , subkey , 0 , KEY_SET_VALUE , & hsubkey ) ) )
return ret ;
hkey = hsubkey ;
}
RtlInitUnicodeString ( & nameW , name ) ;
ret = RtlNtStatusToDosError ( NtDeleteValueKey ( hkey , & nameW ) ) ;
if ( hsubkey ) RegCloseKey ( hsubkey ) ;
return ret ;
}
/******************************************************************************
* RegDeleteKeyValueA [ ADVAPI32 . @ ]
*/
LONG WINAPI RegDeleteKeyValueA ( HKEY hkey , LPCSTR subkey , LPCSTR name )
{
UNICODE_STRING nameW ;
HKEY hsubkey = 0 ;
ANSI_STRING nameA ;
2000-10-01 03:44:50 +02:00
NTSTATUS status ;
1999-11-23 20:41:34 +01:00
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
2002-09-13 23:42:28 +02:00
2014-06-28 18:15:47 +02:00
if ( subkey )
{
LONG ret = RegOpenKeyExA ( hkey , subkey , 0 , KEY_SET_VALUE , & hsubkey ) ;
if ( ret )
return ret ;
hkey = hsubkey ;
}
2000-10-01 03:44:50 +02:00
RtlInitAnsiString ( & nameA , name ) ;
2010-04-02 11:50:12 +02:00
if ( ! ( status = RtlAnsiStringToUnicodeString ( & nameW , & nameA , TRUE ) ) )
{
status = NtDeleteValueKey ( hkey , & nameW ) ;
RtlFreeUnicodeString ( & nameW ) ;
}
2014-06-28 18:15:47 +02:00
if ( hsubkey ) RegCloseKey ( hsubkey ) ;
2000-10-01 03:44:50 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegLoadKeyW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2005-11-12 20:12:03 +01:00
* Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
* registration information from a specified file into that subkey .
*
1999-11-23 20:41:34 +01:00
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of open key
* subkey [ I ] Address of name of subkey
* filename [ I ] Address of filename for registry information
*
* RETURNS
2006-11-07 00:37:42 +01:00
* Success : ERROR_SUCCESS
2004-07-14 01:33:14 +02:00
* Failure : nonzero error code from Winerror . h
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegLoadKeyW ( HKEY hkey , LPCWSTR subkey , LPCWSTR filename )
1999-11-23 20:41:34 +01:00
{
2005-03-29 13:38:58 +02:00
OBJECT_ATTRIBUTES destkey , file ;
UNICODE_STRING subkeyW , filenameW ;
2006-10-17 21:32:00 +02:00
NTSTATUS status ;
2005-03-29 13:38:58 +02:00
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
2005-03-29 13:38:58 +02:00
destkey . Length = sizeof ( destkey ) ;
destkey . RootDirectory = hkey ; /* root key: HKLM or HKU */
destkey . ObjectName = & subkeyW ; /* name of the key */
destkey . Attributes = 0 ;
destkey . SecurityDescriptor = NULL ;
destkey . SecurityQualityOfService = NULL ;
RtlInitUnicodeString ( & subkeyW , subkey ) ;
file . Length = sizeof ( file ) ;
file . RootDirectory = NULL ;
file . ObjectName = & filenameW ; /* file containing the hive */
file . Attributes = OBJ_CASE_INSENSITIVE ;
file . SecurityDescriptor = NULL ;
file . SecurityQualityOfService = NULL ;
RtlDosPathNameToNtPathName_U ( filename , & filenameW , NULL , NULL ) ;
2006-10-17 21:32:00 +02:00
status = NtLoadKey ( & destkey , & file ) ;
RtlFreeUnicodeString ( & filenameW ) ;
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegLoadKeyA [ ADVAPI32 . @ ]
*
2005-11-04 12:43:27 +01:00
* See RegLoadKeyW .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegLoadKeyA ( HKEY hkey , LPCSTR subkey , LPCSTR filename )
1999-11-23 20:41:34 +01:00
{
2005-03-29 13:38:58 +02:00
UNICODE_STRING subkeyW , filenameW ;
STRING subkeyA , filenameA ;
NTSTATUS status ;
2006-10-17 21:32:00 +02:00
LONG ret ;
2000-10-15 02:40:25 +02:00
2005-03-29 13:38:58 +02:00
RtlInitAnsiString ( & subkeyA , subkey ) ;
RtlInitAnsiString ( & filenameA , filename ) ;
2000-10-15 02:40:25 +02:00
2006-10-17 21:32:00 +02:00
RtlInitUnicodeString ( & subkeyW , NULL ) ;
RtlInitUnicodeString ( & filenameW , NULL ) ;
if ( ! ( status = RtlAnsiStringToUnicodeString ( & subkeyW , & subkeyA , TRUE ) ) & &
! ( status = RtlAnsiStringToUnicodeString ( & filenameW , & filenameA , TRUE ) ) )
{
ret = RegLoadKeyW ( hkey , subkeyW . Buffer , filenameW . Buffer ) ;
}
else ret = RtlNtStatusToDosError ( status ) ;
RtlFreeUnicodeString ( & subkeyW ) ;
RtlFreeUnicodeString ( & filenameW ) ;
return ret ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegSaveKeyW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
2005-11-12 20:12:03 +01:00
* Save a key and all of its subkeys and values to a new file in the standard format .
*
1999-11-23 20:41:34 +01:00
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of key where save begins
* lpFile [ I ] Address of filename to save to
* sa [ I ] Address of security structure
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegSaveKeyW ( HKEY hkey , LPCWSTR file , LPSECURITY_ATTRIBUTES sa )
1999-11-23 20:41:34 +01:00
{
2003-03-14 05:50:34 +01:00
static const WCHAR format [ ] =
{ ' r ' , ' e ' , ' g ' , ' % ' , ' 0 ' , ' 4 ' , ' x ' , ' . ' , ' t ' , ' m ' , ' p ' , 0 } ;
WCHAR buffer [ MAX_PATH ] ;
1999-11-23 20:41:34 +01:00
int count = 0 ;
2003-03-14 05:50:34 +01:00
LPWSTR nameW ;
1999-11-23 20:41:34 +01:00
DWORD ret , err ;
2002-07-31 21:26:03 +02:00
HANDLE handle ;
1999-11-23 20:41:34 +01:00
2003-03-14 05:50:34 +01:00
TRACE ( " (%p,%s,%p) \n " , hkey , debugstr_w ( file ) , sa ) ;
1999-11-23 20:41:34 +01:00
if ( ! file | | ! * file ) return ERROR_INVALID_PARAMETER ;
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
err = GetLastError ( ) ;
2003-03-14 05:50:34 +01:00
GetFullPathNameW ( file , sizeof ( buffer ) / sizeof ( WCHAR ) , buffer , & nameW ) ;
1999-11-23 20:41:34 +01:00
for ( ; ; )
{
2003-03-14 05:50:34 +01:00
snprintfW ( nameW , 16 , format , count + + ) ;
handle = CreateFileW ( buffer , GENERIC_WRITE , 0 , NULL ,
2001-01-06 02:29:18 +01:00
CREATE_NEW , FILE_ATTRIBUTE_NORMAL , 0 ) ;
1999-11-23 20:41:34 +01:00
if ( handle ! = INVALID_HANDLE_VALUE ) break ;
2006-11-10 12:22:44 +01:00
if ( ( ret = GetLastError ( ) ) ! = ERROR_FILE_EXISTS ) goto done ;
2000-05-10 00:31:43 +02:00
/* Something gone haywire ? Please report if this happens abnormally */
if ( count > = 100 )
2003-03-14 05:50:34 +01:00
MESSAGE ( " Wow, we are already fiddling with a temp file %s with an ordinal as high as %d ! \n You might want to delete all corresponding temp files in that directory. \n " , debugstr_w ( buffer ) , count ) ;
1999-11-23 20:41:34 +01:00
}
2005-03-30 12:21:15 +02:00
ret = RtlNtStatusToDosError ( NtSaveKey ( hkey , handle ) ) ;
2000-10-15 02:40:25 +02:00
1999-11-23 20:41:34 +01:00
CloseHandle ( handle ) ;
if ( ! ret )
{
2003-03-14 05:50:34 +01:00
if ( ! MoveFileExW ( buffer , file , MOVEFILE_REPLACE_EXISTING ) )
1999-11-23 20:41:34 +01:00
{
2003-03-14 05:50:34 +01:00
ERR ( " Failed to move %s to %s \n " , debugstr_w ( buffer ) ,
debugstr_w ( file ) ) ;
1999-11-23 20:41:34 +01:00
ret = GetLastError ( ) ;
}
}
2003-03-14 05:50:34 +01:00
if ( ret ) DeleteFileW ( buffer ) ;
1999-11-23 20:41:34 +01:00
done :
SetLastError ( err ) ; /* restore last error code */
return ret ;
}
/******************************************************************************
2004-07-14 01:33:14 +02:00
* RegSaveKeyA [ ADVAPI32 . @ ]
*
2005-11-04 12:43:27 +01:00
* See RegSaveKeyW .
1999-11-23 20:41:34 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegSaveKeyA ( HKEY hkey , LPCSTR file , LPSECURITY_ATTRIBUTES sa )
1999-11-23 20:41:34 +01:00
{
2003-03-14 05:50:34 +01:00
UNICODE_STRING * fileW = & NtCurrentTeb ( ) - > StaticUnicodeString ;
NTSTATUS status ;
STRING fileA ;
RtlInitAnsiString ( & fileA , file ) ;
if ( ( status = RtlAnsiStringToUnicodeString ( fileW , & fileA , FALSE ) ) )
return RtlNtStatusToDosError ( status ) ;
return RegSaveKeyW ( hkey , fileW - > Buffer , sa ) ;
1999-11-23 20:41:34 +01:00
}
2000-11-30 21:31:41 +01:00
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegRestoreKeyW [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
2005-11-12 20:12:03 +01:00
* Read the registry information from a file and copy it over a key .
*
2000-11-30 21:31:41 +01:00
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of key where restore begins
* lpFile [ I ] Address of filename containing saved tree
* dwFlags [ I ] Optional flags
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegRestoreKeyW ( HKEY hkey , LPCWSTR lpFile , DWORD dwFlags )
2000-11-30 21:31:41 +01:00
{
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%s,%d) \n " , hkey , debugstr_w ( lpFile ) , dwFlags ) ;
2000-11-30 21:31:41 +01:00
/* It seems to do this check before the hkey check */
if ( ! lpFile | | ! * lpFile )
return ERROR_INVALID_PARAMETER ;
2006-10-03 15:48:41 +02:00
FIXME ( " (%p,%s,%d): stub \n " , hkey , debugstr_w ( lpFile ) , dwFlags ) ;
2000-11-30 21:31:41 +01:00
/* Check for file existence */
return ERROR_SUCCESS ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegRestoreKeyA [ ADVAPI32 . @ ]
2004-07-14 01:33:14 +02:00
*
2005-11-04 12:43:27 +01:00
* See RegRestoreKeyW .
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegRestoreKeyA ( HKEY hkey , LPCSTR lpFile , DWORD dwFlags )
2000-11-30 21:31:41 +01:00
{
2003-01-21 00:23:12 +01:00
UNICODE_STRING lpFileW ;
LONG ret ;
RtlCreateUnicodeStringFromAsciiz ( & lpFileW , lpFile ) ;
ret = RegRestoreKeyW ( hkey , lpFileW . Buffer , dwFlags ) ;
RtlFreeUnicodeString ( & lpFileW ) ;
2000-11-30 21:31:41 +01:00
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegUnLoadKeyW [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
2005-11-12 20:12:03 +01:00
* Unload a registry key and its subkeys from the registry .
*
2000-11-30 21:31:41 +01:00
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of open key
* lpSubKey [ I ] Address of name of subkey to unload
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegUnLoadKeyW ( HKEY hkey , LPCWSTR lpSubKey )
2000-11-30 21:31:41 +01:00
{
2003-08-19 05:08:17 +02:00
DWORD ret ;
HKEY shkey ;
2007-01-29 14:55:02 +01:00
OBJECT_ATTRIBUTES attr ;
UNICODE_STRING subkey ;
2003-08-19 05:08:17 +02:00
TRACE ( " (%p,%s) \n " , hkey , debugstr_w ( lpSubKey ) ) ;
ret = RegOpenKeyW ( hkey , lpSubKey , & shkey ) ;
if ( ret )
return ERROR_INVALID_PARAMETER ;
2007-01-29 14:55:02 +01:00
RtlInitUnicodeString ( & subkey , lpSubKey ) ;
InitializeObjectAttributes ( & attr , & subkey , OBJ_CASE_INSENSITIVE , shkey , NULL ) ;
ret = RtlNtStatusToDosError ( NtUnloadKey ( & attr ) ) ;
2005-03-30 12:21:15 +02:00
2003-08-19 05:08:17 +02:00
RegCloseKey ( shkey ) ;
return ret ;
2000-11-30 21:31:41 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegUnLoadKeyA [ ADVAPI32 . @ ]
2004-07-14 01:33:14 +02:00
*
2005-11-04 12:43:27 +01:00
* See RegUnLoadKeyW .
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegUnLoadKeyA ( HKEY hkey , LPCSTR lpSubKey )
2000-11-30 21:31:41 +01:00
{
2003-01-21 00:23:12 +01:00
UNICODE_STRING lpSubKeyW ;
LONG ret ;
RtlCreateUnicodeStringFromAsciiz ( & lpSubKeyW , lpSubKey ) ;
ret = RegUnLoadKeyW ( hkey , lpSubKeyW . Buffer ) ;
RtlFreeUnicodeString ( & lpSubKeyW ) ;
2000-11-30 21:31:41 +01:00
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegReplaceKeyW [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
2005-11-12 20:12:03 +01:00
* Replace the file backing a registry key and all its subkeys with another file .
*
2000-11-30 21:31:41 +01:00
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of open key
* lpSubKey [ I ] Address of name of subkey
* lpNewFile [ I ] Address of filename for file with new data
* lpOldFile [ I ] Address of filename for backup file
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegReplaceKeyW ( HKEY hkey , LPCWSTR lpSubKey , LPCWSTR lpNewFile ,
2000-11-30 21:31:41 +01:00
LPCWSTR lpOldFile )
{
2002-10-25 21:17:33 +02:00
FIXME ( " (%p,%s,%s,%s): stub \n " , hkey , debugstr_w ( lpSubKey ) ,
2000-11-30 21:31:41 +01:00
debugstr_w ( lpNewFile ) , debugstr_w ( lpOldFile ) ) ;
return ERROR_SUCCESS ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegReplaceKeyA [ ADVAPI32 . @ ]
2004-07-14 01:33:14 +02:00
*
2005-11-04 12:43:27 +01:00
* See RegReplaceKeyW .
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegReplaceKeyA ( HKEY hkey , LPCSTR lpSubKey , LPCSTR lpNewFile ,
2000-11-30 21:31:41 +01:00
LPCSTR lpOldFile )
{
2003-01-21 00:23:12 +01:00
UNICODE_STRING lpSubKeyW ;
UNICODE_STRING lpNewFileW ;
UNICODE_STRING lpOldFileW ;
LONG ret ;
RtlCreateUnicodeStringFromAsciiz ( & lpSubKeyW , lpSubKey ) ;
RtlCreateUnicodeStringFromAsciiz ( & lpOldFileW , lpOldFile ) ;
RtlCreateUnicodeStringFromAsciiz ( & lpNewFileW , lpNewFile ) ;
ret = RegReplaceKeyW ( hkey , lpSubKeyW . Buffer , lpNewFileW . Buffer , lpOldFileW . Buffer ) ;
RtlFreeUnicodeString ( & lpOldFileW ) ;
RtlFreeUnicodeString ( & lpNewFileW ) ;
RtlFreeUnicodeString ( & lpSubKeyW ) ;
2000-11-30 21:31:41 +01:00
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegSetKeySecurity [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
2005-11-12 20:12:03 +01:00
* Set the security of an open registry key .
*
2000-11-30 21:31:41 +01:00
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Open handle of key to set
* SecurityInfo [ I ] Descriptor contents
* pSecurityDesc [ I ] Address of descriptor for key
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegSetKeySecurity ( HKEY hkey , SECURITY_INFORMATION SecurityInfo ,
2000-11-30 21:31:41 +01:00
PSECURITY_DESCRIPTOR pSecurityDesc )
{
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%d,%p) \n " , hkey , SecurityInfo , pSecurityDesc ) ;
2000-11-30 21:31:41 +01:00
/* It seems to perform this check before the hkey check */
if ( ( SecurityInfo & OWNER_SECURITY_INFORMATION ) | |
( SecurityInfo & GROUP_SECURITY_INFORMATION ) | |
( SecurityInfo & DACL_SECURITY_INFORMATION ) | |
( SecurityInfo & SACL_SECURITY_INFORMATION ) ) {
/* Param OK */
} else
return ERROR_INVALID_PARAMETER ;
if ( ! pSecurityDesc )
return ERROR_INVALID_PARAMETER ;
2014-07-04 18:10:45 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
2000-11-30 21:31:41 +01:00
2014-07-04 18:10:45 +02:00
return RtlNtStatusToDosError ( NtSetSecurityObject ( hkey , SecurityInfo , pSecurityDesc ) ) ;
2000-11-30 21:31:41 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegGetKeySecurity [ ADVAPI32 . @ ]
2004-04-23 23:32:34 +02:00
*
* Get a copy of the security descriptor for a given registry key .
2000-11-30 21:31:41 +01:00
*
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Open handle of key to set
* SecurityInformation [ I ] Descriptor contents
* pSecurityDescriptor [ O ] Address of descriptor for key
* lpcbSecurityDescriptor [ I / O ] Address of size of buffer and description
2000-11-30 21:31:41 +01:00
*
* RETURNS
2004-07-14 01:33:14 +02:00
* Success : ERROR_SUCCESS
* Failure : Error code
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegGetKeySecurity ( HKEY hkey , SECURITY_INFORMATION SecurityInformation ,
2000-11-30 21:31:41 +01:00
PSECURITY_DESCRIPTOR pSecurityDescriptor ,
LPDWORD lpcbSecurityDescriptor )
{
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%d,%p,%d) \n " , hkey , SecurityInformation , pSecurityDescriptor ,
2008-02-14 15:38:30 +01:00
* lpcbSecurityDescriptor ) ;
2000-11-30 21:31:41 +01:00
2013-10-04 16:44:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey , 0 ) ) ) return ERROR_INVALID_HANDLE ;
2002-04-02 04:41:27 +02:00
2007-03-16 20:21:03 +01:00
return RtlNtStatusToDosError ( NtQuerySecurityObject ( hkey ,
SecurityInformation , pSecurityDescriptor ,
* lpcbSecurityDescriptor , lpcbSecurityDescriptor ) ) ;
2000-11-30 21:31:41 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegFlushKey [ ADVAPI32 . @ ]
2004-04-23 23:32:34 +02:00
*
* Immediately write a registry key to registry .
2000-11-30 21:31:41 +01:00
*
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of key to write
2000-11-30 21:31:41 +01:00
*
* RETURNS
2004-07-14 01:33:14 +02:00
* Success : ERROR_SUCCESS
* Failure : Error code
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegFlushKey ( HKEY hkey )
2000-11-30 21:31:41 +01:00
{
2013-10-04 16:44:28 +02:00
hkey = get_special_root_hkey ( hkey , 0 ) ;
2004-01-03 01:38:30 +01:00
if ( ! hkey ) return ERROR_INVALID_HANDLE ;
return RtlNtStatusToDosError ( NtFlushKey ( hkey ) ) ;
2000-11-30 21:31:41 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegConnectRegistryW [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
2007-04-07 01:46:59 +02:00
* Establish a connection to a predefined registry key on another computer .
2005-11-12 20:12:03 +01:00
*
2000-11-30 21:31:41 +01:00
* PARAMS
2004-07-14 01:33:14 +02:00
* lpMachineName [ I ] Address of name of remote computer
* hHey [ I ] Predefined registry handle
* phkResult [ I ] Address of buffer for remote registry handle
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegConnectRegistryW ( LPCWSTR lpMachineName , HKEY hKey ,
2002-10-03 21:46:27 +02:00
PHKEY phkResult )
2000-11-30 21:31:41 +01:00
{
2004-03-18 02:34:23 +01:00
LONG ret ;
2012-06-26 23:38:13 +02:00
TRACE ( " (%s,%p,%p) \n " , debugstr_w ( lpMachineName ) , hKey , phkResult ) ;
2000-11-30 21:31:41 +01:00
if ( ! lpMachineName | | ! * lpMachineName ) {
/* Use the local machine name */
2004-03-18 02:34:23 +01:00
ret = RegOpenKeyW ( hKey , NULL , phkResult ) ;
2000-11-30 21:31:41 +01:00
}
2005-09-15 11:31:05 +02:00
else {
2004-03-18 02:34:23 +01:00
WCHAR compName [ MAX_COMPUTERNAME_LENGTH + 1 ] ;
DWORD len = sizeof ( compName ) / sizeof ( WCHAR ) ;
2000-11-30 21:31:41 +01:00
2005-09-15 11:31:05 +02:00
/* MSDN says lpMachineName must start with \\ : not so */
if ( lpMachineName [ 0 ] = = ' \\ ' & & lpMachineName [ 1 ] = = ' \\ ' )
lpMachineName + = 2 ;
2004-03-18 02:34:23 +01:00
if ( GetComputerNameW ( compName , & len ) )
{
2005-09-15 11:31:05 +02:00
if ( ! strcmpiW ( lpMachineName , compName ) )
2004-03-18 02:34:23 +01:00
ret = RegOpenKeyW ( hKey , NULL , phkResult ) ;
else
{
2005-09-15 11:31:05 +02:00
FIXME ( " Connect to %s is not supported. \n " , debugstr_w ( lpMachineName ) ) ;
2004-03-18 02:34:23 +01:00
ret = ERROR_BAD_NETPATH ;
}
}
else
ret = GetLastError ( ) ;
}
return ret ;
2000-11-30 21:31:41 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegConnectRegistryA [ ADVAPI32 . @ ]
2004-07-14 01:33:14 +02:00
*
2005-11-04 12:43:27 +01:00
* See RegConnectRegistryW .
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegConnectRegistryA ( LPCSTR machine , HKEY hkey , PHKEY reskey )
2000-11-30 21:31:41 +01:00
{
2003-01-21 00:23:12 +01:00
UNICODE_STRING machineW ;
LONG ret ;
RtlCreateUnicodeStringFromAsciiz ( & machineW , machine ) ;
ret = RegConnectRegistryW ( machineW . Buffer , hkey , reskey ) ;
RtlFreeUnicodeString ( & machineW ) ;
2000-11-30 21:31:41 +01:00
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegNotifyChangeKeyValue [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
2005-11-12 20:12:03 +01:00
* Notify the caller about changes to the attributes or contents of a registry key .
*
2000-11-30 21:31:41 +01:00
* PARAMS
2004-07-14 01:33:14 +02:00
* hkey [ I ] Handle of key to watch
* fWatchSubTree [ I ] Flag for subkey notification
* fdwNotifyFilter [ I ] Changes to be reported
* hEvent [ I ] Handle of signaled event
* fAsync [ I ] Flag for asynchronous reporting
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
2000-11-30 21:31:41 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegNotifyChangeKeyValue ( HKEY hkey , BOOL fWatchSubTree ,
2000-11-30 21:31:41 +01:00
DWORD fdwNotifyFilter , HANDLE hEvent ,
BOOL fAsync )
{
2005-05-16 16:08:11 +02:00
NTSTATUS status ;
IO_STATUS_BLOCK iosb ;
2002-11-25 03:47:32 +01:00
2013-10-04 16:44:28 +02:00
hkey = get_special_root_hkey ( hkey , 0 ) ;
2005-05-16 16:08:11 +02:00
if ( ! hkey ) return ERROR_INVALID_HANDLE ;
2002-11-25 03:47:32 +01:00
2006-10-03 15:48:41 +02:00
TRACE ( " (%p,%i,%d,%p,%i) \n " , hkey , fWatchSubTree , fdwNotifyFilter ,
2005-05-16 16:08:11 +02:00
hEvent , fAsync ) ;
2002-11-25 03:47:32 +01:00
2005-05-16 16:08:11 +02:00
status = NtNotifyChangeKey ( hkey , hEvent , NULL , NULL , & iosb ,
2006-02-09 12:08:47 +01:00
fdwNotifyFilter , fAsync , NULL , 0 ,
fWatchSubTree ) ;
2002-11-25 03:47:32 +01:00
2005-05-16 16:08:11 +02:00
if ( status & & status ! = STATUS_TIMEOUT )
return RtlNtStatusToDosError ( status ) ;
return ERROR_SUCCESS ;
2000-11-30 21:31:41 +01:00
}
2004-01-16 05:40:33 +01:00
/******************************************************************************
* RegOpenUserClassesRoot [ ADVAPI32 . @ ]
2004-04-23 23:32:34 +02:00
*
* Open the HKEY_CLASSES_ROOT key for a user .
2004-01-16 05:40:33 +01:00
*
* PARAMS
2004-07-14 01:33:14 +02:00
* hToken [ I ] Handle of token representing the user
2007-04-07 01:46:59 +02:00
* dwOptions [ I ] Reserved , must be 0
2004-07-14 01:33:14 +02:00
* samDesired [ I ] Desired access rights
* phkResult [ O ] Destination for the resulting key handle
2004-01-16 05:40:33 +01:00
*
2004-07-14 01:33:14 +02:00
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
*
2004-04-23 23:32:34 +02:00
* NOTES
2004-07-14 01:33:14 +02:00
* On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
* " HKEY_LOCAL_MACHINE \ Software \ Classes " and the
* " HKEY_CURRENT_USER \ Software \ Classes " keys merged together .
2004-01-16 05:40:33 +01:00
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegOpenUserClassesRoot (
2004-01-16 05:40:33 +01:00
HANDLE hToken ,
DWORD dwOptions ,
REGSAM samDesired ,
PHKEY phkResult
)
{
2006-10-03 15:48:41 +02:00
FIXME ( " (%p, 0x%x, 0x%x, %p) semi-stub \n " , hToken , dwOptions , samDesired , phkResult ) ;
2004-01-16 05:40:33 +01:00
* phkResult = HKEY_CLASSES_ROOT ;
return ERROR_SUCCESS ;
}
2006-02-14 10:41:18 +01:00
/******************************************************************************
* load_string [ Internal ]
*
* This is basically a copy of user32 / resource . c ' s LoadStringW . Necessary to
* avoid importing user32 , which is higher level than advapi32 . Helper for
* RegLoadMUIString .
*/
static int load_string ( HINSTANCE hModule , UINT resId , LPWSTR pwszBuffer , INT cMaxChars )
{
HGLOBAL hMemory ;
HRSRC hResource ;
WCHAR * pString ;
int idxString ;
/* Negative values have to be inverted. */
if ( HIWORD ( resId ) = = 0xffff )
resId = ( UINT ) ( - ( ( INT ) resId ) ) ;
/* Load the resource into memory and get a pointer to it. */
hResource = FindResourceW ( hModule , MAKEINTRESOURCEW ( LOWORD ( resId > > 4 ) + 1 ) , ( LPWSTR ) RT_STRING ) ;
if ( ! hResource ) return 0 ;
hMemory = LoadResource ( hModule , hResource ) ;
if ( ! hMemory ) return 0 ;
pString = LockResource ( hMemory ) ;
/* Strings are length-prefixed. Lowest nibble of resId is an index. */
idxString = resId & 0xf ;
while ( idxString - - ) pString + = * pString + 1 ;
/* If no buffer is given, return length of the string. */
if ( ! pwszBuffer ) return * pString ;
/* Else copy over the string, respecting the buffer size. */
cMaxChars = ( * pString < cMaxChars ) ? * pString : ( cMaxChars - 1 ) ;
if ( cMaxChars > = 0 ) {
memcpy ( pwszBuffer , pString + 1 , cMaxChars * sizeof ( WCHAR ) ) ;
pwszBuffer [ cMaxChars ] = ' \0 ' ;
}
return cMaxChars ;
}
/******************************************************************************
* RegLoadMUIStringW [ ADVAPI32 . @ ]
*
* Load the localized version of a string resource from some PE , respective
* id and path of which are given in the registry value in the format
* @ [ path ] \ dllname , - resourceId
*
* PARAMS
* hKey [ I ] Key , of which to load the string value from .
* pszValue [ I ] The value to be loaded ( Has to be of REG_EXPAND_SZ or REG_SZ type ) .
* pszBuffer [ O ] Buffer to store the localized string in .
* cbBuffer [ I ] Size of the destination buffer in bytes .
* pcbData [ O ] Number of bytes written to pszBuffer ( optional , may be NULL ) .
* dwFlags [ I ] None supported yet .
* pszBaseDir [ I ] Not supported yet .
*
* RETURNS
* Success : ERROR_SUCCESS ,
* Failure : nonzero error code from winerror . h
*
* NOTES
* This is an API of Windows Vista , which wasn ' t available at the time this code
* was written . We have to check for the correct behaviour once it ' s available .
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegLoadMUIStringW ( HKEY hKey , LPCWSTR pwszValue , LPWSTR pwszBuffer , DWORD cbBuffer ,
2006-02-14 10:41:18 +01:00
LPDWORD pcbData , DWORD dwFlags , LPCWSTR pwszBaseDir )
{
DWORD dwValueType , cbData ;
LPWSTR pwszTempBuffer = NULL , pwszExpandedBuffer = NULL ;
LONG result ;
2006-10-03 15:48:41 +02:00
TRACE ( " (hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2012-06-26 23:38:13 +02:00
" dwFlags = %d, pwszBaseDir = %s) \n " , hKey , debugstr_w ( pwszValue ) , pwszBuffer ,
2006-02-14 10:41:18 +01:00
cbBuffer , pcbData , dwFlags , debugstr_w ( pwszBaseDir ) ) ;
/* Parameter sanity checks. */
if ( ! hKey | | ! pwszBuffer )
return ERROR_INVALID_PARAMETER ;
if ( pwszBaseDir & & * pwszBaseDir ) {
FIXME ( " BaseDir parameter not yet supported! \n " ) ;
return ERROR_INVALID_PARAMETER ;
}
2014-02-07 22:42:49 +01:00
/* Check for value existence and correctness of its type, allocate a buffer and load it. */
2006-02-14 10:41:18 +01:00
result = RegQueryValueExW ( hKey , pwszValue , NULL , & dwValueType , NULL , & cbData ) ;
if ( result ! = ERROR_SUCCESS ) goto cleanup ;
if ( ! ( dwValueType = = REG_SZ | | dwValueType = = REG_EXPAND_SZ ) | | ! cbData ) {
result = ERROR_FILE_NOT_FOUND ;
goto cleanup ;
}
2014-08-28 15:42:22 +02:00
pwszTempBuffer = heap_alloc ( cbData ) ;
2006-02-14 10:41:18 +01:00
if ( ! pwszTempBuffer ) {
result = ERROR_NOT_ENOUGH_MEMORY ;
goto cleanup ;
}
result = RegQueryValueExW ( hKey , pwszValue , NULL , & dwValueType , ( LPBYTE ) pwszTempBuffer , & cbData ) ;
if ( result ! = ERROR_SUCCESS ) goto cleanup ;
/* Expand environment variables, if appropriate, or copy the original string over. */
if ( dwValueType = = REG_EXPAND_SZ ) {
cbData = ExpandEnvironmentStringsW ( pwszTempBuffer , NULL , 0 ) * sizeof ( WCHAR ) ;
if ( ! cbData ) goto cleanup ;
2014-08-28 15:42:22 +02:00
pwszExpandedBuffer = heap_alloc ( cbData ) ;
2006-02-14 10:41:18 +01:00
if ( ! pwszExpandedBuffer ) {
result = ERROR_NOT_ENOUGH_MEMORY ;
goto cleanup ;
}
ExpandEnvironmentStringsW ( pwszTempBuffer , pwszExpandedBuffer , cbData ) ;
} else {
2014-08-28 15:42:22 +02:00
pwszExpandedBuffer = heap_alloc ( cbData ) ;
2006-02-14 10:41:18 +01:00
memcpy ( pwszExpandedBuffer , pwszTempBuffer , cbData ) ;
}
/* If the value references a resource based string, parse the value and load the string.
* Else just copy over the original value . */
result = ERROR_SUCCESS ;
if ( * pwszExpandedBuffer ! = ' @ ' ) { /* '@' is the prefix for resource based string entries. */
lstrcpynW ( pwszBuffer , pwszExpandedBuffer , cbBuffer / sizeof ( WCHAR ) ) ;
} else {
WCHAR * pComma = strrchrW ( pwszExpandedBuffer , ' , ' ) ;
UINT uiStringId ;
HMODULE hModule ;
/* Format of the expanded value is 'path_to_dll,-resId' */
if ( ! pComma | | pComma [ 1 ] ! = ' - ' ) {
result = ERROR_BADKEY ;
goto cleanup ;
}
uiStringId = atoiW ( pComma + 2 ) ;
* pComma = ' \0 ' ;
hModule = LoadLibraryW ( pwszExpandedBuffer + 1 ) ;
if ( ! hModule | | ! load_string ( hModule , uiStringId , pwszBuffer , cbBuffer / sizeof ( WCHAR ) ) )
result = ERROR_BADKEY ;
FreeLibrary ( hModule ) ;
}
cleanup :
2014-08-28 15:42:22 +02:00
heap_free ( pwszTempBuffer ) ;
heap_free ( pwszExpandedBuffer ) ;
2006-02-14 10:41:18 +01:00
return result ;
}
/******************************************************************************
* RegLoadMUIStringA [ ADVAPI32 . @ ]
*
* See RegLoadMUIStringW
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegLoadMUIStringA ( HKEY hKey , LPCSTR pszValue , LPSTR pszBuffer , DWORD cbBuffer ,
2006-02-14 10:41:18 +01:00
LPDWORD pcbData , DWORD dwFlags , LPCSTR pszBaseDir )
{
UNICODE_STRING valueW , baseDirW ;
WCHAR * pwszBuffer ;
DWORD cbData = cbBuffer * sizeof ( WCHAR ) ;
LONG result ;
valueW . Buffer = baseDirW . Buffer = pwszBuffer = NULL ;
if ( ! RtlCreateUnicodeStringFromAsciiz ( & valueW , pszValue ) | |
! RtlCreateUnicodeStringFromAsciiz ( & baseDirW , pszBaseDir ) | |
2014-08-28 15:42:22 +02:00
! ( pwszBuffer = heap_alloc ( cbData ) ) )
2006-02-14 10:41:18 +01:00
{
result = ERROR_NOT_ENOUGH_MEMORY ;
goto cleanup ;
}
result = RegLoadMUIStringW ( hKey , valueW . Buffer , pwszBuffer , cbData , NULL , dwFlags ,
baseDirW . Buffer ) ;
if ( result = = ERROR_SUCCESS ) {
cbData = WideCharToMultiByte ( CP_ACP , 0 , pwszBuffer , - 1 , pszBuffer , cbBuffer , NULL , NULL ) ;
if ( pcbData )
* pcbData = cbData ;
}
cleanup :
2014-08-28 15:42:22 +02:00
heap_free ( pwszBuffer ) ;
2006-02-14 10:41:18 +01:00
RtlFreeUnicodeString ( & baseDirW ) ;
RtlFreeUnicodeString ( & valueW ) ;
return result ;
}
2006-06-30 12:06:48 +02:00
/******************************************************************************
* RegDisablePredefinedCache [ ADVAPI32 . @ ]
*
* Disables the caching of the HKEY_CLASSES_ROOT key for the process .
*
* PARAMS
* None .
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : nonzero error code from Winerror . h
*
* NOTES
* This is useful for services that use impersonation .
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegDisablePredefinedCache ( void )
2006-06-30 12:06:48 +02:00
{
HKEY hkey_current_user ;
2013-01-23 17:55:08 +01:00
int idx = HandleToUlong ( HKEY_CURRENT_USER ) - HandleToUlong ( HKEY_SPECIAL_ROOT_FIRST ) ;
2006-06-30 12:06:48 +02:00
/* prevent caching of future requests */
hkcu_cache_disabled = TRUE ;
hkey_current_user = InterlockedExchangePointer ( ( void * * ) & special_root_keys [ idx ] , NULL ) ;
if ( hkey_current_user )
NtClose ( hkey_current_user ) ;
return ERROR_SUCCESS ;
}
2007-05-25 18:15:54 +02:00
/******************************************************************************
* RegDeleteTreeW [ ADVAPI32 . @ ]
*
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegDeleteTreeW ( HKEY hKey , LPCWSTR lpszSubKey )
2007-05-25 18:15:54 +02:00
{
LONG ret ;
DWORD dwMaxSubkeyLen , dwMaxValueLen ;
DWORD dwMaxLen , dwSize ;
WCHAR szNameBuf [ MAX_PATH ] , * lpszName = szNameBuf ;
HKEY hSubKey = hKey ;
TRACE ( " (hkey=%p,%p %s) \n " , hKey , lpszSubKey , debugstr_w ( lpszSubKey ) ) ;
if ( lpszSubKey )
{
ret = RegOpenKeyExW ( hKey , lpszSubKey , 0 , KEY_READ , & hSubKey ) ;
if ( ret ) return ret ;
}
/* Get highest length for keys, values */
ret = RegQueryInfoKeyW ( hSubKey , NULL , NULL , NULL , NULL ,
& dwMaxSubkeyLen , NULL , NULL , & dwMaxValueLen , NULL , NULL , NULL ) ;
if ( ret ) goto cleanup ;
dwMaxSubkeyLen + + ;
dwMaxValueLen + + ;
dwMaxLen = max ( dwMaxSubkeyLen , dwMaxValueLen ) ;
if ( dwMaxLen > sizeof ( szNameBuf ) / sizeof ( WCHAR ) )
{
/* Name too big: alloc a buffer for it */
2014-08-28 15:42:22 +02:00
if ( ! ( lpszName = heap_alloc ( dwMaxLen * sizeof ( WCHAR ) ) ) )
2007-05-25 18:15:54 +02:00
{
ret = ERROR_NOT_ENOUGH_MEMORY ;
goto cleanup ;
}
}
/* Recursively delete all the subkeys */
while ( TRUE )
{
dwSize = dwMaxLen ;
if ( RegEnumKeyExW ( hSubKey , 0 , lpszName , & dwSize , NULL ,
NULL , NULL , NULL ) ) break ;
ret = RegDeleteTreeW ( hSubKey , lpszName ) ;
if ( ret ) goto cleanup ;
}
if ( lpszSubKey )
ret = RegDeleteKeyW ( hKey , lpszSubKey ) ;
else
while ( TRUE )
{
dwSize = dwMaxLen ;
if ( RegEnumValueW ( hKey , 0 , lpszName , & dwSize ,
NULL , NULL , NULL , NULL ) ) break ;
ret = RegDeleteValueW ( hKey , lpszName ) ;
if ( ret ) goto cleanup ;
}
cleanup :
/* Free buffer if allocated */
if ( lpszName ! = szNameBuf )
2014-08-28 15:42:22 +02:00
heap_free ( lpszName ) ;
2007-05-25 18:15:54 +02:00
if ( lpszSubKey )
RegCloseKey ( hSubKey ) ;
return ret ;
}
/******************************************************************************
* RegDeleteTreeA [ ADVAPI32 . @ ]
*
*/
2007-09-18 00:40:48 +02:00
LSTATUS WINAPI RegDeleteTreeA ( HKEY hKey , LPCSTR lpszSubKey )
2007-05-25 18:15:54 +02:00
{
LONG ret ;
UNICODE_STRING lpszSubKeyW ;
if ( lpszSubKey ) RtlCreateUnicodeStringFromAsciiz ( & lpszSubKeyW , lpszSubKey ) ;
else lpszSubKeyW . Buffer = NULL ;
ret = RegDeleteTreeW ( hKey , lpszSubKeyW . Buffer ) ;
RtlFreeUnicodeString ( & lpszSubKeyW ) ;
return ret ;
}
2012-02-04 04:54:14 +01:00
/******************************************************************************
* RegDisableReflectionKey [ ADVAPI32 . @ ]
*
*/
LONG WINAPI RegDisableReflectionKey ( HKEY base )
{
FIXME ( " %p: stub \n " , base ) ;
return ERROR_SUCCESS ;
}