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
*
* This file is concerned about handle management and interaction with the Wine server .
* Registry file I / O is in misc / registry . c .
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
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
1999-11-23 20:41:34 +01:00
*/
# include <stdlib.h>
2000-02-10 23:15:21 +01:00
# include <stdio.h>
1999-11-23 20:41:34 +01:00
# include "winbase.h"
# include "winreg.h"
# include "winerror.h"
2000-08-14 16:41:19 +02:00
# include "wine/unicode.h"
1999-11-23 20:41:34 +01:00
# include "heap.h"
2001-07-19 02:39:09 +02:00
# include "wine/server.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
/* allowed bits for access mask */
# define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
# define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
# define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
# define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
static HKEY special_root_keys [ NB_SPECIAL_ROOT_KEYS ] ;
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 ' , ' \\ ' ,
' H ' , ' a ' , ' r ' , ' d ' , ' w ' , ' a ' , ' r ' , ' e ' , ' P ' , ' r ' , ' o ' , ' f ' , ' i ' , ' l ' , ' e ' , ' s ' , ' \\ ' ,
' C ' , ' u ' , ' r ' , ' r ' , ' e ' , ' n ' , ' t ' , 0 } ;
static const WCHAR name_DYN_DATA [ ] =
{ ' D ' , ' y ' , ' n ' , ' D ' , ' a ' , ' t ' , ' a ' , 0 } ;
# define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
static UNICODE_STRING root_key_names [ NB_SPECIAL_ROOT_KEYS ] =
{
DECL_STR ( CLASSES_ROOT ) ,
{ 0 , 0 , NULL } , /* HKEY_CURRENT_USER is determined dynamically */
DECL_STR ( LOCAL_MACHINE ) ,
DECL_STR ( USERS ) ,
DECL_STR ( PERFORMANCE_DATA ) ,
DECL_STR ( CURRENT_CONFIG ) ,
DECL_STR ( DYN_DATA )
} ;
# undef DECL_STR
1999-11-23 20:41:34 +01:00
/* check if value type needs string conversion (Ansi<->Unicode) */
2002-03-21 02:24:52 +01:00
inline static int 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 */
inline static int is_version_nt ( void )
{
return ! ( GetVersion ( ) & 0x80000000 ) ;
}
1999-11-23 20:41:34 +01:00
2002-09-13 23:42:28 +02:00
/* create one of the HKEY_* special root keys */
static HKEY create_special_root_hkey ( HKEY hkey , DWORD access )
{
HKEY ret = 0 ;
int idx = ( UINT ) hkey - ( UINT ) HKEY_SPECIAL_ROOT_FIRST ;
if ( hkey = = HKEY_CURRENT_USER )
{
if ( RtlOpenCurrentUser ( access , & hkey ) ) return 0 ;
TRACE ( " HKEY_CURRENT_USER -> %08x \n " , hkey ) ;
}
else
{
OBJECT_ATTRIBUTES attr ;
attr . Length = sizeof ( attr ) ;
attr . RootDirectory = 0 ;
attr . ObjectName = & root_key_names [ idx ] ;
attr . Attributes = 0 ;
attr . SecurityDescriptor = NULL ;
attr . SecurityQualityOfService = NULL ;
if ( NtCreateKey ( & hkey , access , & attr , 0 , NULL , 0 , NULL ) ) return 0 ;
TRACE ( " %s -> %08x \n " , debugstr_w ( attr . ObjectName - > Buffer ) , hkey ) ;
}
if ( ! ( ret = InterlockedCompareExchange ( ( PLONG ) & special_root_keys [ idx ] , hkey , 0 ) ) )
ret = hkey ;
else
NtClose ( hkey ) ; /* somebody beat us to it */
return ret ;
}
/* map the hkey from special root to normal key if necessary */
inline static HKEY get_special_root_hkey ( HKEY hkey )
{
HKEY ret = hkey ;
if ( ( hkey > = HKEY_SPECIAL_ROOT_FIRST ) & & ( hkey < = HKEY_SPECIAL_ROOT_LAST ) )
{
if ( ! ( ret = special_root_keys [ ( UINT ) hkey - ( UINT ) HKEY_SPECIAL_ROOT_FIRST ] ) )
ret = create_special_root_hkey ( hkey , KEY_ALL_ACCESS ) ;
}
return ret ;
}
2002-05-09 21:39:10 +02:00
1999-11-23 20:41:34 +01:00
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegCreateKeyExW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* PARAMS
* hkey [ I ] Handle of an open key
* name [ I ] Address of subkey name
* reserved [ I ] Reserved - must be 0
* class [ I ] Address of class string
* options [ I ] Special options flag
* access [ I ] Desired security access
* sa [ I ] Address of key security structure
* retkey [ O ] Address of buffer for opened handle
* dispos [ O ] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2000-01-09 22:10:18 +01:00
*
* NOTES
2000-01-16 00:38:49 +01:00
* in case of failing retkey remains untouched
2002-05-09 21:39:10 +02:00
*
* FIXME MAXIMUM_ALLOWED in access mask not supported by server
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegCreateKeyExW ( HKEY hkey , LPCWSTR name , DWORD reserved , LPWSTR class ,
2002-06-01 01:06:46 +02:00
DWORD options , REGSAM access , SECURITY_ATTRIBUTES * sa ,
2002-10-03 21:46:27 +02:00
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 ;
2002-05-09 21:39:10 +02:00
if ( ! ( access & KEY_ACCESS_MASK ) | | ( access & ~ KEY_ACCESS_MASK ) ) return ERROR_ACCESS_DENIED ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) 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 ;
RtlInitUnicodeString ( & nameW , name ) ;
RtlInitUnicodeString ( & classW , class ) ;
return RtlNtStatusToDosError ( NtCreateKey ( retkey , access , & attr , 0 ,
& classW , options , dispos ) ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegCreateKeyExA [ ADVAPI32 . @ ]
2002-05-09 21:39:10 +02:00
*
* FIXME MAXIMUM_ALLOWED in access mask not supported by server
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegCreateKeyExA ( HKEY hkey , LPCSTR name , DWORD reserved , LPSTR class ,
2002-06-01 01:06:46 +02:00
DWORD options , REGSAM access , SECURITY_ATTRIBUTES * sa ,
2002-10-03 21:46:27 +02:00
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 ;
2002-03-21 02:24:52 +01:00
if ( ! is_version_nt ( ) ) access = KEY_ALL_ACCESS ; /* Win95 ignores the access mask */
2002-05-09 21:39:10 +02:00
else if ( ! ( access & KEY_ACCESS_MASK ) | | ( access & ~ KEY_ACCESS_MASK ) ) return ERROR_ACCESS_DENIED ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) 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 ;
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 ) ) )
{
status = NtCreateKey ( retkey , access , & attr , 0 , & classW , options , dispos ) ;
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
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegCreateKeyW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
2002-10-03 21:46:27 +02:00
DWORD WINAPI RegCreateKeyW ( HKEY hkey , LPCWSTR name , PHKEY retkey )
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 */
return RegCreateKeyExW ( hkey , name , 0 , NULL , REG_OPTION_NON_VOLATILE ,
KEY_ALL_ACCESS , NULL , retkey , NULL ) ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegCreateKeyA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
2002-10-03 21:46:27 +02:00
DWORD WINAPI RegCreateKeyA ( HKEY hkey , LPCSTR name , PHKEY retkey )
1999-11-23 20:41:34 +01:00
{
return RegCreateKeyExA ( hkey , name , 0 , NULL , REG_OPTION_NON_VOLATILE ,
KEY_ALL_ACCESS , NULL , retkey , NULL ) ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegOpenKeyExW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* Opens the specified key
*
* Unlike RegCreateKeyEx , this does not create the key if it does not exist .
*
* PARAMS
* hkey [ I ] Handle of open key
* name [ I ] Name of subkey to open
* reserved [ I ] Reserved - must be zero
* access [ I ] Security access mask
* retkey [ O ] Handle to open key
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : Error code
2000-01-09 22:10:18 +01:00
*
* NOTES
* in case of failing is retkey = 0
1999-11-23 20:41:34 +01:00
*/
2002-10-03 21:46:27 +02:00
DWORD WINAPI RegOpenKeyExW ( HKEY hkey , LPCWSTR name , DWORD reserved , 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 ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
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 ;
RtlInitUnicodeString ( & nameW , name ) ;
return RtlNtStatusToDosError ( NtOpenKey ( retkey , access , & attr ) ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegOpenKeyExA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
2002-10-03 21:46:27 +02:00
DWORD WINAPI RegOpenKeyExA ( HKEY hkey , LPCSTR name , DWORD reserved , 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 ;
2002-03-21 02:24:52 +01:00
if ( ! is_version_nt ( ) ) access = KEY_ALL_ACCESS ; /* Win95 ignores the access mask */
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
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 ;
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
{
status = NtOpenKey ( retkey , access , & attr ) ;
}
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegOpenKeyW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* PARAMS
* hkey [ I ] Handle of open key
* name [ I ] Address of name of subkey to open
* retkey [ O ] Handle to open key
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : Error code
2000-01-09 22:10:18 +01:00
*
* NOTES
* in case of failing is retkey = 0
1999-11-23 20:41:34 +01:00
*/
2002-10-03 21:46:27 +02:00
DWORD WINAPI RegOpenKeyW ( HKEY hkey , LPCWSTR name , PHKEY retkey )
1999-11-23 20:41:34 +01:00
{
return RegOpenKeyExW ( hkey , name , 0 , KEY_ALL_ACCESS , retkey ) ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegOpenKeyA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
2002-10-03 21:46:27 +02:00
DWORD WINAPI RegOpenKeyA ( HKEY hkey , LPCSTR name , PHKEY retkey )
1999-11-23 20:41:34 +01:00
{
return RegOpenKeyExA ( hkey , name , 0 , KEY_ALL_ACCESS , retkey ) ;
}
2000-10-29 02:24:54 +01:00
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegOpenCurrentUser [ ADVAPI32 . @ ]
2000-10-29 02:24:54 +01:00
* 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 .
*/
DWORD WINAPI RegOpenCurrentUser ( REGSAM access , PHKEY retkey )
{
return RegOpenKeyExA ( HKEY_CURRENT_USER , " " , 0 , access , retkey ) ;
}
1999-11-23 20:41:34 +01:00
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegEnumKeyExW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* PARAMS
* 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
*/
DWORD WINAPI RegEnumKeyExW ( HKEY hkey , DWORD index , LPWSTR name , LPDWORD name_len ,
LPDWORD reserved , LPWSTR class , LPDWORD class_len , FILETIME * ft )
{
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
TRACE ( " (0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p) \n " , hkey , index , name , name_len ,
name_len ? * name_len : - 1 , reserved , class , class_len , ft ) ;
if ( reserved ) return ERROR_INVALID_PARAMETER ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) 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 */
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
if ( ! ( buf_ptr = HeapAlloc ( GetProcessHeap ( ) , 0 , total_size ) ) )
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
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegEnumKeyExA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegEnumKeyExA ( HKEY hkey , DWORD index , LPSTR name , LPDWORD name_len ,
LPDWORD reserved , LPSTR class , LPDWORD class_len , FILETIME * ft )
{
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
TRACE ( " (0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p) \n " , hkey , index , name , name_len ,
name_len ? * name_len : - 1 , reserved , class , class_len , ft ) ;
if ( reserved ) return ERROR_INVALID_PARAMETER ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) 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 */
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
if ( ! ( buf_ptr = HeapAlloc ( GetProcessHeap ( ) , 0 , total_size ) ) )
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
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegEnumKeyW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegEnumKeyW ( HKEY hkey , DWORD index , LPWSTR name , DWORD name_len )
{
return RegEnumKeyExW ( hkey , index , name , & name_len , NULL , NULL , NULL , NULL ) ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegEnumKeyA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegEnumKeyA ( HKEY hkey , DWORD index , LPSTR name , DWORD name_len )
{
return RegEnumKeyExA ( hkey , index , name , & name_len , NULL , NULL , NULL , NULL ) ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegQueryInfoKeyW [ ADVAPI32 . @ ]
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
*
2002-06-01 01:06:46 +02:00
* - win95 allows class to be valid and class_len to be NULL
1999-11-23 20:41:34 +01:00
* - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
2002-06-01 01:06:46 +02:00
* - both allow class to be NULL and class_len to be NULL
1999-11-23 20:41:34 +01:00
* ( it ' s hard to test validity , so test ! NULL instead )
*/
DWORD WINAPI RegQueryInfoKeyW ( HKEY hkey , LPWSTR class , LPDWORD class_len , LPDWORD reserved ,
LPDWORD subkeys , LPDWORD max_subkey , LPDWORD max_class ,
LPDWORD values , LPDWORD max_value , LPDWORD max_data ,
LPDWORD security , FILETIME * modif )
{
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
TRACE ( " (0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p) \n " , hkey , class , class_len ? * class_len : 0 ,
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 ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) 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
if ( class )
{
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
{
2000-10-02 05:46:58 +02:00
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
if ( ! ( buf_ptr = HeapAlloc ( GetProcessHeap ( ) , 0 , total_size ) ) )
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
{
2001-02-14 22:45:52 +01:00
status = STATUS_BUFFER_OVERFLOW ;
}
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 :
2000-10-02 05:46:58 +02:00
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
2002-07-20 22:02:55 +02:00
/******************************************************************************
* RegQueryMultipleValuesA [ ADVAPI32 . @ ]
*/
DWORD WINAPI RegQueryMultipleValuesA ( HKEY hkey , PVALENTA val_list , DWORD num_vals ,
LPSTR lpValueBuf , LPDWORD ldwTotsize )
{
int i ;
DWORD maxBytes = * ldwTotsize ;
HRESULT status ;
LPSTR bufptr = lpValueBuf ;
* ldwTotsize = 0 ;
TRACE ( " (%x,%p,%ld,%p,%p=%ld) \n " , hkey , val_list , num_vals , lpValueBuf , ldwTotsize , * ldwTotsize ) ;
for ( i = 0 ; i < num_vals ; + + i )
{
val_list [ i ] . ve_valuelen = 0 ;
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 ,
bufptr , & val_list [ i ] . ve_valuelen ) ;
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 ;
}
/******************************************************************************
* RegQueryMultipleValuesW [ ADVAPI32 . @ ]
*/
DWORD WINAPI RegQueryMultipleValuesW ( HKEY hkey , PVALENTW val_list , DWORD num_vals ,
LPWSTR lpValueBuf , LPDWORD ldwTotsize )
{
int i ;
DWORD maxBytes = * ldwTotsize ;
HRESULT status ;
LPSTR bufptr = ( LPSTR ) lpValueBuf ;
* ldwTotsize = 0 ;
TRACE ( " (%x,%p,%ld,%p,%p=%ld) \n " , hkey , val_list , num_vals , lpValueBuf , ldwTotsize , * ldwTotsize ) ;
for ( i = 0 ; i < num_vals ; + + i )
{
val_list [ i ] . ve_valuelen = 0 ;
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 ,
bufptr , & val_list [ i ] . ve_valuelen ) ;
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
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegQueryInfoKeyA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegQueryInfoKeyA ( HKEY hkey , LPSTR class , LPDWORD class_len , LPDWORD reserved ,
LPDWORD subkeys , LPDWORD max_subkey , LPDWORD max_class ,
LPDWORD values , LPDWORD max_value , LPDWORD max_data ,
LPDWORD security , FILETIME * modif )
{
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
TRACE ( " (0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p) \n " , hkey , class , class_len ? * class_len : 0 ,
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 ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) 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 )
{
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
if ( ! ( buf_ptr = HeapAlloc ( GetProcessHeap ( ) , 0 , total_size ) ) )
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 ;
2001-12-05 23:18:48 +01:00
RtlUnicodeToMultiByteSize ( & len , ( WCHAR * ) ( buf_ptr + info - > ClassOffset ) , info - > ClassLength ) ;
2001-02-14 22:45:52 +01:00
if ( class_len )
1999-11-23 20:41:34 +01:00
{
2001-02-14 22:45:52 +01:00
if ( len + 1 > * class_len ) status = STATUS_BUFFER_OVERFLOW ;
* class_len = len ;
}
if ( class & & ! status )
{
2001-12-05 23:18:48 +01:00
RtlUnicodeToMultiByteN ( class , len , NULL , ( WCHAR * ) ( buf_ptr + info - > ClassOffset ) ,
info - > ClassLength ) ;
2001-02-14 22:45:52 +01:00
class [ len ] = 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 ( 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 :
2000-10-02 05:46:58 +02:00
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegCloseKey [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* Releases the handle of the specified key
*
* PARAMS
* hkey [ I ] Handle of key to close
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : Error code
*/
DWORD WINAPI RegCloseKey ( HKEY hkey )
{
2002-07-31 21:26:03 +02:00
if ( ! hkey | | 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
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegDeleteKeyW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* PARAMS
* hkey [ I ] Handle to open key
* name [ I ] Name of subkey to delete
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : Error code
*/
DWORD WINAPI RegDeleteKeyW ( HKEY hkey , LPCWSTR name )
{
DWORD ret ;
2000-10-01 03:44:50 +02:00
HKEY tmp ;
1999-11-23 20:41:34 +01:00
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
2002-06-15 01:35:37 +02:00
if ( ! name | | ! * name )
2000-10-01 03:44:50 +02:00
{
2002-06-15 01:35:37 +02:00
ret = RtlNtStatusToDosError ( NtDeleteKey ( hkey ) ) ;
}
2002-09-12 22:47:14 +02:00
else if ( ! ( ret = RegOpenKeyExW ( hkey , name , 0 , KEY_ENUMERATE_SUB_KEYS , & tmp ) ) )
2002-06-15 01:35:37 +02:00
{
if ( ! is_version_nt ( ) ) /* win95 does recursive key deletes */
{
WCHAR name [ MAX_PATH ] ;
while ( ! RegEnumKeyW ( tmp , 0 , name , sizeof name ) )
{
if ( RegDeleteKeyW ( tmp , name ) ) /* recurse */
break ;
}
}
2000-10-01 03:44:50 +02:00
ret = RtlNtStatusToDosError ( NtDeleteKey ( tmp ) ) ;
RegCloseKey ( tmp ) ;
}
2002-06-15 01:35:37 +02:00
TRACE ( " %s ret=%08lx \n " , debugstr_w ( name ) , ret ) ;
2000-10-01 03:44:50 +02:00
return ret ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegDeleteKeyA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegDeleteKeyA ( HKEY hkey , LPCSTR name )
{
DWORD ret ;
2000-10-01 03:44:50 +02:00
HKEY tmp ;
1999-11-23 20:41:34 +01:00
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
2002-06-15 01:35:37 +02:00
if ( ! name | | ! * name )
2000-10-01 03:44:50 +02:00
{
2002-06-15 01:35:37 +02:00
ret = RtlNtStatusToDosError ( NtDeleteKey ( hkey ) ) ;
}
2002-09-12 22:47:14 +02:00
else if ( ! ( ret = RegOpenKeyExA ( hkey , name , 0 , KEY_ENUMERATE_SUB_KEYS , & tmp ) ) )
2002-06-15 01:35:37 +02:00
{
if ( ! is_version_nt ( ) ) /* win95 does recursive key deletes */
{
CHAR name [ MAX_PATH ] ;
while ( ! RegEnumKeyA ( tmp , 0 , name , sizeof name ) )
{
if ( RegDeleteKeyA ( tmp , name ) ) /* recurse */
break ;
}
}
2000-10-01 03:44:50 +02:00
ret = RtlNtStatusToDosError ( NtDeleteKey ( tmp ) ) ;
RegCloseKey ( tmp ) ;
}
2002-06-15 01:35:37 +02:00
TRACE ( " %s ret=%08lx \n " , debugstr_a ( name ) , ret ) ;
2000-10-01 03:44:50 +02:00
return ret ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegSetValueExW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* Sets the data and type of a value under a register key
*
* PARAMS
* hkey [ I ] Handle of key to set value for
* name [ I ] Name of value to set
* reserved [ I ] Reserved - must be zero
* type [ I ] Flag for value type
* data [ I ] Address of value data
* count [ I ] Size of value data
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : Error code
*
* NOTES
2002-06-01 01:06:46 +02:00
* win95 does not care about count for REG_SZ and finds out the len by itself ( js )
1999-11-23 20:41:34 +01:00
* NT does definitely care ( aj )
*/
DWORD WINAPI RegSetValueExW ( HKEY hkey , LPCWSTR name , DWORD reserved ,
DWORD type , CONST BYTE * data , DWORD count )
{
2000-10-01 03:44:50 +02:00
UNICODE_STRING nameW ;
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
{
if ( type = = REG_SZ ) count = ( strlenW ( ( WCHAR * ) data ) + 1 ) * sizeof ( WCHAR ) ;
}
else 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 ) ;
}
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) 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
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegSetValueExA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegSetValueExA ( HKEY hkey , LPCSTR name , DWORD reserved , DWORD type ,
2000-10-01 03:44:50 +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 ;
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
{
if ( type = = REG_SZ ) count = strlen ( data ) + 1 ;
}
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
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
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 ;
RtlMultiByteToUnicodeSize ( & lenW , data , count ) ;
if ( ! ( dataW = HeapAlloc ( GetProcessHeap ( ) , 0 , lenW ) ) ) return ERROR_OUTOFMEMORY ;
RtlMultiByteToUnicodeN ( dataW , lenW , NULL , data , count ) ;
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 ) ;
2001-03-23 20:12:01 +01:00
if ( ! ( status = RtlAnsiStringToUnicodeString ( & NtCurrentTeb ( ) - > StaticUnicodeString ,
& nameA , FALSE ) ) )
2000-10-01 03:44:50 +02:00
{
2001-03-23 20:12:01 +01:00
status = NtSetValueKey ( hkey , & NtCurrentTeb ( ) - > StaticUnicodeString , 0 , type , data , count ) ;
2000-05-15 00:57:57 +02:00
}
2000-10-01 03:44:50 +02:00
if ( dataW ) HeapFree ( GetProcessHeap ( ) , 0 , dataW ) ;
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegSetValueW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegSetValueW ( HKEY hkey , LPCWSTR name , DWORD type , LPCWSTR data , DWORD count )
{
HKEY subkey = hkey ;
DWORD ret ;
TRACE ( " (0x%x,%s,%ld,%s,%ld) \n " , hkey , debugstr_w ( name ) , type , debugstr_w ( data ) , count ) ;
if ( type ! = REG_SZ ) return ERROR_INVALID_PARAMETER ;
if ( name & & name [ 0 ] ) /* need to create the subkey */
{
if ( ( ret = RegCreateKeyW ( hkey , name , & subkey ) ) ! = ERROR_SUCCESS ) return ret ;
}
ret = RegSetValueExW ( subkey , NULL , 0 , REG_SZ , ( LPBYTE ) data ,
2000-08-14 16:41:19 +02:00
( strlenW ( data ) + 1 ) * sizeof ( WCHAR ) ) ;
1999-11-23 20:41:34 +01:00
if ( subkey ! = hkey ) RegCloseKey ( subkey ) ;
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegSetValueA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegSetValueA ( HKEY hkey , LPCSTR name , DWORD type , LPCSTR data , DWORD count )
{
HKEY subkey = hkey ;
DWORD ret ;
TRACE ( " (0x%x,%s,%ld,%s,%ld) \n " , hkey , debugstr_a ( name ) , type , debugstr_a ( data ) , count ) ;
if ( type ! = REG_SZ ) return ERROR_INVALID_PARAMETER ;
if ( name & & name [ 0 ] ) /* need to create the subkey */
{
if ( ( ret = RegCreateKeyA ( hkey , name , & subkey ) ) ! = ERROR_SUCCESS ) return ret ;
}
ret = RegSetValueExA ( subkey , NULL , 0 , REG_SZ , ( LPBYTE ) data , strlen ( data ) + 1 ) ;
if ( subkey ! = hkey ) RegCloseKey ( subkey ) ;
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegQueryValueExW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* Retrieves type and data for a specified name associated with an open key
*
* PARAMS
* hkey [ I ] Handle of key to query
* name [ I ] Name of value to query
* reserved [ I ] Reserved - must be NULL
* type [ O ] Address of buffer for value type . If NULL , the type
* is not required .
* data [ O ] Address of data buffer . If NULL , the actual data is
* not required .
* count [ I / O ] Address of data buffer size
*
2002-06-01 01:06:46 +02:00
* RETURNS
1999-11-23 20:41:34 +01:00
* ERROR_SUCCESS : Success
* ERROR_MORE_DATA : ! ! ! if the specified buffer is not big enough to hold the data
* buffer is left untouched . The MS - documentation is wrong ( js ) ! ! !
*/
DWORD WINAPI RegQueryValueExW ( HKEY hkey , LPCWSTR name , LPDWORD reserved , LPDWORD type ,
2000-10-01 03:44:50 +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
TRACE ( " (0x%x,%s,%p,%p,%p,%p=%ld) \n " ,
hkey , debugstr_w ( name ) , reserved , type , data , count , count ? * count : 0 ) ;
1999-11-25 23:05:46 +01:00
if ( ( data & & ! count ) | | reserved ) return ERROR_INVALID_PARAMETER ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) 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 ) ;
else total_size = info_size ;
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
{
2000-10-01 03:44:50 +02:00
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
if ( ! ( buf_ptr = HeapAlloc ( GetProcessHeap ( ) , 0 , 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 :
2000-10-02 05:46:58 +02:00
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
2000-10-01 03:44:50 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegQueryValueExA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* NOTES :
2002-06-01 01:06:46 +02:00
* the documentation is wrong : if the buffer is too small it remains untouched
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegQueryValueExA ( HKEY hkey , LPCSTR name , LPDWORD reserved , LPDWORD type ,
2000-10-01 03:44:50 +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 ;
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
TRACE ( " (0x%x,%s,%p,%p,%p,%p=%ld) \n " ,
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 ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
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-02 05:46:58 +02:00
return RtlNtStatusToDosError ( status ) ;
2000-05-15 00:57:57 +02:00
2001-03-23 20:12:01 +01:00
status = NtQueryValueKey ( hkey , & NtCurrentTeb ( ) - > StaticUnicodeString ,
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
{
2000-10-01 03:44:50 +02:00
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
if ( ! ( buf_ptr = HeapAlloc ( GetProcessHeap ( ) , 0 , 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 ;
2001-03-23 20:12:01 +01:00
status = NtQueryValueKey ( hkey , & NtCurrentTeb ( ) - > StaticUnicodeString ,
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
{
2001-02-14 22:45:52 +01:00
if ( len > * count ) status = STATUS_BUFFER_OVERFLOW ;
else
2000-10-01 03:44:50 +02:00
{
2001-12-05 23:18:48 +01:00
RtlUnicodeToMultiByteN ( data , len , NULL , ( WCHAR * ) ( buf_ptr + info_size ) ,
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 */
if ( len < * count & & 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 )
{
if ( total_size - info_size > * count ) status = STATUS_BUFFER_OVERFLOW ;
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 :
2000-10-02 05:46:58 +02:00
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
2000-10-01 03:44:50 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegQueryValueW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegQueryValueW ( HKEY hkey , LPCWSTR name , LPWSTR data , LPLONG count )
{
DWORD ret ;
HKEY subkey = hkey ;
TRACE ( " (%x,%s,%p,%ld) \n " , hkey , debugstr_w ( name ) , data , count ? * count : 0 ) ;
if ( name & & name [ 0 ] )
{
if ( ( ret = RegOpenKeyW ( hkey , name , & subkey ) ) ! = ERROR_SUCCESS ) return ret ;
}
ret = RegQueryValueExW ( subkey , NULL , NULL , NULL , ( LPBYTE ) data , count ) ;
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 ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegQueryValueA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegQueryValueA ( HKEY hkey , LPCSTR name , LPSTR data , LPLONG count )
{
DWORD ret ;
HKEY subkey = hkey ;
TRACE ( " (%x,%s,%p,%ld) \n " , hkey , debugstr_a ( name ) , data , count ? * count : 0 ) ;
if ( name & & name [ 0 ] )
{
if ( ( ret = RegOpenKeyA ( hkey , name , & subkey ) ) ! = ERROR_SUCCESS ) return ret ;
}
ret = RegQueryValueExA ( subkey , NULL , NULL , NULL , ( LPBYTE ) data , count ) ;
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 ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegEnumValueW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* PARAMS
* hkey [ I ] Handle to key to query
* index [ I ] Index of value to query
* value [ O ] Value string
* val_count [ I / O ] Size of value buffer ( in wchars )
* reserved [ I ] Reserved
* type [ O ] Type code
* data [ O ] Value data
* count [ I / O ] Size of data buffer ( in bytes )
*/
DWORD WINAPI RegEnumValueW ( HKEY hkey , DWORD index , LPWSTR value , LPDWORD val_count ,
LPDWORD reserved , LPDWORD type , LPBYTE data , LPDWORD count )
{
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
TRACE ( " (%x,%ld,%p,%p,%p,%p,%p,%p) \n " ,
hkey , index , value , val_count , reserved , type , data , count ) ;
/* NT only checks count, not val_count */
1999-11-25 23:05:46 +01:00
if ( ( data & & ! count ) | | reserved ) return ERROR_INVALID_PARAMETER ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) 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 ;
1999-11-23 20:41:34 +01:00
2000-12-15 21:57:00 +01:00
if ( value | | data )
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 )
{
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
if ( ! ( buf_ptr = HeapAlloc ( GetProcessHeap ( ) , 0 , 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 ) ;
}
if ( status ) goto done ;
if ( value )
{
if ( info - > NameLength / sizeof ( WCHAR ) > = * val_count )
{
status = STATUS_BUFFER_OVERFLOW ;
2002-07-10 05:27:35 +02:00
goto overflow ;
2000-12-15 21:57:00 +01:00
}
memcpy ( value , info - > Name , info - > NameLength ) ;
* val_count = info - > NameLength / sizeof ( WCHAR ) ;
value [ * val_count ] = 0 ;
}
if ( data )
2000-05-15 00:57:57 +02:00
{
2000-12-15 21:57:00 +01:00
if ( total_size - info - > DataOffset > * count )
2000-05-15 00:57:57 +02:00
{
2000-12-15 21:57:00 +01:00
status = STATUS_BUFFER_OVERFLOW ;
2002-07-10 05:27:35 +02:00
goto overflow ;
2000-12-15 21:57:00 +01:00
}
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
}
}
}
2001-02-14 22:45:52 +01: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 :
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegEnumValueA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegEnumValueA ( HKEY hkey , DWORD index , LPSTR value , LPDWORD val_count ,
LPDWORD reserved , LPDWORD type , LPBYTE data , LPDWORD count )
{
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
TRACE ( " (%x,%ld,%p,%p,%p,%p,%p,%p) \n " ,
hkey , index , value , val_count , reserved , type , data , count ) ;
/* NT only checks count, not val_count */
1999-11-25 23:05:46 +01:00
if ( ( data & & ! count ) | | reserved ) return ERROR_INVALID_PARAMETER ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) 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
{
2000-12-15 21:57:00 +01:00
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
if ( ! ( buf_ptr = HeapAlloc ( GetProcessHeap ( ) , 0 , 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 ) ;
}
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
{
2002-07-10 05:27:35 +02:00
RtlUnicodeToMultiByteN ( data , len , NULL , ( WCHAR * ) ( buf_ptr + info - > DataOffset ) ,
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 :
if ( buf_ptr ! = buffer ) HeapFree ( GetProcessHeap ( ) , 0 , buf_ptr ) ;
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegDeleteValueW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* PARAMS
* hkey [ I ] handle to key
* name [ I ] name of value to delete
*
* RETURNS
* error status
*/
DWORD WINAPI RegDeleteValueW ( HKEY hkey , LPCWSTR name )
{
2000-10-01 03:44:50 +02:00
UNICODE_STRING nameW ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
2000-10-01 03:44:50 +02:00
RtlInitUnicodeString ( & nameW , name ) ;
return RtlNtStatusToDosError ( NtDeleteValueKey ( hkey , & nameW ) ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegDeleteValueA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
DWORD WINAPI RegDeleteValueA ( HKEY hkey , LPCSTR name )
{
2000-10-01 03:44:50 +02:00
STRING nameA ;
NTSTATUS status ;
1999-11-23 20:41:34 +01:00
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
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 ) ) )
status = NtDeleteValueKey ( hkey , & NtCurrentTeb ( ) - > StaticUnicodeString ) ;
2000-10-01 03:44:50 +02:00
return RtlNtStatusToDosError ( status ) ;
1999-11-23 20:41:34 +01:00
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegLoadKeyW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* PARAMS
* hkey [ I ] Handle of open key
* subkey [ I ] Address of name of subkey
* filename [ I ] Address of filename for registry information
*/
LONG WINAPI RegLoadKeyW ( HKEY hkey , LPCWSTR subkey , LPCWSTR filename )
{
HANDLE file ;
2000-10-15 02:40:25 +02:00
DWORD ret , len , err = GetLastError ( ) ;
1999-11-23 20:41:34 +01:00
TRACE ( " (%x,%s,%s) \n " , hkey , debugstr_w ( subkey ) , debugstr_w ( filename ) ) ;
if ( ! filename | | ! * filename ) return ERROR_INVALID_PARAMETER ;
if ( ! subkey | | ! * subkey ) return ERROR_INVALID_PARAMETER ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
2000-10-15 02:40:25 +02:00
len = strlenW ( subkey ) * sizeof ( WCHAR ) ;
if ( len > MAX_PATH * sizeof ( WCHAR ) ) return ERROR_INVALID_PARAMETER ;
1999-11-23 20:41:34 +01:00
if ( ( file = CreateFileW ( filename , GENERIC_READ , 0 , NULL , OPEN_EXISTING ,
2001-01-06 02:29:18 +01:00
FILE_ATTRIBUTE_NORMAL , 0 ) ) = = INVALID_HANDLE_VALUE )
1999-11-23 20:41:34 +01:00
{
ret = GetLastError ( ) ;
goto done ;
}
2000-10-15 02:40:25 +02:00
2001-11-30 19:46:42 +01:00
SERVER_START_REQ ( load_registry )
2000-10-15 02:40:25 +02:00
{
req - > hkey = hkey ;
req - > file = file ;
2001-11-30 19:46:42 +01:00
wine_server_add_data ( req , subkey , len ) ;
ret = RtlNtStatusToDosError ( wine_server_call ( req ) ) ;
2000-10-15 02:40:25 +02:00
}
2001-11-30 19:46:42 +01:00
SERVER_END_REQ ;
1999-11-23 20:41:34 +01:00
CloseHandle ( file ) ;
done :
SetLastError ( err ) ; /* restore the last error code */
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegLoadKeyA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
LONG WINAPI RegLoadKeyA ( HKEY hkey , LPCSTR subkey , LPCSTR filename )
{
2001-11-30 19:46:42 +01:00
WCHAR buffer [ MAX_PATH ] ;
1999-11-23 20:41:34 +01:00
HANDLE file ;
2000-10-15 02:40:25 +02:00
DWORD ret , len , err = GetLastError ( ) ;
1999-11-23 20:41:34 +01:00
TRACE ( " (%x,%s,%s) \n " , hkey , debugstr_a ( subkey ) , debugstr_a ( filename ) ) ;
if ( ! filename | | ! * filename ) return ERROR_INVALID_PARAMETER ;
if ( ! subkey | | ! * subkey ) return ERROR_INVALID_PARAMETER ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
2001-11-30 19:46:42 +01:00
if ( ! ( len = MultiByteToWideChar ( CP_ACP , 0 , subkey , strlen ( subkey ) , buffer , MAX_PATH ) ) )
return ERROR_INVALID_PARAMETER ;
2000-10-15 02:40:25 +02:00
1999-11-23 20:41:34 +01:00
if ( ( file = CreateFileA ( filename , GENERIC_READ , 0 , NULL , OPEN_EXISTING ,
2001-01-06 02:29:18 +01:00
FILE_ATTRIBUTE_NORMAL , 0 ) ) = = INVALID_HANDLE_VALUE )
1999-11-23 20:41:34 +01:00
{
ret = GetLastError ( ) ;
goto done ;
}
2000-10-15 02:40:25 +02:00
2001-11-30 19:46:42 +01:00
SERVER_START_REQ ( load_registry )
2000-10-15 02:40:25 +02:00
{
req - > hkey = hkey ;
req - > file = file ;
2001-11-30 19:46:42 +01:00
wine_server_add_data ( req , buffer , len * sizeof ( WCHAR ) ) ;
ret = RtlNtStatusToDosError ( wine_server_call ( req ) ) ;
2000-10-15 02:40:25 +02:00
}
2001-11-30 19:46:42 +01:00
SERVER_END_REQ ;
1999-11-23 20:41:34 +01:00
CloseHandle ( file ) ;
done :
SetLastError ( err ) ; /* restore the last error code */
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegSaveKeyA [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*
* PARAMS
* hkey [ I ] Handle of key where save begins
* lpFile [ I ] Address of filename to save to
* sa [ I ] Address of security structure
*/
LONG WINAPI RegSaveKeyA ( HKEY hkey , LPCSTR file , LPSECURITY_ATTRIBUTES sa )
{
char buffer [ 1024 ] ;
int count = 0 ;
LPSTR name ;
DWORD ret , err ;
2002-07-31 21:26:03 +02:00
HANDLE handle ;
1999-11-23 20:41:34 +01:00
TRACE ( " (%x,%s,%p) \n " , hkey , debugstr_a ( file ) , sa ) ;
if ( ! file | | ! * file ) return ERROR_INVALID_PARAMETER ;
2002-09-13 23:42:28 +02:00
if ( ! ( hkey = get_special_root_hkey ( hkey ) ) ) return ERROR_INVALID_HANDLE ;
1999-11-23 20:41:34 +01:00
err = GetLastError ( ) ;
GetFullPathNameA ( file , sizeof ( buffer ) , buffer , & name ) ;
for ( ; ; )
{
sprintf ( name , " reg%04x.tmp " , count + + ) ;
handle = CreateFileA ( 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 ;
2000-03-26 20:18:03 +02:00
if ( ( ret = GetLastError ( ) ) ! = ERROR_ALREADY_EXISTS ) goto done ;
2000-05-10 00:31:43 +02:00
/* Something gone haywire ? Please report if this happens abnormally */
if ( count > = 100 )
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 " , buffer , count ) ;
1999-11-23 20:41:34 +01:00
}
2001-02-27 03:09:16 +01:00
SERVER_START_REQ ( save_registry )
2000-10-15 02:40:25 +02:00
{
req - > hkey = hkey ;
req - > file = handle ;
2001-11-30 19:46:42 +01:00
ret = RtlNtStatusToDosError ( wine_server_call ( req ) ) ;
2000-10-15 02:40:25 +02:00
}
SERVER_END_REQ ;
1999-11-23 20:41:34 +01:00
CloseHandle ( handle ) ;
if ( ! ret )
{
if ( ! MoveFileExA ( buffer , file , MOVEFILE_REPLACE_EXISTING ) )
{
ERR ( " Failed to move %s to %s \n " , buffer , file ) ;
ret = GetLastError ( ) ;
}
}
if ( ret ) DeleteFileA ( buffer ) ;
done :
SetLastError ( err ) ; /* restore last error code */
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegSaveKeyW [ ADVAPI32 . @ ]
1999-11-23 20:41:34 +01:00
*/
LONG WINAPI RegSaveKeyW ( HKEY hkey , LPCWSTR file , LPSECURITY_ATTRIBUTES sa )
{
LPSTR fileA = HEAP_strdupWtoA ( GetProcessHeap ( ) , 0 , file ) ;
DWORD ret = RegSaveKeyA ( hkey , fileA , sa ) ;
if ( fileA ) HeapFree ( GetProcessHeap ( ) , 0 , fileA ) ;
return ret ;
}
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
*
* PARAMS
* hkey [ I ] Handle of key where restore begins
* lpFile [ I ] Address of filename containing saved tree
* dwFlags [ I ] Optional flags
*/
LONG WINAPI RegRestoreKeyW ( HKEY hkey , LPCWSTR lpFile , DWORD dwFlags )
{
TRACE ( " (%x,%s,%ld) \n " , hkey , debugstr_w ( lpFile ) , dwFlags ) ;
/* It seems to do this check before the hkey check */
if ( ! lpFile | | ! * lpFile )
return ERROR_INVALID_PARAMETER ;
FIXME ( " (%x,%s,%ld): stub \n " , hkey , debugstr_w ( lpFile ) , dwFlags ) ;
/* Check for file existence */
return ERROR_SUCCESS ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegRestoreKeyA [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*/
LONG WINAPI RegRestoreKeyA ( HKEY hkey , LPCSTR lpFile , DWORD dwFlags )
{
LPWSTR lpFileW = HEAP_strdupAtoW ( GetProcessHeap ( ) , 0 , lpFile ) ;
LONG ret = RegRestoreKeyW ( hkey , lpFileW , dwFlags ) ;
HeapFree ( GetProcessHeap ( ) , 0 , lpFileW ) ;
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegUnLoadKeyW [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
* PARAMS
* hkey [ I ] Handle of open key
* lpSubKey [ I ] Address of name of subkey to unload
*/
LONG WINAPI RegUnLoadKeyW ( HKEY hkey , LPCWSTR lpSubKey )
{
FIXME ( " (%x,%s): stub \n " , hkey , debugstr_w ( lpSubKey ) ) ;
return ERROR_SUCCESS ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegUnLoadKeyA [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*/
LONG WINAPI RegUnLoadKeyA ( HKEY hkey , LPCSTR lpSubKey )
{
LPWSTR lpSubKeyW = HEAP_strdupAtoW ( GetProcessHeap ( ) , 0 , lpSubKey ) ;
LONG ret = RegUnLoadKeyW ( hkey , lpSubKeyW ) ;
if ( lpSubKeyW ) HeapFree ( GetProcessHeap ( ) , 0 , lpSubKeyW ) ;
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegReplaceKeyW [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
* PARAMS
* 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
*/
LONG WINAPI RegReplaceKeyW ( HKEY hkey , LPCWSTR lpSubKey , LPCWSTR lpNewFile ,
LPCWSTR lpOldFile )
{
2002-06-01 01:06:46 +02:00
FIXME ( " (%x,%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 . @ ]
2000-11-30 21:31:41 +01:00
*/
LONG WINAPI RegReplaceKeyA ( HKEY hkey , LPCSTR lpSubKey , LPCSTR lpNewFile ,
LPCSTR lpOldFile )
{
LPWSTR lpSubKeyW = HEAP_strdupAtoW ( GetProcessHeap ( ) , 0 , lpSubKey ) ;
LPWSTR lpNewFileW = HEAP_strdupAtoW ( GetProcessHeap ( ) , 0 , lpNewFile ) ;
LPWSTR lpOldFileW = HEAP_strdupAtoW ( GetProcessHeap ( ) , 0 , lpOldFile ) ;
LONG ret = RegReplaceKeyW ( hkey , lpSubKeyW , lpNewFileW , lpOldFileW ) ;
HeapFree ( GetProcessHeap ( ) , 0 , lpOldFileW ) ;
HeapFree ( GetProcessHeap ( ) , 0 , lpNewFileW ) ;
HeapFree ( GetProcessHeap ( ) , 0 , lpSubKeyW ) ;
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegSetKeySecurity [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
* PARAMS
* hkey [ I ] Open handle of key to set
* SecurityInfo [ I ] Descriptor contents
* pSecurityDesc [ I ] Address of descriptor for key
*/
LONG WINAPI RegSetKeySecurity ( HKEY hkey , SECURITY_INFORMATION SecurityInfo ,
PSECURITY_DESCRIPTOR pSecurityDesc )
{
TRACE ( " (%x,%ld,%p) \n " , hkey , SecurityInfo , pSecurityDesc ) ;
/* 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 ;
FIXME ( " :(%x,%ld,%p): stub \n " , hkey , SecurityInfo , pSecurityDesc ) ;
return ERROR_SUCCESS ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegGetKeySecurity [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
* Retrieves a copy of security descriptor protecting the registry key
*
* PARAMS
* 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
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : Error code
*/
LONG WINAPI RegGetKeySecurity ( HKEY hkey , SECURITY_INFORMATION SecurityInformation ,
PSECURITY_DESCRIPTOR pSecurityDescriptor ,
LPDWORD lpcbSecurityDescriptor )
{
TRACE ( " (%x,%ld,%p,%ld) \n " , hkey , SecurityInformation , pSecurityDescriptor ,
lpcbSecurityDescriptor ? * lpcbSecurityDescriptor : 0 ) ;
/* FIXME: Check for valid SecurityInformation values */
if ( * lpcbSecurityDescriptor < sizeof ( SECURITY_DESCRIPTOR ) )
return ERROR_INSUFFICIENT_BUFFER ;
FIXME ( " (%x,%ld,%p,%ld): stub \n " , hkey , SecurityInformation ,
pSecurityDescriptor , lpcbSecurityDescriptor ? * lpcbSecurityDescriptor : 0 ) ;
2002-04-02 04:41:27 +02:00
/* Do not leave security descriptor filled with garbage */
RtlCreateSecurityDescriptor ( pSecurityDescriptor , SECURITY_DESCRIPTOR_REVISION ) ;
2000-11-30 21:31:41 +01:00
return ERROR_SUCCESS ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegFlushKey [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
* Immediately writes key to registry .
* Only returns after data has been written to disk .
*
* FIXME : does it really wait until data is written ?
*
* PARAMS
* hkey [ I ] Handle of key to write
*
* RETURNS
* Success : ERROR_SUCCESS
* Failure : Error code
*/
DWORD WINAPI RegFlushKey ( HKEY hkey )
{
FIXME ( " (%x): stub \n " , hkey ) ;
return ERROR_SUCCESS ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegConnectRegistryW [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
* PARAMS
* lpMachineName [ I ] Address of name of remote computer
* hHey [ I ] Predefined registry handle
* phkResult [ I ] Address of buffer for remote registry handle
*/
2002-06-01 01:06:46 +02:00
LONG WINAPI RegConnectRegistryW ( LPCWSTR lpMachineName , HKEY hKey ,
2002-10-03 21:46:27 +02:00
PHKEY phkResult )
2000-11-30 21:31:41 +01:00
{
TRACE ( " (%s,%x,%p): stub \n " , debugstr_w ( lpMachineName ) , hKey , phkResult ) ;
if ( ! lpMachineName | | ! * lpMachineName ) {
/* Use the local machine name */
return RegOpenKeyA ( hKey , " " , phkResult ) ;
}
FIXME ( " Cannot connect to %s \n " , debugstr_w ( lpMachineName ) ) ;
return ERROR_BAD_NETPATH ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegConnectRegistryA [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*/
2002-10-03 21:46:27 +02:00
LONG WINAPI RegConnectRegistryA ( LPCSTR machine , HKEY hkey , PHKEY reskey )
2000-11-30 21:31:41 +01:00
{
LPWSTR machineW = HEAP_strdupAtoW ( GetProcessHeap ( ) , 0 , machine ) ;
DWORD ret = RegConnectRegistryW ( machineW , hkey , reskey ) ;
HeapFree ( GetProcessHeap ( ) , 0 , machineW ) ;
return ret ;
}
/******************************************************************************
2001-02-15 00:11:17 +01:00
* RegNotifyChangeKeyValue [ ADVAPI32 . @ ]
2000-11-30 21:31:41 +01:00
*
* PARAMS
* 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
*/
2002-06-01 01:06:46 +02:00
LONG WINAPI RegNotifyChangeKeyValue ( HKEY hkey , BOOL fWatchSubTree ,
2000-11-30 21:31:41 +01:00
DWORD fdwNotifyFilter , HANDLE hEvent ,
BOOL fAsync )
{
FIXME ( " (%x,%i,%ld,%x,%i): stub \n " , hkey , fWatchSubTree , fdwNotifyFilter ,
hEvent , fAsync ) ;
return ERROR_SUCCESS ;
}