diff --git a/dlls/advapi32/Makefile.in b/dlls/advapi32/Makefile.in index ac610c94735..db5015ecb45 100644 --- a/dlls/advapi32/Makefile.in +++ b/dlls/advapi32/Makefile.in @@ -1,6 +1,7 @@ EXTRADEFS = -D_ADVAPI32_ MODULE = advapi32.dll IMPORTLIB = advapi32 +IMPORTS = kernelbase DELAYIMPORTS = rpcrt4 EXTRALIBS = $(SECURITY_LIBS) diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec index fa96d189c22..cc767fb0904 100644 --- a/dlls/advapi32/advapi32.spec +++ b/dlls/advapi32/advapi32.spec @@ -272,7 +272,7 @@ # @ stub EncryptionDisable @ stdcall EnumDependentServicesA(long long ptr long ptr ptr) @ stdcall EnumDependentServicesW(long long ptr long ptr ptr) -@ stdcall EnumDynamicTimeZoneInformation(long ptr) EnumDynamicTimeZoneInformation +@ stdcall -import EnumDynamicTimeZoneInformation(long ptr) @ stub EnumServiceGroupA @ stub EnumServiceGroupW @ stdcall EnumServicesStatusA (long long long ptr long ptr ptr ptr) @@ -611,89 +611,89 @@ @ stdcall ReadEncryptedFileRaw(ptr ptr ptr) @ stdcall ReadEventLogA (long long long ptr long ptr ptr) @ stdcall ReadEventLogW (long long long ptr long ptr ptr) -@ stdcall RegCloseKey(long) +@ stdcall -import RegCloseKey(long) @ stdcall RegConnectRegistryA(str long ptr) # @ stub RegConnectRegistryExA # @ stub RegConnectRegistryExW @ stdcall RegConnectRegistryW(wstr long ptr) @ stdcall RegCopyTreeA(long str long) -@ stdcall RegCopyTreeW(long wstr long) +@ stdcall -import RegCopyTreeW(long wstr long) @ stdcall RegCreateKeyA(long str ptr) -@ stdcall RegCreateKeyExA(long str long ptr long long ptr ptr ptr) -@ stdcall RegCreateKeyExW(long wstr long ptr long long ptr ptr ptr) +@ stdcall -import RegCreateKeyExA(long str long ptr long long ptr ptr ptr) +@ stdcall -import RegCreateKeyExW(long wstr long ptr long long ptr ptr ptr) @ stdcall RegCreateKeyTransactedA(long str long ptr long long ptr ptr ptr long ptr) @ stdcall RegCreateKeyTransactedW(long wstr long ptr long long ptr ptr ptr long ptr) @ stdcall RegCreateKeyW(long wstr ptr) @ stdcall RegDeleteKeyA(long str) -@ stdcall RegDeleteKeyExA(long str long long) -@ stdcall RegDeleteKeyExW(long wstr long long) +@ stdcall -import RegDeleteKeyExA(long str long long) +@ stdcall -import RegDeleteKeyExW(long wstr long long) # @ stub RegDeleteKeyTransactedA # @ stub RegDeleteKeyTransactedW -@ stdcall RegDeleteKeyValueA(long str str) -@ stdcall RegDeleteKeyValueW(long wstr wstr) +@ stdcall -import RegDeleteKeyValueA(long str str) +@ stdcall -import RegDeleteKeyValueW(long wstr wstr) @ stdcall RegDeleteKeyW(long wstr) -@ stdcall RegDeleteTreeA(long str) -@ stdcall RegDeleteTreeW(long wstr) -@ stdcall RegDeleteValueA(long str) -@ stdcall RegDeleteValueW(long wstr) +@ stdcall -import RegDeleteTreeA(long str) +@ stdcall -import RegDeleteTreeW(long wstr) +@ stdcall -import RegDeleteValueA(long str) +@ stdcall -import RegDeleteValueW(long wstr) @ stdcall RegDisablePredefinedCache() # @ stub RegDisablePredefinedCacheEx @ stdcall RegDisableReflectionKey(ptr) # @ stub RegEnableReflectionKey @ stdcall RegEnumKeyA(long long ptr long) -@ stdcall RegEnumKeyExA(long long ptr ptr ptr ptr ptr ptr) -@ stdcall RegEnumKeyExW(long long ptr ptr ptr ptr ptr ptr) +@ stdcall -import RegEnumKeyExA(long long ptr ptr ptr ptr ptr ptr) +@ stdcall -import RegEnumKeyExW(long long ptr ptr ptr ptr ptr ptr) @ stdcall RegEnumKeyW(long long ptr long) -@ stdcall RegEnumValueA(long long ptr ptr ptr ptr ptr ptr) -@ stdcall RegEnumValueW(long long ptr ptr ptr ptr ptr ptr) -@ stdcall RegFlushKey(long) -@ stdcall RegGetKeySecurity(long long ptr ptr) -@ stdcall RegGetValueA(long str str long ptr ptr ptr) -@ stdcall RegGetValueW(long wstr wstr long ptr ptr ptr) -@ stdcall RegLoadAppKeyA(str ptr long long long) -@ stdcall RegLoadAppKeyW(wstr ptr long long long) -@ stdcall RegLoadKeyA(long str str) -@ stdcall RegLoadKeyW(long wstr wstr) -@ stdcall RegLoadMUIStringA(long str str long ptr long str) -@ stdcall RegLoadMUIStringW(long wstr wstr long ptr long wstr) -@ stdcall RegNotifyChangeKeyValue(long long long long long) -@ stdcall RegOpenCurrentUser(long ptr) +@ stdcall -import RegEnumValueA(long long ptr ptr ptr ptr ptr ptr) +@ stdcall -import RegEnumValueW(long long ptr ptr ptr ptr ptr ptr) +@ stdcall -import RegFlushKey(long) +@ stdcall -import RegGetKeySecurity(long long ptr ptr) +@ stdcall -import RegGetValueA(long str str long ptr ptr ptr) +@ stdcall -import RegGetValueW(long wstr wstr long ptr ptr ptr) +@ stdcall -import RegLoadAppKeyA(str ptr long long long) +@ stdcall -import RegLoadAppKeyW(wstr ptr long long long) +@ stdcall -import RegLoadKeyA(long str str) +@ stdcall -import RegLoadKeyW(long wstr wstr) +@ stdcall -import RegLoadMUIStringA(long str str long ptr long str) +@ stdcall -import RegLoadMUIStringW(long wstr wstr long ptr long wstr) +@ stdcall -import RegNotifyChangeKeyValue(long long long long long) +@ stdcall -import RegOpenCurrentUser(long ptr) @ stdcall RegOpenKeyA(long str ptr) -@ stdcall RegOpenKeyExA(long str long long ptr) -@ stdcall RegOpenKeyExW(long wstr long long ptr) +@ stdcall -import RegOpenKeyExA(long str long long ptr) +@ stdcall -import RegOpenKeyExW(long wstr long long ptr) # @ stub RegOpenKeyTransactedA # @ stub RegOpenKeyTransactedW @ stdcall RegOpenKeyW(long wstr ptr) -@ stdcall RegOpenUserClassesRoot(ptr long long ptr) +@ stdcall -import RegOpenUserClassesRoot(ptr long long ptr) @ stdcall RegOverridePredefKey(long long) -@ stdcall RegQueryInfoKeyA(long ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stdcall RegQueryInfoKeyW(long ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall -import RegQueryInfoKeyA(long ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall -import RegQueryInfoKeyW(long ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall RegQueryMultipleValuesA(long ptr long ptr ptr) @ stdcall RegQueryMultipleValuesW(long ptr long ptr ptr) @ stdcall RegQueryReflectionKey(long ptr) @ stdcall RegQueryValueA(long str ptr ptr) -@ stdcall RegQueryValueExA(long str ptr ptr ptr ptr) -@ stdcall RegQueryValueExW(long wstr ptr ptr ptr ptr) +@ stdcall -import RegQueryValueExA(long str ptr ptr ptr ptr) +@ stdcall -import RegQueryValueExW(long wstr ptr ptr ptr ptr) @ stdcall RegQueryValueW(long wstr ptr ptr) @ stub RegRemapPreDefKey # @ stub RegRenameKey @ stdcall RegReplaceKeyA(long str str str) @ stdcall RegReplaceKeyW(long wstr wstr wstr) -@ stdcall RegRestoreKeyA(long str long) -@ stdcall RegRestoreKeyW(long wstr long) +@ stdcall -import RegRestoreKeyA(long str long) +@ stdcall -import RegRestoreKeyW(long wstr long) @ stdcall RegSaveKeyA(long ptr ptr) -@ stdcall RegSaveKeyExA(long str ptr long) -@ stdcall RegSaveKeyExW(long wstr ptr long) +@ stdcall -import RegSaveKeyExA(long str ptr long) +@ stdcall -import RegSaveKeyExW(long wstr ptr long) @ stdcall RegSaveKeyW(long ptr ptr) -@ stdcall RegSetKeySecurity(long long ptr) -@ stdcall RegSetKeyValueA(long str str long ptr long) -@ stdcall RegSetKeyValueW(long wstr wstr long ptr long) +@ stdcall -import RegSetKeySecurity(long long ptr) +@ stdcall -import RegSetKeyValueA(long str str long ptr long) +@ stdcall -import RegSetKeyValueW(long wstr wstr long ptr long) @ stdcall RegSetValueA(long str long ptr long) -@ stdcall RegSetValueExA(long str long long ptr long) -@ stdcall RegSetValueExW(long wstr long long ptr long) +@ stdcall -import RegSetValueExA(long str long long ptr long) +@ stdcall -import RegSetValueExW(long wstr long long ptr long) @ stdcall RegSetValueW(long wstr long ptr long) -@ stdcall RegUnLoadKeyA(long str) -@ stdcall RegUnLoadKeyW(long wstr) +@ stdcall -import RegUnLoadKeyA(long str) +@ stdcall -import RegUnLoadKeyW(long wstr) @ stdcall RegisterEventSourceA(str str) @ stdcall RegisterEventSourceW(wstr wstr) # @ stub RegisterIdleTask diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c index 2d2c1be4dce..b8b168496f0 100644 --- a/dlls/advapi32/registry.c +++ b/dlls/advapi32/registry.c @@ -24,8 +24,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" - #include #include #include @@ -37,10 +35,6 @@ #include "winreg.h" #include "winerror.h" #include "winternl.h" -#include "winperf.h" -#include "winuser.h" -#include "sddl.h" -#include "advapi32_misc.h" #include "wine/unicode.h" #include "wine/debug.h" @@ -48,306 +42,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(reg); -#define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT -#define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA - -static const WCHAR name_CLASSES_ROOT[] = - {'\\','R','e','g','i','s','t','r','y','\\', - '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[] = - {'\\','R','e','g','i','s','t','r','y','\\', - 'M','a','c','h','i','n','e',0}; -static const WCHAR name_USERS[] = - {'\\','R','e','g','i','s','t','r','y','\\', - 'U','s','e','r',0}; -static const WCHAR name_PERFORMANCE_DATA[] = - {'\\','R','e','g','i','s','t','r','y','\\', - 'P','e','r','f','D','a','t','a',0}; -static const WCHAR name_CURRENT_CONFIG[] = - {'\\','R','e','g','i','s','t','r','y','\\', - '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[] = - {'\\','R','e','g','i','s','t','r','y','\\', - 'D','y','n','D','a','t','a',0}; - -static const WCHAR * const root_key_names[] = -{ - name_CLASSES_ROOT, - NULL, /* HKEY_CURRENT_USER is determined dynamically */ - name_LOCAL_MACHINE, - name_USERS, - name_PERFORMANCE_DATA, - name_CURRENT_CONFIG, - name_DYN_DATA -}; - -static HKEY special_root_keys[ARRAY_SIZE(root_key_names)]; -static BOOL hkcu_cache_disabled; - -static CRITICAL_SECTION reg_mui_cs; -static CRITICAL_SECTION_DEBUG reg_mui_cs_debug = -{ - 0, 0, ®_mui_cs, - { ®_mui_cs_debug.ProcessLocksList, - ®_mui_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": reg_mui_cs") } -}; -static CRITICAL_SECTION reg_mui_cs = { ®_mui_cs_debug, -1, 0, 0, 0, 0 }; -struct mui_cache_entry { - struct list entry; - WCHAR *file_name; /* full path name */ - DWORD index; - LCID locale; - WCHAR *text; -}; -static struct list reg_mui_cache = LIST_INIT(reg_mui_cache); /* MRU */ -static unsigned int reg_mui_cache_count; -#define REG_MUI_CACHE_SIZE 8 - -static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); - -/* check if value type needs string conversion (Ansi<->Unicode) */ -static inline BOOL is_string( DWORD type ) -{ - return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ); -} - -/* check if current version is NT or Win95 */ -static inline BOOL is_version_nt(void) -{ - return !(GetVersion() & 0x80000000); -} - -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) && - !strncmpiW( name->Buffer, wow6432nodeW, ARRAY_SIZE( wow6432nodeW ))); -} - -/* open the Wow6432Node subkey of the specified key */ -static HANDLE open_wow6432node( HANDLE key ) -{ - 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 (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) ret = 0; - return ret; -} - -/* 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 ) -{ - BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); - NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; - HANDLE subkey, root = attr->RootDirectory; - - if (!force_wow32) status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos ); - - if (status == STATUS_OBJECT_NAME_NOT_FOUND) - { - static const WCHAR registry_root[] = {'\\','R','e','g','i','s','t','r','y','\\'}; - WCHAR *buffer = attr->ObjectName->Buffer; - DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); - UNICODE_STRING str; - - /* don't try to create registry root */ - if (!attr->RootDirectory && len > ARRAY_SIZE( registry_root ) && - !strncmpiW( buffer, registry_root, ARRAY_SIZE( registry_root ))) - i += ARRAY_SIZE( registry_root ); - - while (i < len && buffer[i] != '\\') i++; - if (i == len && !force_wow32) return status; - - attrs = attr->Attributes; - attr->ObjectName = &str; - - for (;;) - { - str.Buffer = buffer + pos; - str.Length = (i - pos) * sizeof(WCHAR); - if (force_wow32 && pos) - { - if (is_wow6432node( &str )) force_wow32 = FALSE; - else if ((subkey = open_wow6432node( attr->RootDirectory ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - force_wow32 = FALSE; - } - } - if (i == len) - { - attr->Attributes = attrs; - status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos ); - } - else - { - attr->Attributes = attrs & ~OBJ_OPENLINK; - status = NtCreateKey( &subkey, access, attr, 0, class, - options & ~REG_OPTION_CREATE_LINK, dispos ); - } - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - if (status) return status; - if (i == len) break; - attr->RootDirectory = subkey; - while (i < len && buffer[i] == '\\') i++; - pos = i; - while (i < len && buffer[i] != '\\') i++; - } - } - attr->RootDirectory = subkey; - if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - } - *retkey = attr->RootDirectory; - return status; -} - -/* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ -static NTSTATUS open_key( HKEY *retkey, DWORD options, 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 pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); - UNICODE_STRING str; - - *retkey = NULL; - - if (!force_wow32) - { - if (options & REG_OPTION_OPEN_LINK) attr->Attributes |= OBJ_OPENLINK; - return NtOpenKeyEx( (HANDLE *)retkey, access, attr, options ); - } - - if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID; - while (i < len && buffer[i] != '\\') i++; - attr->ObjectName = &str; - - for (;;) - { - str.Buffer = buffer + pos; - str.Length = (i - pos) * sizeof(WCHAR); - if (force_wow32 && pos) - { - if (is_wow6432node( &str )) force_wow32 = FALSE; - else if ((subkey = open_wow6432node( attr->RootDirectory ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - force_wow32 = FALSE; - } - } - if (i == len) - { - if (options & REG_OPTION_OPEN_LINK) attr->Attributes |= OBJ_OPENLINK; - status = NtOpenKeyEx( &subkey, access, attr, options ); - } - else - { - if (!(options & REG_OPTION_OPEN_LINK)) attr->Attributes &= ~OBJ_OPENLINK; - status = NtOpenKeyEx( &subkey, access, attr, options & ~REG_OPTION_OPEN_LINK ); - } - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - if (status) return status; - attr->RootDirectory = subkey; - if (i == len) break; - while (i < len && buffer[i] == '\\') i++; - pos = i; - while (i < len && buffer[i] != '\\') i++; - } - if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - } - *retkey = attr->RootDirectory; - return status; -} - -/* create one of the HKEY_* special root keys */ -static HKEY create_special_root_hkey( HKEY hkey, DWORD access ) -{ - HKEY ret = 0; - int idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST); - - if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER)) - { - if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0; - TRACE( "HKEY_CURRENT_USER -> %p\n", hkey ); - - /* don't cache the key in the table if caching is disabled */ - if (hkcu_cache_disabled) - return hkey; - } - else - { - OBJECT_ATTRIBUTES attr; - UNICODE_STRING name; - - attr.Length = sizeof(attr); - attr.RootDirectory = 0; - attr.ObjectName = &name; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - RtlInitUnicodeString( &name, root_key_names[idx] ); - if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0; - TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey ); - } - - 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 */ - } - else - ret = hkey; - return ret; -} - -/* map the hkey from special root to normal key if necessary */ -static inline HKEY get_special_root_hkey( HKEY hkey, REGSAM access ) -{ - HKEY ret = hkey; - - if ((HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) - && (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST))) - { - 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) ); - } - return ret; -} +NTSTATUS WINAPI RemapPredefinedHandleInternal( HKEY hkey, HKEY override ); +NTSTATUS WINAPI DisablePredefinedHandleTableInternal( HKEY hkey ); /****************************************************************************** @@ -355,119 +51,7 @@ static inline HKEY get_special_root_hkey( HKEY hkey, REGSAM access ) */ LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override ) { - HKEY old_key; - int idx; - - TRACE("(%p %p)\n", hkey, override); - - if ((HandleToUlong(hkey) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) - || (HandleToUlong(hkey) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST))) - return ERROR_INVALID_PARAMETER; - idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST); - - 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; -} - - -/****************************************************************************** - * RegCreateKeyExW [ADVAPI32.@] - * - * See RegCreateKeyExA. - */ -LSTATUS WINAPI DECLSPEC_HOTPATCH RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class, - DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, - PHKEY retkey, LPDWORD dispos ) -{ - OBJECT_ATTRIBUTES attr; - UNICODE_STRING nameW, classW; - - if (reserved) return ERROR_INVALID_PARAMETER; - if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; - - attr.Length = sizeof(attr); - attr.RootDirectory = hkey; - attr.ObjectName = &nameW; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; - RtlInitUnicodeString( &nameW, name ); - RtlInitUnicodeString( &classW, class ); - - return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) ); -} - - -/****************************************************************************** - * RegCreateKeyExA [ADVAPI32.@] - * - * Open a registry key, creating it if it doesn't exist. - * - * PARAMS - * 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 - * - * RETURNS - * Success: ERROR_SUCCESS. - * Failure: A standard Win32 error code. retkey remains untouched. - * - * FIXME - * MAXIMUM_ALLOWED in access mask not supported by server - */ -LSTATUS WINAPI DECLSPEC_HOTPATCH RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class, - DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, - PHKEY retkey, LPDWORD dispos ) -{ - OBJECT_ATTRIBUTES attr; - UNICODE_STRING classW; - ANSI_STRING nameA, classA; - NTSTATUS status; - - if (reserved) return ERROR_INVALID_PARAMETER; - if (!is_version_nt()) - { - access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */ - if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */ - } - if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; - - attr.Length = sizeof(attr); - attr.RootDirectory = hkey; - attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; - RtlInitAnsiString( &nameA, name ); - RtlInitAnsiString( &classA, class ); - - if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString, - &nameA, FALSE ))) - { - if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE ))) - { - status = create_key( retkey, access, &attr, &classW, options, dispos ); - RtlFreeUnicodeString( &classW ); - } - } - return RtlNtStatusToDosError( status ); + return RtlNtStatusToDosError( RemapPredefinedHandleInternal( hkey, override )); } @@ -487,8 +71,6 @@ LSTATUS WINAPI DECLSPEC_HOTPATCH RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD */ LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult ) { - /* 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, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, phkResult, NULL ); } @@ -532,101 +114,6 @@ LSTATUS WINAPI RegCreateKeyTransactedA( HKEY hkey, LPCSTR name, DWORD reserved, } -/****************************************************************************** - * RegOpenKeyExW [ADVAPI32.@] - * - * See RegOpenKeyExA. - */ -LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey ) -{ - OBJECT_ATTRIBUTES attr; - UNICODE_STRING nameW; - - if (retkey && (!name || !name[0]) && - (HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) && - (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST))) - { - *retkey = hkey; - return ERROR_SUCCESS; - } - - /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */ - if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++; - - if (!retkey) return ERROR_INVALID_PARAMETER; - if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; - - attr.Length = sizeof(attr); - attr.RootDirectory = hkey; - attr.ObjectName = &nameW; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - RtlInitUnicodeString( &nameW, name ); - return RtlNtStatusToDosError( open_key( retkey, options, access, &attr ) ); -} - - -/****************************************************************************** - * RegOpenKeyExA [ADVAPI32.@] - * - * Open a registry key. - * - * PARAMS - * hkey [I] Handle of open key - * name [I] Name of subkey to open - * options [I] Open options (can be set to REG_OPTION_OPEN_LINK) - * access [I] Security access mask - * retkey [O] Handle to open key - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: A standard Win32 error code. retkey is set to 0. - * - * NOTES - * Unlike RegCreateKeyExA(), this function will not create the key if it - * does not exist. - */ -LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey ) -{ - OBJECT_ATTRIBUTES attr; - STRING nameA; - NTSTATUS status; - - if (retkey && (!name || !name[0]) && - (HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) && - (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST))) - { - *retkey = hkey; - return ERROR_SUCCESS; - } - - if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */ - else - { - /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */ - if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++; - } - - if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; - - attr.Length = sizeof(attr); - attr.RootDirectory = hkey; - attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - - RtlInitAnsiString( &nameA, name ); - if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString, - &nameA, FALSE ))) - { - status = open_key( retkey, options, access, &attr ); - } - return RtlNtStatusToDosError( status ); -} - - /****************************************************************************** * RegOpenKeyW [ADVAPI32.@] * @@ -648,7 +135,7 @@ LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey ) /****************************************************************************** * RegOpenKeyA [ADVAPI32.@] - * + * * Open a registry key. * * PARAMS @@ -673,225 +160,6 @@ LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey ) return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey ); } -static WCHAR *get_thread_token_user_sid(HANDLE token) -{ - WCHAR *sidstring = NULL; - TOKEN_USER *info; - DWORD len = 0; - - GetTokenInformation(token, TokenUser, NULL, 0, &len); - - info = heap_alloc(len); - if (GetTokenInformation(token, TokenUser, info, len, &len)) - ConvertSidToStringSidW(info->User.Sid, &sidstring); - heap_free(info); - - return sidstring; -} - -/****************************************************************************** - * RegOpenCurrentUser [ADVAPI32.@] - * - * 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. - */ -LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey ) -{ - WCHAR *sidstring = NULL; - HANDLE threadtoken; - LSTATUS ret; - - /* get current user SID */ - if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &threadtoken)) - { - sidstring = get_thread_token_user_sid(threadtoken); - CloseHandle(threadtoken); - } - - if (!sidstring) - { - ImpersonateSelf(SecurityIdentification); - if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &threadtoken)) - { - sidstring = get_thread_token_user_sid(threadtoken); - CloseHandle(threadtoken); - } - RevertToSelf(); - } - - if (sidstring) - { - ret = RegOpenKeyExW( HKEY_USERS, sidstring, 0, access, retkey ); - LocalFree(sidstring); - } - else - ret = RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey ); - - return ret; -} - - - -/****************************************************************************** - * RegEnumKeyExW [ADVAPI32.@] - * - * Enumerate subkeys of the specified open registry key. - * - * 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 - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: System error code. If there are no more subkeys available, the - * function returns ERROR_NO_MORE_ITEMS. - */ -LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len, - LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft ) -{ - NTSTATUS status; - char buffer[256], *buf_ptr = buffer; - KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; - DWORD total_size; - - 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 ); - - if (reserved) return ERROR_INVALID_PARAMETER; - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - status = NtEnumerateKey( hkey, index, KeyNodeInformation, - buffer, sizeof(buffer), &total_size ); - - while (status == STATUS_BUFFER_OVERFLOW) - { - /* retry with a dynamically allocated buffer */ - if (buf_ptr != buffer) heap_free( buf_ptr ); - if (!(buf_ptr = heap_alloc( total_size ))) - return ERROR_NOT_ENOUGH_MEMORY; - info = (KEY_NODE_INFORMATION *)buf_ptr; - status = NtEnumerateKey( hkey, index, KeyNodeInformation, - buf_ptr, total_size, &total_size ); - } - - if (!status) - { - DWORD len = info->NameLength / sizeof(WCHAR); - DWORD cls_len = info->ClassLength / sizeof(WCHAR); - - if (ft) *ft = *(FILETIME *)&info->LastWriteTime; - - if (len >= *name_len || (class && class_len && (cls_len >= *class_len))) - 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; - } - } - } - } - - if (buf_ptr != buffer) heap_free( buf_ptr ); - return RtlNtStatusToDosError( status ); -} - - -/****************************************************************************** - * RegEnumKeyExA [ADVAPI32.@] - * - * See RegEnumKeyExW. - */ -LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len, - LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft ) -{ - NTSTATUS status; - char buffer[256], *buf_ptr = buffer; - KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; - DWORD total_size; - - 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 ); - - if (reserved) return ERROR_INVALID_PARAMETER; - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - status = NtEnumerateKey( hkey, index, KeyNodeInformation, - buffer, sizeof(buffer), &total_size ); - - while (status == STATUS_BUFFER_OVERFLOW) - { - /* retry with a dynamically allocated buffer */ - if (buf_ptr != buffer) heap_free( buf_ptr ); - if (!(buf_ptr = heap_alloc( total_size ))) - return ERROR_NOT_ENOUGH_MEMORY; - info = (KEY_NODE_INFORMATION *)buf_ptr; - status = NtEnumerateKey( hkey, index, KeyNodeInformation, - buf_ptr, total_size, &total_size ); - } - - if (!status) - { - DWORD len, cls_len; - - RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength ); - RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset), - info->ClassLength ); - if (ft) *ft = *(FILETIME *)&info->LastWriteTime; - - if (len >= *name_len || (class && class_len && (cls_len >= *class_len))) - status = STATUS_BUFFER_OVERFLOW; - else - { - *name_len = len; - RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength ); - name[len] = 0; - if (class_len) - { - *class_len = cls_len; - if (class) - { - RtlUnicodeToMultiByteN( class, cls_len, NULL, - (WCHAR *)(buf_ptr + info->ClassOffset), - info->ClassLength ); - class[cls_len] = 0; - } - } - } - } - - if (buf_ptr != buffer) heap_free( buf_ptr ); - return RtlNtStatusToDosError( status ); -} - /****************************************************************************** * RegEnumKeyW [ADVAPI32.@] @@ -926,101 +194,6 @@ LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len ) } -/****************************************************************************** - * RegQueryInfoKeyW [ADVAPI32.@] - * - * Retrieves information about the specified registry key. - * - * 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 - * - * 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) - */ -LSTATUS 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 ) -{ - NTSTATUS status; - char buffer[256], *buf_ptr = buffer; - KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer; - DWORD total_size; - - TRACE( "(%p,%p,%d,%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 ); - - if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER; - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); - if (status && status != STATUS_BUFFER_OVERFLOW) goto done; - - if (class && class_len && *class_len) - { - /* retry with a dynamically allocated buffer */ - while (status == STATUS_BUFFER_OVERFLOW) - { - if (buf_ptr != buffer) heap_free( buf_ptr ); - if (!(buf_ptr = heap_alloc( total_size ))) - return ERROR_NOT_ENOUGH_MEMORY; - info = (KEY_FULL_INFORMATION *)buf_ptr; - status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size ); - } - - if (status) goto done; - - if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len)) - { - status = STATUS_BUFFER_TOO_SMALL; - } - else - { - memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength ); - class[info->ClassLength/sizeof(WCHAR)] = 0; - } - } - else status = STATUS_SUCCESS; - - if (class_len) *class_len = info->ClassLength / sizeof(WCHAR); - if (subkeys) *subkeys = info->SubKeys; - if (max_subkey) *max_subkey = info->MaxNameLen / sizeof(WCHAR); - if (max_class) *max_class = info->MaxClassLen / sizeof(WCHAR); - if (values) *values = info->Values; - if (max_value) *max_value = info->MaxValueNameLen / sizeof(WCHAR); - if (max_data) *max_data = info->MaxValueDataLen; - if (modif) *modif = *(FILETIME *)&info->LastWriteTime; - - if (security) - { - FIXME( "security argument not supported.\n"); - *security = 0; - } - - done: - if (buf_ptr != buffer) heap_free( buf_ptr ); - return RtlNtStatusToDosError( status ); -} - - /****************************************************************************** * RegQueryMultipleValuesA [ADVAPI32.@] * @@ -1039,7 +212,7 @@ LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPD * bytes. */ LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals, - LPSTR lpValueBuf, LPDWORD ldwTotsize ) + LPSTR lpValueBuf, LPDWORD ldwTotsize ) { unsigned int i; DWORD maxBytes = *ldwTotsize; @@ -1085,7 +258,7 @@ LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_ * See RegQueryMultipleValuesA. */ LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals, - LPWSTR lpValueBuf, LPDWORD ldwTotsize ) + LPWSTR lpValueBuf, LPDWORD ldwTotsize ) { unsigned int i; DWORD maxBytes = *ldwTotsize; @@ -1123,97 +296,6 @@ LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_ return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA; } -/****************************************************************************** - * 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. - * lpftLastWriteTime [O] FILETIME structure that is the last write time. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: nonzero error code from Winerror.h - */ -LSTATUS 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 ) -{ - NTSTATUS status; - char buffer[256], *buf_ptr = buffer; - KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer; - DWORD total_size, len; - - TRACE( "(%p,%p,%d,%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 ); - - if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER; - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); - if (status && status != STATUS_BUFFER_OVERFLOW) goto done; - - if (class || class_len) - { - /* retry with a dynamically allocated buffer */ - while (status == STATUS_BUFFER_OVERFLOW) - { - if (buf_ptr != buffer) heap_free( buf_ptr ); - if (!(buf_ptr = heap_alloc( total_size ))) - return ERROR_NOT_ENOUGH_MEMORY; - info = (KEY_FULL_INFORMATION *)buf_ptr; - status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size ); - } - - if (status) goto done; - - len = 0; - if (class && class_len) len = *class_len; - RtlUnicodeToMultiByteN( class, len, class_len, - (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength ); - if (len) - { - if (*class_len + 1 > len) - { - status = STATUS_BUFFER_OVERFLOW; - *class_len -= 1; - } - class[*class_len] = 0; - } - } - else status = STATUS_SUCCESS; - - if (subkeys) *subkeys = info->SubKeys; - if (max_subkey) *max_subkey = info->MaxNameLen / sizeof(WCHAR); - if (max_class) *max_class = info->MaxClassLen / sizeof(WCHAR); - if (values) *values = info->Values; - if (max_value) *max_value = info->MaxValueNameLen / sizeof(WCHAR); - if (max_data) *max_data = info->MaxValueDataLen; - if (modif) *modif = *(FILETIME *)&info->LastWriteTime; - - if (security) - { - FIXME( "security argument not supported.\n"); - *security = 0; - } - - done: - if (buf_ptr != buffer) heap_free( buf_ptr ); - return RtlNtStatusToDosError( status ); -} /****************************************************************************** * RegQueryReflectionKey [ADVAPI32.@] @@ -1225,48 +307,6 @@ LONG WINAPI RegQueryReflectionKey( HKEY hkey, BOOL *is_reflection_disabled ) return ERROR_CALL_NOT_IMPLEMENTED; } -/****************************************************************************** - * RegCloseKey [ADVAPI32.@] - * - * Close an open registry key. - * - * PARAMS - * hkey [I] Handle of key to close - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: Error code - */ -LSTATUS WINAPI DECLSPEC_HOTPATCH RegCloseKey( HKEY hkey ) -{ - if (!hkey) return ERROR_INVALID_HANDLE; - if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS; - return RtlNtStatusToDosError( NtClose( hkey ) ); -} - - -/****************************************************************************** - * RegDeleteKeyExW [ADVAPI32.@] - */ -LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved ) -{ - DWORD ret; - HKEY tmp; - - if (!name) return ERROR_INVALID_PARAMETER; - - if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; - - access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY; - if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp ))) - { - ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) ); - RegCloseKey( tmp ); - } - TRACE("%s ret=%08x\n", debugstr_w(name), ret); - return ret; -} - /****************************************************************************** * RegDeleteKeyW [ADVAPI32.@] @@ -1279,39 +319,6 @@ LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name ) } -/****************************************************************************** - * RegDeleteKeyExA [ADVAPI32.@] - */ -LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved ) -{ - DWORD ret; - HKEY tmp; - - if (!name) return ERROR_INVALID_PARAMETER; - - if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; - - access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY; - if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp ))) - { - if (!is_version_nt()) /* win95 does recursive key deletes */ - { - CHAR sub[MAX_PATH]; - - while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub))) - { - if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */ - break; - } - } - ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) ); - RegCloseKey( tmp ); - } - TRACE("%s ret=%08x\n", debugstr_a(name), ret); - return ret; -} - - /****************************************************************************** * RegDeleteKeyA [ADVAPI32.@] * @@ -1336,101 +343,6 @@ LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name ) } - -/****************************************************************************** - * RegSetValueExW [ADVAPI32.@] - * - * Set the data and contents of a registry value. - * - * 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] Type of the value being set - * data [I] The new contents of the value to set - * count [I] Size of data - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: Error code - */ -LSTATUS WINAPI DECLSPEC_HOTPATCH RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved, - DWORD type, const BYTE *data, DWORD count ) -{ - UNICODE_STRING nameW; - - /* no need for version check, not implemented on win9x anyway */ - - if ((data && ((ULONG_PTR)data >> 16) == 0) || (!data && count)) return ERROR_NOACCESS; - - if (count && is_string(type)) - { - 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); - } - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - RtlInitUnicodeString( &nameW, name ); - return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) ); -} - - -/****************************************************************************** - * RegSetValueExA [ADVAPI32.@] - * - * See RegSetValueExW. - * - * NOTES - * win95 does not care about count for REG_SZ and finds out the len by itself (js) - * NT does definitely care (aj) - */ -LSTATUS WINAPI DECLSPEC_HOTPATCH RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type, - const BYTE *data, DWORD count ) -{ - ANSI_STRING nameA; - UNICODE_STRING nameW; - WCHAR *dataW = NULL; - NTSTATUS status; - - if (!is_version_nt()) /* win95 */ - { - if (type == REG_SZ) - { - if (!data) return ERROR_INVALID_PARAMETER; - count = strlen((const char *)data) + 1; - } - } - else if (count && is_string(type)) - { - /* if user forgot to count terminating null, add it (yes NT does this) */ - if (data[count-1] && !data[count]) count++; - } - - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - if (is_string( type )) /* need to convert to Unicode */ - { - DWORD lenW; - RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count ); - if (!(dataW = heap_alloc( lenW ))) return ERROR_OUTOFMEMORY; - RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count ); - count = lenW; - data = (BYTE *)dataW; - } - - RtlInitAnsiString( &nameA, name ); - if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) - { - status = NtSetValueKey( hkey, &nameW, 0, type, data, count ); - RtlFreeUnicodeString( &nameW ); - } - heap_free( dataW ); - return RtlNtStatusToDosError( status ); -} - - /****************************************************************************** * RegSetValueW [ADVAPI32.@] * @@ -1470,506 +382,6 @@ LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR subkey, DWORD type, LPCSTR data, 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 */ - { - if ((ret = RegCreateKeyW( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret; - hkey = hsubkey; - } - - ret = RegSetValueExW( hkey, name, 0, type, (const BYTE*)data, len ); - if (hsubkey) RegCloseKey( hsubkey ); - return ret; -} - -/****************************************************************************** - * 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 ); - - 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; -} - -struct perf_provider -{ - HMODULE perflib; - WCHAR linkage[MAX_PATH]; - WCHAR objects[MAX_PATH]; - PM_OPEN_PROC *pOpen; - PM_CLOSE_PROC *pClose; - PM_COLLECT_PROC *pCollect; -}; - -static void *get_provider_entry(HKEY perf, HMODULE perflib, const char *name) -{ - char buf[MAX_PATH]; - DWORD err, type, len; - - len = sizeof(buf) - 1; - err = RegQueryValueExA(perf, name, NULL, &type, (BYTE *)buf, &len); - if (err != ERROR_SUCCESS || type != REG_SZ) - return NULL; - - buf[len] = 0; - TRACE("Loading function pointer for %s: %s\n", name, debugstr_a(buf)); - - return GetProcAddress(perflib, buf); -} - -static BOOL load_provider(HKEY root, const WCHAR *name, struct perf_provider *provider) -{ - static const WCHAR object_listW[] = { 'O','b','j','e','c','t',' ','L','i','s','t',0 }; - static const WCHAR performanceW[] = { 'P','e','r','f','o','r','m','a','n','c','e',0 }; - static const WCHAR libraryW[] = { 'L','i','b','r','a','r','y',0 }; - static const WCHAR linkageW[] = { 'L','i','n','k','a','g','e',0 }; - static const WCHAR exportW[] = { 'E','x','p','o','r','t',0 }; - WCHAR buf[MAX_PATH], buf2[MAX_PATH]; - DWORD err, type, len; - HKEY service, perf; - - err = RegOpenKeyExW(root, name, 0, KEY_READ, &service); - if (err != ERROR_SUCCESS) - return FALSE; - - provider->linkage[0] = 0; - err = RegOpenKeyExW(service, linkageW, 0, KEY_READ, &perf); - if (err == ERROR_SUCCESS) - { - len = sizeof(buf) - sizeof(WCHAR); - err = RegQueryValueExW(perf, exportW, NULL, &type, (BYTE *)buf, &len); - if (err == ERROR_SUCCESS && (type == REG_SZ || type == REG_MULTI_SZ)) - { - memcpy(provider->linkage, buf, len); - provider->linkage[len / sizeof(WCHAR)] = 0; - TRACE("Export: %s\n", debugstr_w(provider->linkage)); - } - RegCloseKey(perf); - } - - err = RegOpenKeyExW(service, performanceW, 0, KEY_READ, &perf); - RegCloseKey(service); - if (err != ERROR_SUCCESS) - return FALSE; - - provider->objects[0] = 0; - len = sizeof(buf) - sizeof(WCHAR); - err = RegQueryValueExW(perf, object_listW, NULL, &type, (BYTE *)buf, &len); - if (err == ERROR_SUCCESS && (type == REG_SZ || type == REG_MULTI_SZ)) - { - memcpy(provider->objects, buf, len); - provider->objects[len / sizeof(WCHAR)] = 0; - TRACE("Object List: %s\n", debugstr_w(provider->objects)); - } - - len = sizeof(buf) - sizeof(WCHAR); - err = RegQueryValueExW(perf, libraryW, NULL, &type, (BYTE *)buf, &len); - if (err != ERROR_SUCCESS || !(type == REG_SZ || type == REG_EXPAND_SZ)) - goto error; - - buf[len / sizeof(WCHAR)] = 0; - if (type == REG_EXPAND_SZ) - { - len = ExpandEnvironmentStringsW(buf, buf2, MAX_PATH); - if (!len || len > MAX_PATH) goto error; - strcpyW(buf, buf2); - } - - if (!(provider->perflib = LoadLibraryW(buf))) - { - WARN("Failed to load %s\n", debugstr_w(buf)); - goto error; - } - - GetModuleFileNameW(provider->perflib, buf, MAX_PATH); - TRACE("Loaded provider %s\n", wine_dbgstr_w(buf)); - - provider->pOpen = get_provider_entry(perf, provider->perflib, "Open"); - provider->pClose = get_provider_entry(perf, provider->perflib, "Close"); - provider->pCollect = get_provider_entry(perf, provider->perflib, "Collect"); - if (provider->pOpen && provider->pClose && provider->pCollect) - { - RegCloseKey(perf); - return TRUE; - } - - TRACE("Provider is missing required exports\n"); - FreeLibrary(provider->perflib); - -error: - RegCloseKey(perf); - return FALSE; -} - -static DWORD collect_data(struct perf_provider *provider, const WCHAR *query, void **data, DWORD *size, DWORD *obj_count) -{ - static const WCHAR globalW[] = { 'G','l','o','b','a','l',0 }; - WCHAR *linkage = provider->linkage[0] ? provider->linkage : NULL; - DWORD err; - - if (!query || !query[0]) - query = globalW; - - err = provider->pOpen(linkage); - if (err != ERROR_SUCCESS) - { - TRACE("Open(%s) error %u (%#x)\n", debugstr_w(linkage), err, err); - return err; - } - - *obj_count = 0; - err = provider->pCollect((WCHAR *)query, data, size, obj_count); - if (err != ERROR_SUCCESS) - { - TRACE("Collect error %u (%#x)\n", err, err); - *obj_count = 0; - } - - provider->pClose(); - return err; -} - -#define MAX_SERVICE_NAME 260 - -static DWORD query_perf_data(const WCHAR *query, DWORD *type, void *data, DWORD *ret_size) -{ - static const WCHAR SZ_SERVICES_KEY[] = { 'S','y','s','t','e','m','\\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', - 'S','e','r','v','i','c','e','s',0 }; - DWORD err, i, data_size; - HKEY root; - PERF_DATA_BLOCK *pdb; - - if (!ret_size) - return ERROR_INVALID_PARAMETER; - - data_size = *ret_size; - *ret_size = 0; - - if (type) - *type = REG_BINARY; - - if (!data || data_size < sizeof(*pdb)) - return ERROR_MORE_DATA; - - pdb = data; - - pdb->Signature[0] = 'P'; - pdb->Signature[1] = 'E'; - pdb->Signature[2] = 'R'; - pdb->Signature[3] = 'F'; -#ifdef WORDS_BIGENDIAN - pdb->LittleEndian = FALSE; -#else - pdb->LittleEndian = TRUE; -#endif - pdb->Version = PERF_DATA_VERSION; - pdb->Revision = PERF_DATA_REVISION; - pdb->TotalByteLength = 0; - pdb->HeaderLength = sizeof(*pdb); - pdb->NumObjectTypes = 0; - pdb->DefaultObject = 0; - QueryPerformanceCounter(&pdb->PerfTime); - QueryPerformanceFrequency(&pdb->PerfFreq); - - data = pdb + 1; - pdb->SystemNameOffset = sizeof(*pdb); - pdb->SystemNameLength = (data_size - sizeof(*pdb)) / sizeof(WCHAR); - if (!GetComputerNameW(data, &pdb->SystemNameLength)) - return ERROR_MORE_DATA; - - pdb->SystemNameLength++; - pdb->SystemNameLength *= sizeof(WCHAR); - - pdb->HeaderLength += pdb->SystemNameLength; - - /* align to 8 bytes */ - if (pdb->SystemNameLength & 7) - pdb->HeaderLength += 8 - (pdb->SystemNameLength & 7); - - if (data_size < pdb->HeaderLength) - return ERROR_MORE_DATA; - - pdb->TotalByteLength = pdb->HeaderLength; - - data_size -= pdb->HeaderLength; - data = (char *)data + pdb->HeaderLength; - - err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, SZ_SERVICES_KEY, 0, KEY_READ, &root); - if (err != ERROR_SUCCESS) - return err; - - i = 0; - for (;;) - { - DWORD collected_size = data_size, obj_count = 0; - struct perf_provider provider; - WCHAR name[MAX_SERVICE_NAME]; - void *collected_data = data; - - err = RegEnumKeyW(root, i++, name, MAX_SERVICE_NAME); - if (err == ERROR_NO_MORE_ITEMS) - { - err = ERROR_SUCCESS; - break; - } - - if (err != ERROR_SUCCESS) - continue; - - if (!load_provider(root, name, &provider)) - continue; - - err = collect_data(&provider, query, &collected_data, &collected_size, &obj_count); - FreeLibrary(provider.perflib); - - if (err == ERROR_MORE_DATA) - break; - - if (err == ERROR_SUCCESS) - { - PERF_OBJECT_TYPE *obj = (PERF_OBJECT_TYPE *)data; - - TRACE("Collect: obj->TotalByteLength %u, collected_size %u\n", - obj->TotalByteLength, collected_size); - - data_size -= collected_size; - data = collected_data; - - pdb->TotalByteLength += collected_size; - pdb->NumObjectTypes += obj_count; - } - } - - RegCloseKey(root); - - if (err == ERROR_SUCCESS) - { - *ret_size = pdb->TotalByteLength; - - GetSystemTime(&pdb->SystemTime); - GetSystemTimeAsFileTime((FILETIME *)&pdb->PerfTime100nSec); - } - - return err; -} - -/****************************************************************************** - * RegQueryValueExW [ADVAPI32.@] - * - * See RegQueryValueExA. - */ -LSTATUS WINAPI DECLSPEC_HOTPATCH RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type, - LPBYTE data, LPDWORD count ) -{ - NTSTATUS status; - UNICODE_STRING name_str; - DWORD total_size; - char buffer[256], *buf_ptr = buffer; - KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; - static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); - - TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", - hkey, debugstr_w(name), reserved, type, data, count, - (count && data) ? *count : 0 ); - - if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; - - if (hkey == HKEY_PERFORMANCE_DATA) - return query_perf_data(name, type, data, count); - - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - RtlInitUnicodeString( &name_str, name ); - - if (data) total_size = min( sizeof(buffer), *count + info_size ); - else - { - total_size = info_size; - if (count) *count = 0; - } - - status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, - buffer, total_size, &total_size ); - if (status && status != STATUS_BUFFER_OVERFLOW) goto done; - - if (data) - { - /* retry with a dynamically allocated buffer */ - while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count) - { - if (buf_ptr != buffer) heap_free( buf_ptr ); - if (!(buf_ptr = heap_alloc( total_size ))) - return ERROR_NOT_ENOUGH_MEMORY; - info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; - status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, - buf_ptr, total_size, &total_size ); - } - - 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)) - { - WCHAR *ptr = (WCHAR *)(data + total_size - info_size); - if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; - } - } - else if (status != STATUS_BUFFER_OVERFLOW) goto done; - } - else status = STATUS_SUCCESS; - - if (type) *type = info->Type; - if (count) *count = total_size - info_size; - - done: - if (buf_ptr != buffer) heap_free( buf_ptr ); - return RtlNtStatusToDosError(status); -} - - -/****************************************************************************** - * RegQueryValueExA [ADVAPI32.@] - * - * Get the type and contents of a specified value under with a key. - * - * PARAMS - * 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 - * - * 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. - */ -LSTATUS WINAPI DECLSPEC_HOTPATCH RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, - LPDWORD type, LPBYTE data, LPDWORD count ) -{ - NTSTATUS status; - ANSI_STRING nameA; - UNICODE_STRING nameW; - DWORD total_size, datalen = 0; - char buffer[256], *buf_ptr = buffer; - KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; - static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); - - TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", - hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 ); - - if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; - if (hkey != HKEY_PERFORMANCE_DATA && !(hkey = get_special_root_hkey( hkey, 0 ))) - return ERROR_INVALID_HANDLE; - - if (count) datalen = *count; - if (!data && count) *count = 0; - - /* this matches Win9x behaviour - NT sets *type to a random value */ - if (type) *type = REG_NONE; - - RtlInitAnsiString( &nameA, name ); - if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) - return RtlNtStatusToDosError(status); - - if (hkey == HKEY_PERFORMANCE_DATA) - { - DWORD ret = query_perf_data( nameW.Buffer, type, data, count ); - RtlFreeUnicodeString( &nameW ); - return ret; - } - - status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, - buffer, sizeof(buffer), &total_size ); - if (status && status != STATUS_BUFFER_OVERFLOW) goto done; - - /* 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)) - { - /* retry with a dynamically allocated buffer */ - while (status == STATUS_BUFFER_OVERFLOW) - { - if (buf_ptr != buffer) heap_free( buf_ptr ); - if (!(buf_ptr = heap_alloc( total_size ))) - { - status = STATUS_NO_MEMORY; - goto done; - } - info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; - status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, - buf_ptr, total_size, &total_size ); - } - - if (status) goto done; - - if (is_string(info->Type)) - { - DWORD len; - - RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size), - total_size - info_size ); - if (data && len) - { - if (len > datalen) status = STATUS_BUFFER_OVERFLOW; - else - { - RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(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 (len < datalen && data[len-1]) data[len] = 0; - } - } - total_size = len + info_size; - } - else if (data) - { - if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW; - else memcpy( data, buf_ptr + info_size, total_size - info_size ); - } - } - else status = STATUS_SUCCESS; - - if (type) *type = info->Type; - if (count) *count = total_size - info_size; - - done: - if (buf_ptr != buffer) heap_free( buf_ptr ); - RtlFreeUnicodeString( &nameW ); - return RtlNtStatusToDosError(status); -} - /****************************************************************************** * RegQueryValueW [ADVAPI32.@] @@ -2040,616 +452,6 @@ LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count } -/****************************************************************************** - * ADVAPI_ApplyRestrictions [internal] - * - * Helper function for RegGetValueA/W. - */ -static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType, - DWORD cbData, PLONG ret ) -{ - /* 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; - - if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD) - cbExpect = 4; - else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD) - cbExpect = 8; - - if (cbExpect && cbData != cbExpect) - *ret = ERROR_DATATYPE_MISMATCH; - } - } - else *ret = ERROR_UNSUPPORTED_TYPE; - } -} - - -/****************************************************************************** - * RegGetValueW [ADVAPI32.@] - * - * Retrieves the type and data for a value name associated with a key, - * optionally expanding its content and restricting its type. - * - * 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. - * pcbData [I/O] Size of pvData, updated with the size in bytes required to - * retrieve the whole content, including the trailing '\0' - * for strings. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: nonzero error code from Winerror.h - * - * NOTES - * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically - * expanded and pdwType is set to REG_SZ instead. - * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ - * without RRF_NOEXPAND is thus not allowed. - * An exception is the case where RRF_RT_ANY is specified, because then - * RRF_NOEXPAND is allowed. - */ -LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, - DWORD dwFlags, LPDWORD pdwType, PVOID pvData, - LPDWORD pcbData ) -{ - DWORD dwType, cbData = (pvData && pcbData) ? *pcbData : 0; - PVOID pvBuf = NULL; - LONG ret; - - TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n", - hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType, - pvData, pcbData, cbData); - - if (pvData && !pcbData) - return ERROR_INVALID_PARAMETER; - if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && - ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) - 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) && - dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)) - { - do { - heap_free(pvBuf); - - pvBuf = heap_alloc(cbData); - if (!pvBuf) - { - ret = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - if (ret == ERROR_MORE_DATA || !pvData) - 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) - { - /* Recheck dwType in case it changed since the first call */ - if (dwType == REG_EXPAND_SZ) - { - cbData = ExpandEnvironmentStringsW(pvBuf, pvData, - pcbData ? *pcbData : 0) * sizeof(WCHAR); - dwType = REG_SZ; - if(pvData && pcbData && cbData > *pcbData) - ret = ERROR_MORE_DATA; - } - else if (pvData) - CopyMemory(pvData, pvBuf, *pcbData); - } - - heap_free(pvBuf); - } - - if (pszSubKey && pszSubKey[0]) - RegCloseKey(hKey); - - ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret); - - if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) - ZeroMemory(pvData, *pcbData); - - if (pdwType) *pdwType = dwType; - if (pcbData) *pcbData = cbData; - - return ret; -} - - -/****************************************************************************** - * RegGetValueA [ADVAPI32.@] - * - * See RegGetValueW. - */ -LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue, - DWORD dwFlags, LPDWORD pdwType, PVOID pvData, - LPDWORD pcbData ) -{ - DWORD dwType, cbData = (pvData && pcbData) ? *pcbData : 0; - PVOID pvBuf = NULL; - LONG ret; - - TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n", - hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags, - pdwType, pvData, pcbData, cbData); - - if (pvData && !pcbData) - return ERROR_INVALID_PARAMETER; - if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && - ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) - 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) && - dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)) - { - do { - heap_free(pvBuf); - - pvBuf = heap_alloc(cbData); - if (!pvBuf) - { - ret = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - if (ret == ERROR_MORE_DATA || !pvData) - 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) - { - /* Recheck dwType in case it changed since the first call */ - if (dwType == REG_EXPAND_SZ) - { - cbData = ExpandEnvironmentStringsA(pvBuf, pvData, - pcbData ? *pcbData : 0); - dwType = REG_SZ; - if(pvData && pcbData && cbData > *pcbData) - ret = ERROR_MORE_DATA; - } - else if (pvData) - CopyMemory(pvData, pvBuf, *pcbData); - } - - heap_free(pvBuf); - } - - if (pszSubKey && pszSubKey[0]) - RegCloseKey(hKey); - - ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret); - - if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) - ZeroMemory(pvData, *pcbData); - - if (pdwType) *pdwType = dwType; - if (pcbData) *pcbData = cbData; - - return ret; -} - - -/****************************************************************************** - * RegEnumValueW [ADVAPI32.@] - * - * Enumerates the values for the specified open registry key. - * - * PARAMS - * hkey [I] Handle to key to query - * index [I] Index of value to query - * value [O] Value string - * val_count [I/O] Size of value buffer (in wchars) - * reserved [I] Reserved - * type [O] Type code - * data [O] Value data - * count [I/O] Size of data buffer (in bytes) - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: nonzero error code from Winerror.h - */ - -LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count, - LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count ) -{ - NTSTATUS status; - DWORD total_size; - char buffer[256], *buf_ptr = buffer; - KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; - static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name ); - - TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n", - hkey, index, value, val_count, reserved, type, data, count ); - - if ((data && !count) || reserved || !value || !val_count) - return ERROR_INVALID_PARAMETER; - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); - if (data) total_size += *count; - total_size = min( sizeof(buffer), total_size ); - - status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation, - buffer, total_size, &total_size ); - - /* retry with a dynamically allocated buffer */ - while (status == STATUS_BUFFER_OVERFLOW) - { - 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 ); - } - - if (status) goto done; - - 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; - - if (data) - { - if (total_size - info->DataOffset > *count) - { - status = STATUS_BUFFER_OVERFLOW; - goto overflow; - } - memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset ); - if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type)) - { - /* if the type is REG_SZ and data is not 0-terminated - * and there is enough space in the buffer NT appends a \0 */ - WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset); - if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; - } - } - - overflow: - if (type) *type = info->Type; - if (count) *count = info->DataLength; - - done: - if (buf_ptr != buffer) heap_free( buf_ptr ); - return RtlNtStatusToDosError(status); -} - - -/****************************************************************************** - * RegEnumValueA [ADVAPI32.@] - * - * See RegEnumValueW. - */ -LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count, - LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count ) -{ - NTSTATUS status; - DWORD total_size; - char buffer[256], *buf_ptr = buffer; - KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; - static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name ); - - TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n", - hkey, index, value, val_count, reserved, type, data, count ); - - if ((data && !count) || reserved || !value || !val_count) - return ERROR_INVALID_PARAMETER; - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); - if (data) total_size += *count; - total_size = min( sizeof(buffer), total_size ); - - status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation, - buffer, total_size, &total_size ); - - /* 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. */ - - /* retry with a dynamically allocated buffer */ - while (status == STATUS_BUFFER_OVERFLOW) - { - 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 ); - } - - if (status) goto done; - - if (is_string(info->Type)) - { - DWORD len; - RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset), - total_size - info->DataOffset ); - if (data && len) - { - if (len > *count) status = STATUS_BUFFER_OVERFLOW; - else - { - RtlUnicodeToMultiByteN( (char*)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; - } - } - 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 ); - } - - if (!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; - } - } - - if (type) *type = info->Type; - if (count) *count = info->DataLength; - - done: - if (buf_ptr != buffer) heap_free( buf_ptr ); - return RtlNtStatusToDosError(status); -} - -/****************************************************************************** - * RegDeleteValueW [ADVAPI32.@] - * - * See RegDeleteValueA. - */ -LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name ) -{ - return RegDeleteKeyValueW( hkey, NULL, name ); -} - -/****************************************************************************** - * RegDeleteValueA [ADVAPI32.@] - * - * 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 - * Success: ERROR_SUCCESS - * Failure: nonzero error code from Winerror.h - */ -LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name ) -{ - return RegDeleteKeyValueA( hkey, NULL, name ); -} - -/****************************************************************************** - * RegDeleteKeyValueW [ADVAPI32.@] - */ -LONG WINAPI RegDeleteKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name ) -{ - UNICODE_STRING nameW; - 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; - NTSTATUS status; - - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - if (subkey) - { - LONG ret = RegOpenKeyExA( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey ); - if (ret) - return ret; - hkey = hsubkey; - } - - RtlInitAnsiString( &nameA, name ); - if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) - { - status = NtDeleteValueKey( hkey, &nameW ); - RtlFreeUnicodeString( &nameW ); - } - - if (hsubkey) RegCloseKey( hsubkey ); - return RtlNtStatusToDosError( status ); -} - -/****************************************************************************** - * RegLoadKeyW [ADVAPI32.@] - * - * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store - * registration information from a specified file into that subkey. - * - * PARAMS - * hkey [I] Handle of open key - * subkey [I] Address of name of subkey - * filename [I] Address of filename for registry information - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: nonzero error code from Winerror.h - */ -LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename ) -{ - OBJECT_ATTRIBUTES destkey, file; - UNICODE_STRING subkeyW, filenameW; - NTSTATUS status; - - if (!(hkey = get_special_root_hkey(hkey, 0))) return ERROR_INVALID_HANDLE; - - 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); - - status = NtLoadKey(&destkey, &file); - RtlFreeUnicodeString(&filenameW); - return RtlNtStatusToDosError( status ); -} - - -/****************************************************************************** - * RegLoadKeyA [ADVAPI32.@] - * - * See RegLoadKeyW. - */ -LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename ) -{ - UNICODE_STRING subkeyW, filenameW; - STRING subkeyA, filenameA; - NTSTATUS status; - LONG ret; - - RtlInitAnsiString(&subkeyA, subkey); - RtlInitAnsiString(&filenameA, filename); - - 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; -} - - /****************************************************************************** * RegSaveKeyW [ADVAPI32.@] * @@ -2666,52 +468,7 @@ LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename ) */ LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa ) { - static const WCHAR format[] = - {'r','e','g','%','0','4','x','.','t','m','p',0}; - WCHAR buffer[MAX_PATH]; - int count = 0; - LPWSTR nameW; - DWORD ret, err; - HANDLE handle; - - TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa ); - - if (!file || !*file) return ERROR_INVALID_PARAMETER; - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - err = GetLastError(); - GetFullPathNameW( file, ARRAY_SIZE( buffer ), buffer, &nameW ); - - for (;;) - { - snprintfW( nameW, 16, format, count++ ); - handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL, - CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 ); - if (handle != INVALID_HANDLE_VALUE) break; - if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done; - - /* 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 !\nYou might want to delete all corresponding temp files in that directory.\n", debugstr_w(buffer), count); - } - - ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle)); - - CloseHandle( handle ); - if (!ret) - { - if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING )) - { - ERR( "Failed to move %s to %s\n", debugstr_w(buffer), - debugstr_w(file) ); - ret = GetLastError(); - } - } - if (ret) DeleteFileW( buffer ); - -done: - SetLastError( err ); /* restore last error code */ - return ret; + return RegSaveKeyExW(hkey, file, sa, 0); } @@ -2722,133 +479,7 @@ done: */ LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa ) { - 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); -} - -/****************************************************************************** - * RegSaveKeyExA [ADVAPI32.@] - * - */ -LSTATUS WINAPI RegSaveKeyExA( HKEY hkey, LPCSTR file, SECURITY_ATTRIBUTES *sa, DWORD flags ) -{ - FIXME( "(%p,%s,%p,%d) flags not handled\n", hkey, debugstr_a(file), sa, flags ); - return RegSaveKeyA(hkey, file, sa); -} - -/****************************************************************************** - * RegSaveKeyExW [ADVAPI32.@] - * - */ -LSTATUS WINAPI RegSaveKeyExW( HKEY hkey, LPCWSTR file, SECURITY_ATTRIBUTES *sa, DWORD flags ) -{ - FIXME( "(%p,%s,%p,%d) flags not handled\n", hkey, debugstr_w(file), sa, flags ); - return RegSaveKeyW(hkey, file, sa); -} - -/****************************************************************************** - * RegRestoreKeyW [ADVAPI32.@] - * - * Read the registry information from a file and copy it over a key. - * - * PARAMS - * 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 - */ -LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags ) -{ - TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags); - - /* It seems to do this check before the hkey check */ - if (!lpFile || !*lpFile) - return ERROR_INVALID_PARAMETER; - - FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags); - - /* Check for file existence */ - - return ERROR_SUCCESS; -} - - -/****************************************************************************** - * RegRestoreKeyA [ADVAPI32.@] - * - * See RegRestoreKeyW. - */ -LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags ) -{ - UNICODE_STRING lpFileW; - LONG ret; - - RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile ); - ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags ); - RtlFreeUnicodeString( &lpFileW ); - return ret; -} - - -/****************************************************************************** - * RegUnLoadKeyW [ADVAPI32.@] - * - * Unload a registry key and its subkeys from the registry. - * - * PARAMS - * 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 - */ -LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey ) -{ - DWORD ret; - HKEY shkey; - OBJECT_ATTRIBUTES attr; - UNICODE_STRING subkey; - - TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey)); - - ret = RegOpenKeyW(hkey,lpSubKey,&shkey); - if( ret ) - return ERROR_INVALID_PARAMETER; - - RtlInitUnicodeString(&subkey, lpSubKey); - InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL); - ret = RtlNtStatusToDosError(NtUnloadKey(&attr)); - - RegCloseKey(shkey); - - return ret; -} - - -/****************************************************************************** - * RegUnLoadKeyA [ADVAPI32.@] - * - * See RegUnLoadKeyW. - */ -LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey ) -{ - UNICODE_STRING lpSubKeyW; - LONG ret; - - RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey ); - ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer ); - RtlFreeUnicodeString( &lpSubKeyW ); - return ret; + return RegSaveKeyExA(hkey, file, sa, 0); } @@ -2868,7 +499,7 @@ LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey ) * Failure: nonzero error code from Winerror.h */ LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile, - LPCWSTR lpOldFile ) + LPCWSTR lpOldFile ) { FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), debugstr_w(lpNewFile),debugstr_w(lpOldFile)); @@ -2882,7 +513,7 @@ LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile, * See RegReplaceKeyW. */ LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile, - LPCSTR lpOldFile ) + LPCSTR lpOldFile ) { UNICODE_STRING lpSubKeyW; UNICODE_STRING lpNewFileW; @@ -2900,94 +531,6 @@ LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile, } -/****************************************************************************** - * RegSetKeySecurity [ADVAPI32.@] - * - * Set the security of an open registry key. - * - * PARAMS - * 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 - */ -LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo, - PSECURITY_DESCRIPTOR pSecurityDesc ) -{ - TRACE("(%p,%d,%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; - - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - return RtlNtStatusToDosError( NtSetSecurityObject( hkey, SecurityInfo, pSecurityDesc ) ); -} - - -/****************************************************************************** - * RegGetKeySecurity [ADVAPI32.@] - * - * Get a copy of the security descriptor for a given 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 - */ -LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation, - PSECURITY_DESCRIPTOR pSecurityDescriptor, - LPDWORD lpcbSecurityDescriptor ) -{ - TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor, - *lpcbSecurityDescriptor); - - if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; - - return RtlNtStatusToDosError( NtQuerySecurityObject( hkey, - SecurityInformation, pSecurityDescriptor, - *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) ); -} - - -/****************************************************************************** - * RegFlushKey [ADVAPI32.@] - * - * Immediately write a registry key to registry. - * - * PARAMS - * hkey [I] Handle of key to write - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: Error code - */ -LSTATUS WINAPI RegFlushKey( HKEY hkey ) -{ - hkey = get_special_root_hkey( hkey, 0 ); - if (!hkey) return ERROR_INVALID_HANDLE; - - return RtlNtStatusToDosError( NtFlushKey( hkey ) ); -} - - /****************************************************************************** * RegConnectRegistryW [ADVAPI32.@] * @@ -3003,7 +546,7 @@ LSTATUS WINAPI RegFlushKey( HKEY hkey ) * Failure: nonzero error code from Winerror.h */ LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey, - PHKEY phkResult ) + PHKEY phkResult ) { LONG ret; @@ -3054,403 +597,10 @@ LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey ) } -/****************************************************************************** - * RegNotifyChangeKeyValue [ADVAPI32.@] - * - * Notify the caller about changes to the attributes or contents of a registry key. - * - * 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 - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: nonzero error code from Winerror.h - */ -LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree, - DWORD fdwNotifyFilter, HANDLE hEvent, - BOOL fAsync ) -{ - NTSTATUS status; - IO_STATUS_BLOCK iosb; - - hkey = get_special_root_hkey( hkey, 0 ); - if (!hkey) return ERROR_INVALID_HANDLE; - - TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter, - hEvent, fAsync); - - status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb, - fdwNotifyFilter, fWatchSubTree, NULL, 0, - fAsync); - - if (status && status != STATUS_PENDING) - return RtlNtStatusToDosError( status ); - - return ERROR_SUCCESS; -} - -/****************************************************************************** - * RegOpenUserClassesRoot [ADVAPI32.@] - * - * Open the HKEY_CLASSES_ROOT key for a user. - * - * PARAMS - * hToken [I] Handle of token representing the user - * dwOptions [I] Reserved, must be 0 - * samDesired [I] Desired access rights - * phkResult [O] Destination for the resulting key handle - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: nonzero error code from Winerror.h - * - * NOTES - * 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. - */ -LSTATUS WINAPI RegOpenUserClassesRoot( - HANDLE hToken, - DWORD dwOptions, - REGSAM samDesired, - PHKEY phkResult -) -{ - FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult); - - *phkResult = HKEY_CLASSES_ROOT; - return ERROR_SUCCESS; -} - -/****************************************************************************** - * 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 *pResString) -{ - 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 (!*pString) { - SetLastError(ERROR_NOT_FOUND); - return 0; - } - - *pResString = pString + 1; - return *pString; -} - -static void dump_mui_cache(void) -{ - struct mui_cache_entry *ent; - - TRACE("---------- MUI Cache ----------\n"); - LIST_FOR_EACH_ENTRY( ent, ®_mui_cache, struct mui_cache_entry, entry ) - TRACE("entry=%p, %s,-%u [%#x] => %s\n", - ent, wine_dbgstr_w(ent->file_name), ent->index, ent->locale, wine_dbgstr_w(ent->text)); -} - -static inline void free_mui_cache_entry(struct mui_cache_entry *ent) -{ - heap_free(ent->file_name); - heap_free(ent->text); - heap_free(ent); -} - -/* critical section must be held */ -static int reg_mui_cache_get(const WCHAR *file_name, UINT index, WCHAR **buffer) -{ - struct mui_cache_entry *ent; - - TRACE("(%s %u %p)\n", wine_dbgstr_w(file_name), index, buffer); - - LIST_FOR_EACH_ENTRY(ent, ®_mui_cache, struct mui_cache_entry, entry) - { - if (ent->index == index && ent->locale == GetThreadLocale() && - !strcmpiW(ent->file_name, file_name)) - goto found; - } - return 0; - -found: - /* move to the list head */ - if (list_prev(®_mui_cache, &ent->entry)) { - list_remove(&ent->entry); - list_add_head(®_mui_cache, &ent->entry); - } - - TRACE("=> %s\n", wine_dbgstr_w(ent->text)); - *buffer = ent->text; - return strlenW(ent->text); -} - -/* critical section must be held */ -static void reg_mui_cache_put(const WCHAR *file_name, UINT index, const WCHAR *buffer, INT size) -{ - struct mui_cache_entry *ent; - TRACE("(%s %u %s %d)\n", wine_dbgstr_w(file_name), index, wine_dbgstr_wn(buffer, size), size); - - ent = heap_calloc(sizeof(*ent), 1); - if (!ent) - return; - ent->file_name = heap_alloc((strlenW(file_name) + 1) * sizeof(WCHAR)); - if (!ent->file_name) { - free_mui_cache_entry(ent); - return; - } - strcpyW(ent->file_name, file_name); - ent->index = index; - ent->locale = GetThreadLocale(); - ent->text = heap_alloc((size + 1) * sizeof(WCHAR)); - if (!ent->text) { - free_mui_cache_entry(ent); - return; - } - memcpy(ent->text, buffer, size * sizeof(WCHAR)); - ent->text[size] = '\0'; - - TRACE("add %p\n", ent); - list_add_head(®_mui_cache, &ent->entry); - if (reg_mui_cache_count > REG_MUI_CACHE_SIZE) { - ent = LIST_ENTRY( list_tail( ®_mui_cache ), struct mui_cache_entry, entry ); - TRACE("freeing %p\n", ent); - list_remove(&ent->entry); - free_mui_cache_entry(ent); - } - else - reg_mui_cache_count++; - - if (TRACE_ON(reg)) - dump_mui_cache(); - return; -} - -static LONG load_mui_string(const WCHAR *file_name, UINT res_id, WCHAR *buffer, INT max_chars, INT *req_chars, DWORD flags) -{ - HMODULE hModule = NULL; - WCHAR *string, *full_name; - int size; - LONG result; - - /* Verify the file existence. i.e. We don't rely on PATH variable */ - if (GetFileAttributesW(file_name) == INVALID_FILE_ATTRIBUTES) - return ERROR_FILE_NOT_FOUND; - - size = GetFullPathNameW(file_name, 0, NULL, NULL); - full_name = heap_alloc(size * sizeof(WCHAR)); - if (!size) - return GetLastError(); - GetFullPathNameW(file_name, size, full_name, NULL); - - EnterCriticalSection(®_mui_cs); - size = reg_mui_cache_get(full_name, res_id, &string); - if (!size) { - LeaveCriticalSection(®_mui_cs); - - /* Load the file */ - hModule = LoadLibraryExW(full_name, NULL, - LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); - if (!hModule) - return GetLastError(); - - size = load_string(hModule, res_id, &string); - if (!size) { - result = GetLastError(); - goto cleanup; - } - - EnterCriticalSection(®_mui_cs); - reg_mui_cache_put(full_name, res_id, string, size); - LeaveCriticalSection(®_mui_cs); - } - *req_chars = size + 1; - - /* If no buffer is given, skip copying. */ - if (!buffer) { - result = ERROR_MORE_DATA; - goto cleanup; - } - - /* Else copy over the string, respecting the buffer size. */ - if (size < max_chars) - max_chars = size; - else { - if (flags & REG_MUI_STRING_TRUNCATE) - max_chars--; - else { - result = ERROR_MORE_DATA; - goto cleanup; - } - } - if (max_chars >= 0) { - memcpy(buffer, string, max_chars * sizeof(WCHAR)); - buffer[max_chars] = '\0'; - } - - result = ERROR_SUCCESS; - -cleanup: - if (hModule) - FreeLibrary(hModule); - else - LeaveCriticalSection(®_mui_cs); - heap_free(full_name); - return result; -} - -/****************************************************************************** - * 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] Truncate output to fit the buffer if REG_MUI_STRING_TRUNCATE. - * pszBaseDir [I] Base directory of loading path. If NULL, use the current directory. - * - * RETURNS - * Success: ERROR_SUCCESS, - * Failure: nonzero error code from winerror.h - */ -LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer, - LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir) -{ - DWORD dwValueType, cbData; - LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL; - LONG result; - - TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, " - "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer, - cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir)); - - /* Parameter sanity checks. */ - if (!hKey || (!pwszBuffer && cbBuffer) || (cbBuffer % sizeof(WCHAR)) - || ((dwFlags & REG_MUI_STRING_TRUNCATE) && pcbData) - || (dwFlags & ~REG_MUI_STRING_TRUNCATE)) - return ERROR_INVALID_PARAMETER; - - /* Check for value existence and correctness of its type, allocate a buffer and load it. */ - 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; - } - pwszTempBuffer = heap_alloc(cbData); - if (!pwszTempBuffer) { - result = ERROR_NOT_ENOUGH_MEMORY; - goto cleanup; - } - result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData); - if (result != ERROR_SUCCESS) goto cleanup; - - /* '@' is the prefix for resource based string entries. */ - if (*pwszTempBuffer != '@') { - result = ERROR_INVALID_DATA; - goto cleanup; - } - - /* Expand environment variables regardless of the type. */ - cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR); - if (!cbData) goto cleanup; - pwszExpandedBuffer = heap_alloc(cbData); - if (!pwszExpandedBuffer) { - result = ERROR_NOT_ENOUGH_MEMORY; - goto cleanup; - } - ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData / sizeof(WCHAR)); - - /* Parse the value and load the string. */ - { - WCHAR *pComma = strrchrW(pwszExpandedBuffer, ','), *pNewBuffer; - const WCHAR backslashW[] = {'\\',0}; - UINT uiStringId; - DWORD baseDirLen; - int reqChars; - - /* Format of the expanded value is 'path_to_dll,-resId' */ - if (!pComma || pComma[1] != '-') { - result = ERROR_INVALID_DATA; - goto cleanup; - } - - uiStringId = atoiW(pComma+2); - *pComma = '\0'; - - /* Build a resource dll path. */ - baseDirLen = pwszBaseDir ? strlenW(pwszBaseDir) : 0; - cbData = (baseDirLen + 1 + strlenW(pwszExpandedBuffer + 1) + 1) * sizeof(WCHAR); - pNewBuffer = heap_realloc(pwszTempBuffer, cbData); - if (!pNewBuffer) { - result = ERROR_NOT_ENOUGH_MEMORY; - goto cleanup; - } - pwszTempBuffer = pNewBuffer; - pwszTempBuffer[0] = '\0'; - if (baseDirLen) { - strcpyW(pwszTempBuffer, pwszBaseDir); - if (pwszBaseDir[baseDirLen - 1] != '\\') - strcatW(pwszTempBuffer, backslashW); - } - strcatW(pwszTempBuffer, pwszExpandedBuffer + 1); - - /* Load specified string from the file */ - reqChars = 0; - result = load_mui_string(pwszTempBuffer, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR), &reqChars, dwFlags); - if (pcbData && (result == ERROR_SUCCESS || result == ERROR_MORE_DATA)) - *pcbData = reqChars * sizeof(WCHAR); - } - -cleanup: - heap_free(pwszTempBuffer); - heap_free(pwszExpandedBuffer); - return result; -} - -/****************************************************************************** - * RegLoadMUIStringA [ADVAPI32.@] - * - * Not implemented on native. - */ -LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer, - LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir) -{ - return ERROR_CALL_NOT_IMPLEMENTED; -} - /****************************************************************************** * RegDisablePredefinedCache [ADVAPI32.@] * - * Disables the caching of the HKEY_CLASSES_ROOT key for the process. + * Disables the caching of the HKEY_CURRENT_USER key for the process. * * PARAMS * None. @@ -3458,188 +608,13 @@ LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DW * RETURNS * Success: ERROR_SUCCESS * Failure: nonzero error code from Winerror.h - * + * * NOTES * This is useful for services that use impersonation. */ LSTATUS WINAPI RegDisablePredefinedCache(void) { - HKEY hkey_current_user; - int idx = HandleToUlong(HKEY_CURRENT_USER) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST); - - /* 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; -} - - -/****************************************************************************** - * RegDeleteTreeW [ADVAPI32.@] - * - */ -LSTATUS WINAPI RegDeleteTreeW( HKEY hkey, const WCHAR *subkey ) -{ - static const WCHAR emptyW[] = {0}; - DWORD name_size, max_name, max_subkey; - WCHAR *name_buf = NULL; - LONG ret; - - TRACE( "(%p, %s)\n", hkey, debugstr_w(subkey) ); - - if (subkey && *subkey) - { - ret = RegOpenKeyExW( hkey, subkey, 0, KEY_READ, &hkey ); - if (ret) return ret; - } - - ret = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, &max_subkey, - NULL, NULL, &max_name, NULL, NULL, NULL ); - if (ret) - goto cleanup; - - max_name = max( max_subkey, max_name ) + 1; - if (!(name_buf = heap_alloc( max_name * sizeof(WCHAR) ))) - { - ret = ERROR_NOT_ENOUGH_MEMORY; - goto cleanup; - } - - /* Recursively delete subkeys */ - for (;;) - { - name_size = max_name; - ret = RegEnumKeyExW( hkey, 0, name_buf, &name_size, NULL, NULL, NULL, NULL ); - if (ret == ERROR_NO_MORE_ITEMS) break; - if (ret) goto cleanup; - ret = RegDeleteTreeW( hkey, name_buf ); - if (ret) goto cleanup; - } - - /* Delete the key itself */ - if (subkey && *subkey) - { - ret = RegDeleteKeyW( hkey, emptyW ); - goto cleanup; - } - - /* Delete values */ - for (;;) - { - name_size = max_name; - ret = RegEnumValueW( hkey, 0, name_buf, &name_size, NULL, NULL, NULL, NULL ); - if (ret == ERROR_NO_MORE_ITEMS) break; - if (ret) goto cleanup; - ret = RegDeleteValueW( hkey, name_buf ); - if (ret) goto cleanup; - } - - ret = ERROR_SUCCESS; - -cleanup: - heap_free( name_buf ); - if (subkey && *subkey) - RegCloseKey( hkey ); - return ret; -} - - -/****************************************************************************** - * RegDeleteTreeA [ADVAPI32.@] - * - */ -LSTATUS WINAPI RegDeleteTreeA( HKEY hkey, const char *subkey ) -{ - UNICODE_STRING subkeyW; - LONG ret; - - if (subkey) RtlCreateUnicodeStringFromAsciiz( &subkeyW, subkey ); - else subkeyW.Buffer = NULL; - ret = RegDeleteTreeW( hkey, subkeyW.Buffer ); - RtlFreeUnicodeString( &subkeyW ); - return ret; -} - - -/****************************************************************************** - * RegCopyTreeW [ADVAPI32.@] - * - */ -LONG WINAPI RegCopyTreeW( HKEY hsrc, const WCHAR *subkey, HKEY hdst ) -{ - DWORD name_size, max_name; - DWORD value_size, max_value; - DWORD max_subkey, i, type; - WCHAR *name_buf = NULL; - BYTE *value_buf = NULL; - HKEY hkey; - LONG ret; - - TRACE( "(%p, %s, %p)\n", hsrc, debugstr_w(subkey), hdst ); - - if (subkey) - { - ret = RegOpenKeyExW( hsrc, subkey, 0, KEY_READ, &hsrc ); - if (ret) return ret; - } - - ret = RegQueryInfoKeyW( hsrc, NULL, NULL, NULL, NULL, &max_subkey, - NULL, NULL, &max_name, &max_value, NULL, NULL ); - if (ret) - goto cleanup; - - max_name = max( max_subkey, max_name ) + 1; - if (!(name_buf = heap_alloc( max_name * sizeof(WCHAR) ))) - { - ret = ERROR_NOT_ENOUGH_MEMORY; - goto cleanup; - } - - if (!(value_buf = heap_alloc( max_value ))) - { - ret = ERROR_NOT_ENOUGH_MEMORY; - goto cleanup; - } - - /* Copy values */ - for (i = 0;; i++) - { - name_size = max_name; - value_size = max_value; - ret = RegEnumValueW( hsrc, i, name_buf, &name_size, NULL, &type, value_buf, &value_size ); - if (ret == ERROR_NO_MORE_ITEMS) break; - if (ret) goto cleanup; - ret = RegSetValueExW( hdst, name_buf, 0, type, value_buf, value_size ); - if (ret) goto cleanup; - } - - /* Recursively copy subkeys */ - for (i = 0;; i++) - { - name_size = max_name; - ret = RegEnumKeyExW( hsrc, i, name_buf, &name_size, NULL, NULL, NULL, NULL ); - if (ret == ERROR_NO_MORE_ITEMS) break; - if (ret) goto cleanup; - ret = RegCreateKeyExW( hdst, name_buf, 0, NULL, 0, KEY_WRITE, NULL, &hkey, NULL ); - if (ret) goto cleanup; - ret = RegCopyTreeW( hsrc, name_buf, hkey ); - RegCloseKey( hkey ); - if (ret) goto cleanup; - } - - ret = ERROR_SUCCESS; - -cleanup: - heap_free( name_buf ); - heap_free( value_buf ); - if (subkey) - RegCloseKey( hsrc ); - return ret; + return RtlNtStatusToDosError( DisablePredefinedHandleTableInternal( HKEY_CURRENT_USER )); } @@ -3669,97 +644,3 @@ LONG WINAPI RegDisableReflectionKey(HKEY base) FIXME("%p: stub\n", base); return ERROR_SUCCESS; } - -/****************************************************************************** - * RegLoadAppKeyA [ADVAPI32.@] - * - */ -LSTATUS WINAPI RegLoadAppKeyA(const char *file, HKEY *result, REGSAM sam, DWORD options, DWORD reserved) -{ - FIXME("%s %p %u %u %u: stub\n", wine_dbgstr_a(file), result, sam, options, reserved); - - if (!file || reserved) - return ERROR_INVALID_PARAMETER; - - *result = (HKEY)0xdeadbeef; - return ERROR_SUCCESS; -} - -/****************************************************************************** - * RegLoadAppKeyW [ADVAPI32.@] - * - */ -LSTATUS WINAPI RegLoadAppKeyW(const WCHAR *file, HKEY *result, REGSAM sam, DWORD options, DWORD reserved) -{ - FIXME("%s %p %u %u %u: stub\n", wine_dbgstr_w(file), result, sam, options, reserved); - - if (!file || reserved) - return ERROR_INVALID_PARAMETER; - - *result = (HKEY)0xdeadbeef; - return ERROR_SUCCESS; -} - -/****************************************************************************** - * EnumDynamicTimeZoneInformation (ADVAPI32.@) - */ -DWORD WINAPI EnumDynamicTimeZoneInformation(const DWORD index, - DYNAMIC_TIME_ZONE_INFORMATION *dtzi) -{ - static const WCHAR mui_stdW[] = { 'M','U','I','_','S','t','d',0 }; - static const WCHAR mui_dltW[] = { 'M','U','I','_','D','l','t',0 }; - WCHAR keyname[ARRAY_SIZE(dtzi->TimeZoneKeyName)]; - HKEY time_zones_key, sub_key; - WCHAR sysdir[MAX_PATH]; - LSTATUS ret; - DWORD size; - struct tz_reg_data - { - LONG bias; - LONG std_bias; - LONG dlt_bias; - SYSTEMTIME std_date; - SYSTEMTIME dlt_date; - } tz_data; - - if (!dtzi) - return ERROR_INVALID_PARAMETER; - - ret = RegOpenKeyExA( HKEY_LOCAL_MACHINE, - "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, - KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE, &time_zones_key ); - if (ret) return ret; - - sub_key = NULL; - ret = RegEnumKeyW( time_zones_key, index, keyname, ARRAY_SIZE(keyname) ); - if (ret) goto cleanup; - - ret = RegOpenKeyExW( time_zones_key, keyname, 0, KEY_QUERY_VALUE, &sub_key ); - if (ret) goto cleanup; - - GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir)); - size = sizeof(dtzi->StandardName); - ret = RegLoadMUIStringW( sub_key, mui_stdW, dtzi->StandardName, size, NULL, 0, sysdir ); - if (ret) goto cleanup; - - size = sizeof(dtzi->DaylightName); - ret = RegLoadMUIStringW( sub_key, mui_dltW, dtzi->DaylightName, size, NULL, 0, sysdir ); - if (ret) goto cleanup; - - size = sizeof(tz_data); - ret = RegQueryValueExA( sub_key, "TZI", NULL, NULL, (BYTE*)&tz_data, &size ); - if (ret) goto cleanup; - - dtzi->Bias = tz_data.bias; - dtzi->StandardBias = tz_data.std_bias; - dtzi->DaylightBias = tz_data.dlt_bias; - memcpy( &dtzi->StandardDate, &tz_data.std_date, sizeof(tz_data.std_date) ); - memcpy( &dtzi->DaylightDate, &tz_data.dlt_date, sizeof(tz_data.dlt_date) ); - lstrcpyW( dtzi->TimeZoneKeyName, keyname ); - dtzi->DynamicDaylightTimeDisabled = FALSE; - -cleanup: - if (sub_key) RegCloseKey( sub_key ); - RegCloseKey( time_zones_key ); - return ret; -} diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index ae09daec8b3..adf988f9a42 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -262,7 +262,7 @@ @ stdcall DeleteVolumeMountPointW(wstr) kernel32.DeleteVolumeMountPointW @ stdcall DestroyPrivateObjectSecurity(ptr) advapi32.DestroyPrivateObjectSecurity @ stdcall DeviceIoControl(long long ptr long ptr long ptr ptr) kernel32.DeviceIoControl -# @ stub DisablePredefinedHandleTableInternal +@ stdcall DisablePredefinedHandleTableInternal(long) @ stdcall DisableThreadLibraryCalls(long) kernel32.DisableThreadLibraryCalls @ stdcall DisassociateCurrentThreadFromCallback(ptr) kernel32.DisassociateCurrentThreadFromCallback # @ stub DiscardVirtualMemory @@ -297,7 +297,7 @@ @ stdcall EnumDateFormatsExW(ptr long long) kernel32.EnumDateFormatsExW @ stdcall EnumDateFormatsW(ptr long long) kernel32.EnumDateFormatsW # @ stub EnumDeviceDrivers -@ stdcall EnumDynamicTimeZoneInformation(long ptr) advapi32.EnumDynamicTimeZoneInformation +@ stdcall EnumDynamicTimeZoneInformation(long ptr) @ stdcall EnumLanguageGroupLocalesW(ptr long long ptr) kernel32.EnumLanguageGroupLocalesW # @ stub EnumPageFilesA # @ stub EnumPageFilesW @@ -1256,31 +1256,31 @@ # @ stub ReclaimVirtualMemory # @ stub RefreshPolicyExInternal # @ stub RefreshPolicyInternal -@ stdcall -private RegCloseKey(long) kernel32.RegCloseKey -@ stdcall RegCopyTreeW(long wstr long) advapi32.RegCopyTreeW -@ stdcall -private RegCreateKeyExA(long str long ptr long long ptr ptr ptr) kernel32.RegCreateKeyExA +@ stdcall RegCloseKey(long) +@ stdcall RegCopyTreeW(long wstr long) +@ stdcall RegCreateKeyExA(long str long ptr long long ptr ptr ptr) # @ stub RegCreateKeyExInternalA # @ stub RegCreateKeyExInternalW -@ stdcall -private RegCreateKeyExW(long wstr long ptr long long ptr ptr ptr) kernel32.RegCreateKeyExW -@ stdcall -private RegDeleteKeyExA(long str long long) kernel32.RegDeleteKeyExA +@ stdcall RegCreateKeyExW(long wstr long ptr long long ptr ptr ptr) +@ stdcall RegDeleteKeyExA(long str long long) # @ stub RegDeleteKeyExInternalA # @ stub RegDeleteKeyExInternalW -@ stdcall -private RegDeleteKeyExW(long wstr long long) kernel32.RegDeleteKeyExW -@ stdcall RegDeleteKeyValueA(long str str) advapi32.RegDeleteKeyValueA -@ stdcall RegDeleteKeyValueW(long wstr wstr) advapi32.RegDeleteKeyValueW -@ stdcall -private RegDeleteTreeA(long str) kernel32.RegDeleteTreeA -@ stdcall -private RegDeleteTreeW(long wstr) kernel32.RegDeleteTreeW -@ stdcall -private RegDeleteValueA(long str) kernel32.RegDeleteValueA -@ stdcall -private RegDeleteValueW(long wstr) kernel32.RegDeleteValueW +@ stdcall RegDeleteKeyExW(long wstr long long) +@ stdcall RegDeleteKeyValueA(long str str) +@ stdcall RegDeleteKeyValueW(long wstr wstr) +@ stdcall RegDeleteTreeA(long str) +@ stdcall RegDeleteTreeW(long wstr) +@ stdcall RegDeleteValueA(long str) +@ stdcall RegDeleteValueW(long wstr) # @ stub RegDisablePredefinedCacheEx -@ stdcall -private RegEnumKeyExA(long long ptr ptr ptr ptr ptr ptr) kernel32.RegEnumKeyExA -@ stdcall -private RegEnumKeyExW(long long ptr ptr ptr ptr ptr ptr) kernel32.RegEnumKeyExW -@ stdcall -private RegEnumValueA(long long ptr ptr ptr ptr ptr ptr) kernel32.RegEnumValueA -@ stdcall -private RegEnumValueW(long long ptr ptr ptr ptr ptr ptr) kernel32.RegEnumValueW -@ stdcall -private RegFlushKey(long) kernel32.RegFlushKey -@ stdcall -private RegGetKeySecurity(long long ptr ptr) kernel32.RegGetKeySecurity -@ stdcall -private RegGetValueA(long str str long ptr ptr ptr) kernel32.RegGetValueA -@ stdcall -private RegGetValueW(long wstr wstr long ptr ptr ptr) kernel32.RegGetValueW +@ stdcall RegEnumKeyExA(long long ptr ptr ptr ptr ptr ptr) +@ stdcall RegEnumKeyExW(long long ptr ptr ptr ptr ptr ptr) +@ stdcall RegEnumValueA(long long ptr ptr ptr ptr ptr ptr) +@ stdcall RegEnumValueW(long long ptr ptr ptr ptr ptr ptr) +@ stdcall RegFlushKey(long) +@ stdcall RegGetKeySecurity(long long ptr ptr) +@ stdcall RegGetValueA(long str str long ptr ptr ptr) +@ stdcall RegGetValueW(long wstr wstr long ptr ptr ptr) # @ stub RegKrnGetAppKeyEventAddressInternal # @ stub RegKrnGetAppKeyLoaded # @ stub RegKrnGetClassesEnumTableAddressInternal @@ -1289,34 +1289,34 @@ # @ stub RegKrnResetAppKeyLoaded # @ stub RegKrnSetDllHasThreadStateGlobal # @ stub RegKrnSetTermsrvRegistryExtensionFlags -@ stdcall RegLoadAppKeyA(str ptr long long long) advapi32.RegLoadAppKeyA -@ stdcall RegLoadAppKeyW(wstr ptr long long long) advapi32.RegLoadAppKeyW -@ stdcall -private RegLoadKeyA(long str str) kernel32.RegLoadKeyA -@ stdcall -private RegLoadKeyW(long wstr wstr) kernel32.RegLoadKeyW -@ stdcall -private RegLoadMUIStringA(long str str long ptr long str) kernel32.RegLoadMUIStringA -@ stdcall -private RegLoadMUIStringW(long wstr wstr long ptr long wstr) kernel32.RegLoadMUIStringW -@ stdcall -private RegNotifyChangeKeyValue(long long long long long) kernel32.RegNotifyChangeKeyValue -@ stdcall -private RegOpenCurrentUser(long ptr) kernel32.RegOpenCurrentUser -@ stdcall -private RegOpenKeyExA(long str long long ptr) kernel32.RegOpenKeyExA +@ stdcall RegLoadAppKeyA(str ptr long long long) +@ stdcall RegLoadAppKeyW(wstr ptr long long long) +@ stdcall RegLoadKeyA(long str str) +@ stdcall RegLoadKeyW(long wstr wstr) +@ stdcall RegLoadMUIStringA(long str str long ptr long str) +@ stdcall RegLoadMUIStringW(long wstr wstr long ptr long wstr) +@ stdcall RegNotifyChangeKeyValue(long long long long long) +@ stdcall RegOpenCurrentUser(long ptr) +@ stdcall RegOpenKeyExA(long str long long ptr) # @ stub RegOpenKeyExInternalA # @ stub RegOpenKeyExInternalW -@ stdcall -private RegOpenKeyExW(long wstr long long ptr) kernel32.RegOpenKeyExW -@ stdcall -private RegOpenUserClassesRoot(ptr long long ptr) kernel32.RegOpenUserClassesRoot -@ stdcall -private RegQueryInfoKeyA(long ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) kernel32.RegQueryInfoKeyA -@ stdcall -private RegQueryInfoKeyW(long ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) kernel32.RegQueryInfoKeyW -@ stdcall -private RegQueryValueExA(long str ptr ptr ptr ptr) kernel32.RegQueryValueExA -@ stdcall -private RegQueryValueExW(long wstr ptr ptr ptr ptr) kernel32.RegQueryValueExW -@ stdcall -private RegRestoreKeyA(long str long) kernel32.RegRestoreKeyA -@ stdcall -private RegRestoreKeyW(long wstr long) kernel32.RegRestoreKeyW -@ stdcall RegSaveKeyExA(long str ptr long) advapi32.RegSaveKeyExA -@ stdcall RegSaveKeyExW(long wstr ptr long) advapi32.RegSaveKeyExW -@ stdcall -private RegSetKeySecurity(long long ptr) kernel32.RegSetKeySecurity -@ stdcall RegSetKeyValueA(long str str long ptr long) advapi32.RegSetKeyValueA -@ stdcall RegSetKeyValueW(long wstr wstr long ptr long) advapi32.RegSetKeyValueW -@ stdcall -private RegSetValueExA(long str long long ptr long) kernel32.RegSetValueExA -@ stdcall -private RegSetValueExW(long wstr long long ptr long) kernel32.RegSetValueExW -@ stdcall -private RegUnLoadKeyA(long str) kernel32.RegUnLoadKeyA -@ stdcall -private RegUnLoadKeyW(long wstr) kernel32.RegUnLoadKeyW +@ stdcall RegOpenKeyExW(long wstr long long ptr) +@ stdcall RegOpenUserClassesRoot(ptr long long ptr) +@ stdcall RegQueryInfoKeyA(long ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall RegQueryInfoKeyW(long ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall RegQueryValueExA(long str ptr ptr ptr ptr) +@ stdcall RegQueryValueExW(long wstr ptr ptr ptr ptr) +@ stdcall RegRestoreKeyA(long str long) +@ stdcall RegRestoreKeyW(long wstr long) +@ stdcall RegSaveKeyExA(long str ptr long) +@ stdcall RegSaveKeyExW(long wstr ptr long) +@ stdcall RegSetKeySecurity(long long ptr) +@ stdcall RegSetKeyValueA(long str str long ptr long) +@ stdcall RegSetKeyValueW(long wstr wstr long ptr long) +@ stdcall RegSetValueExA(long str long long ptr long) +@ stdcall RegSetValueExW(long wstr long long ptr long) +@ stdcall RegUnLoadKeyA(long str) +@ stdcall RegUnLoadKeyW(long wstr) # @ stub RegisterBadMemoryNotification # @ stub RegisterGPNotificationInternal # @ stub RegisterStateChangeNotification @@ -1331,7 +1331,7 @@ @ stdcall ReleaseSemaphore(long long ptr) kernel32.ReleaseSemaphore @ stdcall ReleaseSemaphoreWhenCallbackReturns(ptr long long) kernel32.ReleaseSemaphoreWhenCallbackReturns # @ stub ReleaseStateLock -# @ stub RemapPredefinedHandleInternal +@ stdcall RemapPredefinedHandleInternal(long long) @ stdcall RemoveDirectoryA(str) kernel32.RemoveDirectoryA @ stdcall RemoveDirectoryW(wstr) kernel32.RemoveDirectoryW @ stdcall RemoveDllDirectory(ptr) kernel32.RemoveDllDirectory diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index 692b10af38b..240b7302491 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -267,7 +267,7 @@ HRESULT WINAPI GetAcceptLanguagesW(WCHAR *langbuf, DWORD *buflen) len = mystrlen * sizeof(WCHAR); mystr = heap_alloc(len); mystr[0] = 0; - RegOpenKeyW(HKEY_CURRENT_USER, keyW, &mykey); + RegOpenKeyExW(HKEY_CURRENT_USER, keyW, 0, KEY_QUERY_VALUE, &mykey); lres = RegQueryValueExW(mykey, valueW, 0, &mytype, (PBYTE)mystr, &len); RegCloseKey(mykey); len = lstrlenW(mystr); diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 0bf6b44aea8..f218ffccb5d 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -1,4 +1,11 @@ /* + * Registry management + * + * Copyright 1996 Marcus Meissner + * Copyright 1998 Matthew Becker + * Copyright 1999 Sylvain St-Germain + * Copyright 1999 Alexandre Julliard + * Copyright 2017 Dmitry Timoshkov * Copyright 2019 Nikolay Sivov for CodeWeavers * * This library is free software; you can redistribute it and/or @@ -16,13 +23,3112 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winerror.h" +#include "winternl.h" +#include "winperf.h" +#include "winuser.h" #include "shlwapi.h" +#include "sddl.h" #include "wine/debug.h" #include "wine/heap.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(reg); +#define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT +#define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA + +static const WCHAR name_CLASSES_ROOT[] = + {'\\','R','e','g','i','s','t','r','y','\\', + '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[] = + {'\\','R','e','g','i','s','t','r','y','\\', + 'M','a','c','h','i','n','e',0}; +static const WCHAR name_USERS[] = + {'\\','R','e','g','i','s','t','r','y','\\', + 'U','s','e','r',0}; +static const WCHAR name_PERFORMANCE_DATA[] = + {'\\','R','e','g','i','s','t','r','y','\\', + 'P','e','r','f','D','a','t','a',0}; +static const WCHAR name_CURRENT_CONFIG[] = + {'\\','R','e','g','i','s','t','r','y','\\', + '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[] = + {'\\','R','e','g','i','s','t','r','y','\\', + 'D','y','n','D','a','t','a',0}; + +static const WCHAR * const root_key_names[] = +{ + name_CLASSES_ROOT, + NULL, /* HKEY_CURRENT_USER is determined dynamically */ + name_LOCAL_MACHINE, + name_USERS, + name_PERFORMANCE_DATA, + name_CURRENT_CONFIG, + name_DYN_DATA +}; + +static HKEY special_root_keys[ARRAY_SIZE(root_key_names)]; +static BOOL cache_disabled[ARRAY_SIZE(root_key_names)]; + +static CRITICAL_SECTION reg_mui_cs; +static CRITICAL_SECTION_DEBUG reg_mui_cs_debug = +{ + 0, 0, ®_mui_cs, + { ®_mui_cs_debug.ProcessLocksList, + ®_mui_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": reg_mui_cs") } +}; +static CRITICAL_SECTION reg_mui_cs = { ®_mui_cs_debug, -1, 0, 0, 0, 0 }; +struct mui_cache_entry { + struct list entry; + WCHAR *file_name; /* full path name */ + DWORD index; + LCID locale; + WCHAR *text; +}; +static struct list reg_mui_cache = LIST_INIT(reg_mui_cache); /* MRU */ +static unsigned int reg_mui_cache_count; +#define REG_MUI_CACHE_SIZE 8 + +static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); + +/* check if value type needs string conversion (Ansi<->Unicode) */ +static inline BOOL is_string( DWORD type ) +{ + return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ); +} + +/* check if current version is NT or Win95 */ +static inline BOOL is_version_nt(void) +{ + return !(GetVersion() & 0x80000000); +} + +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) && + !wcsnicmp( name->Buffer, wow6432nodeW, ARRAY_SIZE( wow6432nodeW ))); +} + +/* open the Wow6432Node subkey of the specified key */ +static HANDLE open_wow6432node( HANDLE key ) +{ + 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 (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) ret = 0; + return ret; +} + +/* 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 ) +{ + BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); + NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; + HANDLE subkey, root = attr->RootDirectory; + + if (!force_wow32) status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos ); + + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + { + static const WCHAR registry_root[] = {'\\','R','e','g','i','s','t','r','y','\\'}; + WCHAR *buffer = attr->ObjectName->Buffer; + DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); + UNICODE_STRING str; + + /* don't try to create registry root */ + if (!attr->RootDirectory && len > ARRAY_SIZE( registry_root ) && + !wcsnicmp( buffer, registry_root, ARRAY_SIZE( registry_root ))) + i += ARRAY_SIZE( registry_root ); + + while (i < len && buffer[i] != '\\') i++; + if (i == len && !force_wow32) return status; + + attrs = attr->Attributes; + attr->ObjectName = &str; + + for (;;) + { + str.Buffer = buffer + pos; + str.Length = (i - pos) * sizeof(WCHAR); + if (force_wow32 && pos) + { + if (is_wow6432node( &str )) force_wow32 = FALSE; + else if ((subkey = open_wow6432node( attr->RootDirectory ))) + { + if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); + attr->RootDirectory = subkey; + force_wow32 = FALSE; + } + } + if (i == len) + { + attr->Attributes = attrs; + status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos ); + } + else + { + attr->Attributes = attrs & ~OBJ_OPENLINK; + status = NtCreateKey( &subkey, access, attr, 0, class, + options & ~REG_OPTION_CREATE_LINK, dispos ); + } + if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); + if (status) return status; + if (i == len) break; + attr->RootDirectory = subkey; + while (i < len && buffer[i] == '\\') i++; + pos = i; + while (i < len && buffer[i] != '\\') i++; + } + } + attr->RootDirectory = subkey; + if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory ))) + { + if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); + attr->RootDirectory = subkey; + } + *retkey = attr->RootDirectory; + return status; +} + +/* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ +static NTSTATUS open_key( HKEY *retkey, DWORD options, 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 pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); + UNICODE_STRING str; + + *retkey = NULL; + + if (!force_wow32) + { + if (options & REG_OPTION_OPEN_LINK) attr->Attributes |= OBJ_OPENLINK; + return NtOpenKeyEx( (HANDLE *)retkey, access, attr, options ); + } + + if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID; + while (i < len && buffer[i] != '\\') i++; + attr->ObjectName = &str; + + for (;;) + { + str.Buffer = buffer + pos; + str.Length = (i - pos) * sizeof(WCHAR); + if (force_wow32 && pos) + { + if (is_wow6432node( &str )) force_wow32 = FALSE; + else if ((subkey = open_wow6432node( attr->RootDirectory ))) + { + if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); + attr->RootDirectory = subkey; + force_wow32 = FALSE; + } + } + if (i == len) + { + if (options & REG_OPTION_OPEN_LINK) attr->Attributes |= OBJ_OPENLINK; + status = NtOpenKeyEx( &subkey, access, attr, options ); + } + else + { + if (!(options & REG_OPTION_OPEN_LINK)) attr->Attributes &= ~OBJ_OPENLINK; + status = NtOpenKeyEx( &subkey, access, attr, options & ~REG_OPTION_OPEN_LINK ); + } + if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); + if (status) return status; + attr->RootDirectory = subkey; + if (i == len) break; + while (i < len && buffer[i] == '\\') i++; + pos = i; + while (i < len && buffer[i] != '\\') i++; + } + if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory ))) + { + if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); + attr->RootDirectory = subkey; + } + *retkey = attr->RootDirectory; + return status; +} + +/* create one of the HKEY_* special root keys */ +static HKEY create_special_root_hkey( HKEY hkey, DWORD access ) +{ + HKEY ret = 0; + int idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST); + + if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER)) + { + if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0; + TRACE( "HKEY_CURRENT_USER -> %p\n", hkey ); + } + else + { + OBJECT_ATTRIBUTES attr; + UNICODE_STRING name; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &name; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString( &name, root_key_names[idx] ); + if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0; + TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey ); + } + + if (!cache_disabled[idx] && !(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 */ + } + else + ret = hkey; + return ret; +} + +/* map the hkey from special root to normal key if necessary */ +static inline HKEY get_special_root_hkey( HKEY hkey, REGSAM access ) +{ + HKEY ret = hkey; + + if ((HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) + && (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST))) + { + 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) ); + } + return ret; +} + + +/****************************************************************************** + * RemapPredefinedHandleInternal (kernelbase.@) + */ +NTSTATUS WINAPI RemapPredefinedHandleInternal( HKEY hkey, HKEY override ) +{ + HKEY old_key; + int idx; + + TRACE("(%p %p)\n", hkey, override); + + if ((HandleToUlong(hkey) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) + || (HandleToUlong(hkey) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST))) + return STATUS_INVALID_HANDLE; + idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST); + + if (override) + { + NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override, + GetCurrentProcess(), (HANDLE *)&override, + 0, 0, DUPLICATE_SAME_ACCESS ); + if (status) return status; + } + + old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override ); + if (old_key) NtClose( old_key ); + return STATUS_SUCCESS; +} + + +/****************************************************************************** + * DisablePredefinedHandleTableInternal (kernelbase.@) + */ +NTSTATUS WINAPI DisablePredefinedHandleTableInternal( HKEY hkey ) +{ + HKEY old_key; + int idx; + + TRACE("(%p)\n", hkey); + + if ((HandleToUlong(hkey) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) + || (HandleToUlong(hkey) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST))) + return STATUS_INVALID_HANDLE; + idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST); + + cache_disabled[idx] = TRUE; + + old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL ); + if (old_key) NtClose( old_key ); + return STATUS_SUCCESS; +} + + +/****************************************************************************** + * RegCreateKeyExW (kernelbase.@) + * + * See RegCreateKeyExA. + */ +LSTATUS WINAPI DECLSPEC_HOTPATCH RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class, + DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, + PHKEY retkey, LPDWORD dispos ) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW, classW; + + if (reserved) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; + + attr.Length = sizeof(attr); + attr.RootDirectory = hkey; + attr.ObjectName = &nameW; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; + RtlInitUnicodeString( &nameW, name ); + RtlInitUnicodeString( &classW, class ); + + return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) ); +} + + +/****************************************************************************** + * RegCreateKeyExA (kernelbase.@) + * + * Open a registry key, creating it if it doesn't exist. + * + * PARAMS + * 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 + * + * RETURNS + * Success: ERROR_SUCCESS. + * Failure: A standard Win32 error code. retkey remains untouched. + * + * FIXME + * MAXIMUM_ALLOWED in access mask not supported by server + */ +LSTATUS WINAPI DECLSPEC_HOTPATCH RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class, + DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, + PHKEY retkey, LPDWORD dispos ) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING classW; + ANSI_STRING nameA, classA; + NTSTATUS status; + + if (reserved) return ERROR_INVALID_PARAMETER; + if (!is_version_nt()) + { + access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */ + if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */ + } + if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; + + attr.Length = sizeof(attr); + attr.RootDirectory = hkey; + attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; + RtlInitAnsiString( &nameA, name ); + RtlInitAnsiString( &classA, class ); + + if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString, + &nameA, FALSE ))) + { + if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE ))) + { + status = create_key( retkey, access, &attr, &classW, options, dispos ); + RtlFreeUnicodeString( &classW ); + } + } + return RtlNtStatusToDosError( status ); +} + + +/****************************************************************************** + * RegOpenKeyExW (kernelbase.@) + * + * See RegOpenKeyExA. + */ +LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey ) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + + if (retkey && (!name || !name[0]) && + (HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) && + (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST))) + { + *retkey = hkey; + return ERROR_SUCCESS; + } + + /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */ + if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++; + + if (!retkey) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; + + attr.Length = sizeof(attr); + attr.RootDirectory = hkey; + attr.ObjectName = &nameW; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString( &nameW, name ); + return RtlNtStatusToDosError( open_key( retkey, options, access, &attr ) ); +} + + +/****************************************************************************** + * RegOpenKeyExA (kernelbase.@) + * + * Open a registry key. + * + * PARAMS + * hkey [I] Handle of open key + * name [I] Name of subkey to open + * options [I] Open options (can be set to REG_OPTION_OPEN_LINK) + * access [I] Security access mask + * retkey [O] Handle to open key + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: A standard Win32 error code. retkey is set to 0. + * + * NOTES + * Unlike RegCreateKeyExA(), this function will not create the key if it + * does not exist. + */ +LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey ) +{ + OBJECT_ATTRIBUTES attr; + STRING nameA; + NTSTATUS status; + + if (retkey && (!name || !name[0]) && + (HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) && + (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST))) + { + *retkey = hkey; + return ERROR_SUCCESS; + } + + if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */ + else + { + /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */ + if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++; + } + + if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; + + attr.Length = sizeof(attr); + attr.RootDirectory = hkey; + attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + RtlInitAnsiString( &nameA, name ); + if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString, + &nameA, FALSE ))) + { + status = open_key( retkey, options, access, &attr ); + } + return RtlNtStatusToDosError( status ); +} + + +/****************************************************************************** + * RegOpenCurrentUser (kernelbase.@) + * + * 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. + */ +LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey ) +{ + void *data[20]; + TOKEN_USER *info = (TOKEN_USER *)data; + HANDLE token; + DWORD len = 0; + + /* get current user SID */ + if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, FALSE, &token )) + { + len = sizeof(data); + if (!GetTokenInformation( token, TokenUser, info, len, &len )) len = 0; + CloseHandle( token ); + } + if (!len) + { + ImpersonateSelf(SecurityIdentification); + if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &token)) + { + len = sizeof(data); + if (!GetTokenInformation( token, TokenUser, info, len, &len )) len = 0; + CloseHandle( token ); + } + RevertToSelf(); + } + + if (len) + { + WCHAR buffer[200]; + UNICODE_STRING string = { 0, sizeof(buffer), buffer }; + + RtlConvertSidToUnicodeString( &string, info->User.Sid, FALSE ); + return RegOpenKeyExW( HKEY_USERS, string.Buffer, 0, access, retkey ); + } + + return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey ); +} + + + +/****************************************************************************** + * RegEnumKeyExW (kernelbase.@) + * + * Enumerate subkeys of the specified open registry key. + * + * 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 + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: System error code. If there are no more subkeys available, the + * function returns ERROR_NO_MORE_ITEMS. + */ +LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len, + LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft ) +{ + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; + DWORD total_size; + + 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 ); + + if (reserved) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buffer, sizeof(buffer), &total_size ); + + while (status == STATUS_BUFFER_OVERFLOW) + { + /* retry with a dynamically allocated buffer */ + if (buf_ptr != buffer) heap_free( buf_ptr ); + if (!(buf_ptr = heap_alloc( total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_NODE_INFORMATION *)buf_ptr; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buf_ptr, total_size, &total_size ); + } + + if (!status) + { + DWORD len = info->NameLength / sizeof(WCHAR); + DWORD cls_len = info->ClassLength / sizeof(WCHAR); + + if (ft) *ft = *(FILETIME *)&info->LastWriteTime; + + if (len >= *name_len || (class && class_len && (cls_len >= *class_len))) + 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; + } + } + } + } + + if (buf_ptr != buffer) heap_free( buf_ptr ); + return RtlNtStatusToDosError( status ); +} + + +/****************************************************************************** + * RegEnumKeyExA (kernelbase.@) + * + * See RegEnumKeyExW. + */ +LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len, + LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft ) +{ + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; + DWORD total_size; + + 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 ); + + if (reserved) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buffer, sizeof(buffer), &total_size ); + + while (status == STATUS_BUFFER_OVERFLOW) + { + /* retry with a dynamically allocated buffer */ + if (buf_ptr != buffer) heap_free( buf_ptr ); + if (!(buf_ptr = heap_alloc( total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_NODE_INFORMATION *)buf_ptr; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buf_ptr, total_size, &total_size ); + } + + if (!status) + { + DWORD len, cls_len; + + RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength ); + RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset), + info->ClassLength ); + if (ft) *ft = *(FILETIME *)&info->LastWriteTime; + + if (len >= *name_len || (class && class_len && (cls_len >= *class_len))) + status = STATUS_BUFFER_OVERFLOW; + else + { + *name_len = len; + RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength ); + name[len] = 0; + if (class_len) + { + *class_len = cls_len; + if (class) + { + RtlUnicodeToMultiByteN( class, cls_len, NULL, + (WCHAR *)(buf_ptr + info->ClassOffset), + info->ClassLength ); + class[cls_len] = 0; + } + } + } + } + + if (buf_ptr != buffer) heap_free( buf_ptr ); + return RtlNtStatusToDosError( status ); +} + + +/****************************************************************************** + * RegQueryInfoKeyW (kernelbase.@) + * + * Retrieves information about the specified registry key. + * + * 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 + * + * 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) + */ +LSTATUS 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 ) +{ + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer; + DWORD total_size; + + TRACE( "(%p,%p,%d,%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 ); + + if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); + if (status && status != STATUS_BUFFER_OVERFLOW) goto done; + + if (class && class_len && *class_len) + { + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) + { + if (buf_ptr != buffer) heap_free( buf_ptr ); + if (!(buf_ptr = heap_alloc( total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_FULL_INFORMATION *)buf_ptr; + status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size ); + } + + if (status) goto done; + + if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len)) + { + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength ); + class[info->ClassLength/sizeof(WCHAR)] = 0; + } + } + else status = STATUS_SUCCESS; + + if (class_len) *class_len = info->ClassLength / sizeof(WCHAR); + if (subkeys) *subkeys = info->SubKeys; + if (max_subkey) *max_subkey = info->MaxNameLen / sizeof(WCHAR); + if (max_class) *max_class = info->MaxClassLen / sizeof(WCHAR); + if (values) *values = info->Values; + if (max_value) *max_value = info->MaxValueNameLen / sizeof(WCHAR); + if (max_data) *max_data = info->MaxValueDataLen; + if (modif) *modif = *(FILETIME *)&info->LastWriteTime; + + if (security) + { + FIXME( "security argument not supported.\n"); + *security = 0; + } + + done: + if (buf_ptr != buffer) heap_free( buf_ptr ); + return RtlNtStatusToDosError( status ); +} + + +/****************************************************************************** + * RegQueryInfoKeyA (kernelbase.@) + * + * 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. + * lpftLastWriteTime [O] FILETIME structure that is the last write time. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: nonzero error code from Winerror.h + */ +LSTATUS 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 ) +{ + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer; + DWORD total_size, len; + + TRACE( "(%p,%p,%d,%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 ); + + if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); + if (status && status != STATUS_BUFFER_OVERFLOW) goto done; + + if (class || class_len) + { + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) + { + if (buf_ptr != buffer) heap_free( buf_ptr ); + if (!(buf_ptr = heap_alloc( total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_FULL_INFORMATION *)buf_ptr; + status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size ); + } + + if (status) goto done; + + len = 0; + if (class && class_len) len = *class_len; + RtlUnicodeToMultiByteN( class, len, class_len, + (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength ); + if (len) + { + if (*class_len + 1 > len) + { + status = STATUS_BUFFER_OVERFLOW; + *class_len -= 1; + } + class[*class_len] = 0; + } + } + else status = STATUS_SUCCESS; + + if (subkeys) *subkeys = info->SubKeys; + if (max_subkey) *max_subkey = info->MaxNameLen / sizeof(WCHAR); + if (max_class) *max_class = info->MaxClassLen / sizeof(WCHAR); + if (values) *values = info->Values; + if (max_value) *max_value = info->MaxValueNameLen / sizeof(WCHAR); + if (max_data) *max_data = info->MaxValueDataLen; + if (modif) *modif = *(FILETIME *)&info->LastWriteTime; + + if (security) + { + FIXME( "security argument not supported.\n"); + *security = 0; + } + + done: + if (buf_ptr != buffer) heap_free( buf_ptr ); + return RtlNtStatusToDosError( status ); +} + +/****************************************************************************** + * RegCloseKey (kernelbase.@) + * + * Close an open registry key. + * + * PARAMS + * hkey [I] Handle of key to close + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Error code + */ +LSTATUS WINAPI DECLSPEC_HOTPATCH RegCloseKey( HKEY hkey ) +{ + if (!hkey) return ERROR_INVALID_HANDLE; + if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS; + return RtlNtStatusToDosError( NtClose( hkey ) ); +} + + +/****************************************************************************** + * RegDeleteKeyExW (kernelbase.@) + */ +LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved ) +{ + DWORD ret; + HKEY tmp; + + if (!name) return ERROR_INVALID_PARAMETER; + + if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; + + access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY; + if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp ))) + { + ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) ); + RegCloseKey( tmp ); + } + TRACE("%s ret=%08x\n", debugstr_w(name), ret); + return ret; +} + + +/****************************************************************************** + * RegDeleteKeyExA (kernelbase.@) + */ +LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved ) +{ + DWORD ret; + HKEY tmp; + + if (!name) return ERROR_INVALID_PARAMETER; + + if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; + + access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY; + if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp ))) + { + if (!is_version_nt()) /* win95 does recursive key deletes */ + { + CHAR sub[MAX_PATH]; + DWORD len = sizeof(sub); + while(!RegEnumKeyExA(tmp, 0, sub, &len, NULL, NULL, NULL, NULL)) + { + if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */ + break; + } + } + ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) ); + RegCloseKey( tmp ); + } + TRACE("%s ret=%08x\n", debugstr_a(name), ret); + return ret; +} + +/****************************************************************************** + * RegSetValueExW (kernelbase.@) + * + * Set the data and contents of a registry value. + * + * 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] Type of the value being set + * data [I] The new contents of the value to set + * count [I] Size of data + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Error code + */ +LSTATUS WINAPI DECLSPEC_HOTPATCH RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved, + DWORD type, const BYTE *data, DWORD count ) +{ + UNICODE_STRING nameW; + + /* no need for version check, not implemented on win9x anyway */ + + if ((data && ((ULONG_PTR)data >> 16) == 0) || (!data && count)) return ERROR_NOACCESS; + + if (count && is_string(type)) + { + 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); + } + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + RtlInitUnicodeString( &nameW, name ); + return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) ); +} + + +/****************************************************************************** + * RegSetValueExA (kernelbase.@) + * + * See RegSetValueExW. + * + * NOTES + * win95 does not care about count for REG_SZ and finds out the len by itself (js) + * NT does definitely care (aj) + */ +LSTATUS WINAPI DECLSPEC_HOTPATCH RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type, + const BYTE *data, DWORD count ) +{ + ANSI_STRING nameA; + UNICODE_STRING nameW; + WCHAR *dataW = NULL; + NTSTATUS status; + + if (!is_version_nt()) /* win95 */ + { + if (type == REG_SZ) + { + if (!data) return ERROR_INVALID_PARAMETER; + count = strlen((const char *)data) + 1; + } + } + else if (count && is_string(type)) + { + /* if user forgot to count terminating null, add it (yes NT does this) */ + if (data[count-1] && !data[count]) count++; + } + + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + if (is_string( type )) /* need to convert to Unicode */ + { + DWORD lenW; + RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count ); + if (!(dataW = heap_alloc( lenW ))) return ERROR_OUTOFMEMORY; + RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count ); + count = lenW; + data = (BYTE *)dataW; + } + + RtlInitAnsiString( &nameA, name ); + if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) + { + status = NtSetValueKey( hkey, &nameW, 0, type, data, count ); + RtlFreeUnicodeString( &nameW ); + } + heap_free( dataW ); + return RtlNtStatusToDosError( status ); +} + + +/****************************************************************************** + * RegSetKeyValueW (kernelbase.@) + */ +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 */ + { + if ((ret = RegCreateKeyExW( hkey, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_SET_VALUE, NULL, &hsubkey, NULL )) != ERROR_SUCCESS) return ret; + hkey = hsubkey; + } + + ret = RegSetValueExW( hkey, name, 0, type, (const BYTE*)data, len ); + if (hsubkey) RegCloseKey( hsubkey ); + return ret; +} + +/****************************************************************************** + * RegSetKeyValueA (kernelbase.@) + */ +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 ); + + if (subkey && subkey[0]) /* need to create the subkey */ + { + if ((ret = RegCreateKeyExA( hkey, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_SET_VALUE, NULL, &hsubkey, NULL )) != ERROR_SUCCESS) return ret; + hkey = hsubkey; + } + + ret = RegSetValueExA( hkey, name, 0, type, (const BYTE*)data, len ); + if (hsubkey) RegCloseKey( hsubkey ); + return ret; +} + +struct perf_provider +{ + HMODULE perflib; + WCHAR linkage[MAX_PATH]; + WCHAR objects[MAX_PATH]; + PM_OPEN_PROC *pOpen; + PM_CLOSE_PROC *pClose; + PM_COLLECT_PROC *pCollect; +}; + +static void *get_provider_entry(HKEY perf, HMODULE perflib, const char *name) +{ + char buf[MAX_PATH]; + DWORD err, type, len; + + len = sizeof(buf) - 1; + err = RegQueryValueExA(perf, name, NULL, &type, (BYTE *)buf, &len); + if (err != ERROR_SUCCESS || type != REG_SZ) + return NULL; + + buf[len] = 0; + TRACE("Loading function pointer for %s: %s\n", name, debugstr_a(buf)); + + return GetProcAddress(perflib, buf); +} + +static BOOL load_provider(HKEY root, const WCHAR *name, struct perf_provider *provider) +{ + static const WCHAR object_listW[] = { 'O','b','j','e','c','t',' ','L','i','s','t',0 }; + static const WCHAR performanceW[] = { 'P','e','r','f','o','r','m','a','n','c','e',0 }; + static const WCHAR libraryW[] = { 'L','i','b','r','a','r','y',0 }; + static const WCHAR linkageW[] = { 'L','i','n','k','a','g','e',0 }; + static const WCHAR exportW[] = { 'E','x','p','o','r','t',0 }; + WCHAR buf[MAX_PATH], buf2[MAX_PATH]; + DWORD err, type, len; + HKEY service, perf; + + err = RegOpenKeyExW(root, name, 0, KEY_READ, &service); + if (err != ERROR_SUCCESS) + return FALSE; + + provider->linkage[0] = 0; + err = RegOpenKeyExW(service, linkageW, 0, KEY_READ, &perf); + if (err == ERROR_SUCCESS) + { + len = sizeof(buf) - sizeof(WCHAR); + err = RegQueryValueExW(perf, exportW, NULL, &type, (BYTE *)buf, &len); + if (err == ERROR_SUCCESS && (type == REG_SZ || type == REG_MULTI_SZ)) + { + memcpy(provider->linkage, buf, len); + provider->linkage[len / sizeof(WCHAR)] = 0; + TRACE("Export: %s\n", debugstr_w(provider->linkage)); + } + RegCloseKey(perf); + } + + err = RegOpenKeyExW(service, performanceW, 0, KEY_READ, &perf); + RegCloseKey(service); + if (err != ERROR_SUCCESS) + return FALSE; + + provider->objects[0] = 0; + len = sizeof(buf) - sizeof(WCHAR); + err = RegQueryValueExW(perf, object_listW, NULL, &type, (BYTE *)buf, &len); + if (err == ERROR_SUCCESS && (type == REG_SZ || type == REG_MULTI_SZ)) + { + memcpy(provider->objects, buf, len); + provider->objects[len / sizeof(WCHAR)] = 0; + TRACE("Object List: %s\n", debugstr_w(provider->objects)); + } + + len = sizeof(buf) - sizeof(WCHAR); + err = RegQueryValueExW(perf, libraryW, NULL, &type, (BYTE *)buf, &len); + if (err != ERROR_SUCCESS || !(type == REG_SZ || type == REG_EXPAND_SZ)) + goto error; + + buf[len / sizeof(WCHAR)] = 0; + if (type == REG_EXPAND_SZ) + { + len = ExpandEnvironmentStringsW(buf, buf2, MAX_PATH); + if (!len || len > MAX_PATH) goto error; + lstrcpyW(buf, buf2); + } + + if (!(provider->perflib = LoadLibraryW(buf))) + { + WARN("Failed to load %s\n", debugstr_w(buf)); + goto error; + } + + GetModuleFileNameW(provider->perflib, buf, MAX_PATH); + TRACE("Loaded provider %s\n", wine_dbgstr_w(buf)); + + provider->pOpen = get_provider_entry(perf, provider->perflib, "Open"); + provider->pClose = get_provider_entry(perf, provider->perflib, "Close"); + provider->pCollect = get_provider_entry(perf, provider->perflib, "Collect"); + if (provider->pOpen && provider->pClose && provider->pCollect) + { + RegCloseKey(perf); + return TRUE; + } + + TRACE("Provider is missing required exports\n"); + FreeLibrary(provider->perflib); + +error: + RegCloseKey(perf); + return FALSE; +} + +static DWORD collect_data(struct perf_provider *provider, const WCHAR *query, void **data, DWORD *size, DWORD *obj_count) +{ + static const WCHAR globalW[] = { 'G','l','o','b','a','l',0 }; + WCHAR *linkage = provider->linkage[0] ? provider->linkage : NULL; + DWORD err; + + if (!query || !query[0]) + query = globalW; + + err = provider->pOpen(linkage); + if (err != ERROR_SUCCESS) + { + TRACE("Open(%s) error %u (%#x)\n", debugstr_w(linkage), err, err); + return err; + } + + *obj_count = 0; + err = provider->pCollect((WCHAR *)query, data, size, obj_count); + if (err != ERROR_SUCCESS) + { + TRACE("Collect error %u (%#x)\n", err, err); + *obj_count = 0; + } + + provider->pClose(); + return err; +} + +#define MAX_SERVICE_NAME 260 + +static DWORD query_perf_data(const WCHAR *query, DWORD *type, void *data, DWORD *ret_size) +{ + static const WCHAR SZ_SERVICES_KEY[] = { 'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'S','e','r','v','i','c','e','s',0 }; + DWORD err, i, data_size; + HKEY root; + PERF_DATA_BLOCK *pdb; + + if (!ret_size) + return ERROR_INVALID_PARAMETER; + + data_size = *ret_size; + *ret_size = 0; + + if (type) + *type = REG_BINARY; + + if (!data || data_size < sizeof(*pdb)) + return ERROR_MORE_DATA; + + pdb = data; + + pdb->Signature[0] = 'P'; + pdb->Signature[1] = 'E'; + pdb->Signature[2] = 'R'; + pdb->Signature[3] = 'F'; +#ifdef WORDS_BIGENDIAN + pdb->LittleEndian = FALSE; +#else + pdb->LittleEndian = TRUE; +#endif + pdb->Version = PERF_DATA_VERSION; + pdb->Revision = PERF_DATA_REVISION; + pdb->TotalByteLength = 0; + pdb->HeaderLength = sizeof(*pdb); + pdb->NumObjectTypes = 0; + pdb->DefaultObject = 0; + QueryPerformanceCounter(&pdb->PerfTime); + QueryPerformanceFrequency(&pdb->PerfFreq); + + data = pdb + 1; + pdb->SystemNameOffset = sizeof(*pdb); + pdb->SystemNameLength = (data_size - sizeof(*pdb)) / sizeof(WCHAR); + if (!GetComputerNameW(data, &pdb->SystemNameLength)) + return ERROR_MORE_DATA; + + pdb->SystemNameLength++; + pdb->SystemNameLength *= sizeof(WCHAR); + + pdb->HeaderLength += pdb->SystemNameLength; + + /* align to 8 bytes */ + if (pdb->SystemNameLength & 7) + pdb->HeaderLength += 8 - (pdb->SystemNameLength & 7); + + if (data_size < pdb->HeaderLength) + return ERROR_MORE_DATA; + + pdb->TotalByteLength = pdb->HeaderLength; + + data_size -= pdb->HeaderLength; + data = (char *)data + pdb->HeaderLength; + + err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, SZ_SERVICES_KEY, 0, KEY_READ, &root); + if (err != ERROR_SUCCESS) + return err; + + i = 0; + for (;;) + { + DWORD collected_size = data_size, obj_count = 0; + struct perf_provider provider; + WCHAR name[MAX_SERVICE_NAME]; + DWORD len = ARRAY_SIZE( name ); + void *collected_data = data; + + err = RegEnumKeyExW(root, i++, name, &len, NULL, NULL, NULL, NULL); + if (err == ERROR_NO_MORE_ITEMS) + { + err = ERROR_SUCCESS; + break; + } + + if (err != ERROR_SUCCESS) + continue; + + if (!load_provider(root, name, &provider)) + continue; + + err = collect_data(&provider, query, &collected_data, &collected_size, &obj_count); + FreeLibrary(provider.perflib); + + if (err == ERROR_MORE_DATA) + break; + + if (err == ERROR_SUCCESS) + { + PERF_OBJECT_TYPE *obj = (PERF_OBJECT_TYPE *)data; + + TRACE("Collect: obj->TotalByteLength %u, collected_size %u\n", + obj->TotalByteLength, collected_size); + + data_size -= collected_size; + data = collected_data; + + pdb->TotalByteLength += collected_size; + pdb->NumObjectTypes += obj_count; + } + } + + RegCloseKey(root); + + if (err == ERROR_SUCCESS) + { + *ret_size = pdb->TotalByteLength; + + GetSystemTime(&pdb->SystemTime); + GetSystemTimeAsFileTime((FILETIME *)&pdb->PerfTime100nSec); + } + + return err; +} + +/****************************************************************************** + * RegQueryValueExW (kernelbase.@) + * + * See RegQueryValueExA. + */ +LSTATUS WINAPI DECLSPEC_HOTPATCH RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type, + LPBYTE data, LPDWORD count ) +{ + NTSTATUS status; + UNICODE_STRING name_str; + DWORD total_size; + char buffer[256], *buf_ptr = buffer; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; + static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); + + TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", + hkey, debugstr_w(name), reserved, type, data, count, + (count && data) ? *count : 0 ); + + if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; + + if (hkey == HKEY_PERFORMANCE_DATA) + return query_perf_data(name, type, data, count); + + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + RtlInitUnicodeString( &name_str, name ); + + if (data) total_size = min( sizeof(buffer), *count + info_size ); + else + { + total_size = info_size; + if (count) *count = 0; + } + + status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, + buffer, total_size, &total_size ); + if (status && status != STATUS_BUFFER_OVERFLOW) goto done; + + if (data) + { + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count) + { + if (buf_ptr != buffer) heap_free( buf_ptr ); + if (!(buf_ptr = heap_alloc( total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; + status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, + buf_ptr, total_size, &total_size ); + } + + 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)) + { + WCHAR *ptr = (WCHAR *)(data + total_size - info_size); + if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; + } + } + else if (status != STATUS_BUFFER_OVERFLOW) goto done; + } + else status = STATUS_SUCCESS; + + if (type) *type = info->Type; + if (count) *count = total_size - info_size; + + done: + if (buf_ptr != buffer) heap_free( buf_ptr ); + return RtlNtStatusToDosError(status); +} + + +/****************************************************************************** + * RegQueryValueExA (kernelbase.@) + * + * Get the type and contents of a specified value under with a key. + * + * PARAMS + * 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 + * + * 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. + */ +LSTATUS WINAPI DECLSPEC_HOTPATCH RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, + LPDWORD type, LPBYTE data, LPDWORD count ) +{ + NTSTATUS status; + ANSI_STRING nameA; + UNICODE_STRING nameW; + DWORD total_size, datalen = 0; + char buffer[256], *buf_ptr = buffer; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; + static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); + + TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", + hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 ); + + if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; + if (hkey != HKEY_PERFORMANCE_DATA && !(hkey = get_special_root_hkey( hkey, 0 ))) + return ERROR_INVALID_HANDLE; + + if (count) datalen = *count; + if (!data && count) *count = 0; + + /* this matches Win9x behaviour - NT sets *type to a random value */ + if (type) *type = REG_NONE; + + RtlInitAnsiString( &nameA, name ); + if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) + return RtlNtStatusToDosError(status); + + if (hkey == HKEY_PERFORMANCE_DATA) + { + DWORD ret = query_perf_data( nameW.Buffer, type, data, count ); + RtlFreeUnicodeString( &nameW ); + return ret; + } + + status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, + buffer, sizeof(buffer), &total_size ); + if (status && status != STATUS_BUFFER_OVERFLOW) goto done; + + /* 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)) + { + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) + { + if (buf_ptr != buffer) heap_free( buf_ptr ); + if (!(buf_ptr = heap_alloc( total_size ))) + { + status = STATUS_NO_MEMORY; + goto done; + } + info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; + status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, + buf_ptr, total_size, &total_size ); + } + + if (status) goto done; + + if (is_string(info->Type)) + { + DWORD len; + + RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size), + total_size - info_size ); + if (data && len) + { + if (len > datalen) status = STATUS_BUFFER_OVERFLOW; + else + { + RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(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 (len < datalen && data[len-1]) data[len] = 0; + } + } + total_size = len + info_size; + } + else if (data) + { + if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW; + else memcpy( data, buf_ptr + info_size, total_size - info_size ); + } + } + else status = STATUS_SUCCESS; + + if (type) *type = info->Type; + if (count) *count = total_size - info_size; + + done: + if (buf_ptr != buffer) heap_free( buf_ptr ); + RtlFreeUnicodeString( &nameW ); + return RtlNtStatusToDosError(status); +} + + +/****************************************************************************** + * apply_restrictions [internal] + * + * Helper function for RegGetValueA/W. + */ +static void apply_restrictions( DWORD dwFlags, DWORD dwType, DWORD cbData, PLONG ret ) +{ + /* 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; + + if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD) + cbExpect = 4; + else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD) + cbExpect = 8; + + if (cbExpect && cbData != cbExpect) + *ret = ERROR_DATATYPE_MISMATCH; + } + } + else *ret = ERROR_UNSUPPORTED_TYPE; + } +} + + +/****************************************************************************** + * RegGetValueW (kernelbase.@) + * + * Retrieves the type and data for a value name associated with a key, + * optionally expanding its content and restricting its type. + * + * 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. + * pcbData [I/O] Size of pvData, updated with the size in bytes required to + * retrieve the whole content, including the trailing '\0' + * for strings. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: nonzero error code from Winerror.h + * + * NOTES + * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically + * expanded and pdwType is set to REG_SZ instead. + * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ + * without RRF_NOEXPAND is thus not allowed. + * An exception is the case where RRF_RT_ANY is specified, because then + * RRF_NOEXPAND is allowed. + */ +LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, + DWORD dwFlags, LPDWORD pdwType, PVOID pvData, + LPDWORD pcbData ) +{ + DWORD dwType, cbData = (pvData && pcbData) ? *pcbData : 0; + PVOID pvBuf = NULL; + LONG ret; + + TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n", + hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType, + pvData, pcbData, cbData); + + if (pvData && !pcbData) + return ERROR_INVALID_PARAMETER; + if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && + ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) + 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) && + dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)) + { + do { + heap_free(pvBuf); + + pvBuf = heap_alloc(cbData); + if (!pvBuf) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + if (ret == ERROR_MORE_DATA || !pvData) + 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) + { + /* Recheck dwType in case it changed since the first call */ + if (dwType == REG_EXPAND_SZ) + { + cbData = ExpandEnvironmentStringsW(pvBuf, pvData, + pcbData ? *pcbData : 0) * sizeof(WCHAR); + dwType = REG_SZ; + if(pvData && pcbData && cbData > *pcbData) + ret = ERROR_MORE_DATA; + } + else if (pvData) + CopyMemory(pvData, pvBuf, *pcbData); + } + + heap_free(pvBuf); + } + + if (pszSubKey && pszSubKey[0]) + RegCloseKey(hKey); + + apply_restrictions(dwFlags, dwType, cbData, &ret); + + if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) + ZeroMemory(pvData, *pcbData); + + if (pdwType) *pdwType = dwType; + if (pcbData) *pcbData = cbData; + + return ret; +} + + +/****************************************************************************** + * RegGetValueA (kernelbase.@) + * + * See RegGetValueW. + */ +LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue, + DWORD dwFlags, LPDWORD pdwType, PVOID pvData, + LPDWORD pcbData ) +{ + DWORD dwType, cbData = (pvData && pcbData) ? *pcbData : 0; + PVOID pvBuf = NULL; + LONG ret; + + TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n", + hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags, + pdwType, pvData, pcbData, cbData); + + if (pvData && !pcbData) + return ERROR_INVALID_PARAMETER; + if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && + ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) + 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) && + dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)) + { + do { + heap_free(pvBuf); + + pvBuf = heap_alloc(cbData); + if (!pvBuf) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + if (ret == ERROR_MORE_DATA || !pvData) + 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) + { + /* Recheck dwType in case it changed since the first call */ + if (dwType == REG_EXPAND_SZ) + { + cbData = ExpandEnvironmentStringsA(pvBuf, pvData, + pcbData ? *pcbData : 0); + dwType = REG_SZ; + if(pvData && pcbData && cbData > *pcbData) + ret = ERROR_MORE_DATA; + } + else if (pvData) + CopyMemory(pvData, pvBuf, *pcbData); + } + + heap_free(pvBuf); + } + + if (pszSubKey && pszSubKey[0]) + RegCloseKey(hKey); + + apply_restrictions(dwFlags, dwType, cbData, &ret); + + if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) + ZeroMemory(pvData, *pcbData); + + if (pdwType) *pdwType = dwType; + if (pcbData) *pcbData = cbData; + + return ret; +} + + +/****************************************************************************** + * RegEnumValueW (kernelbase.@) + * + * Enumerates the values for the specified open registry key. + * + * PARAMS + * hkey [I] Handle to key to query + * index [I] Index of value to query + * value [O] Value string + * val_count [I/O] Size of value buffer (in wchars) + * reserved [I] Reserved + * type [O] Type code + * data [O] Value data + * count [I/O] Size of data buffer (in bytes) + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: nonzero error code from Winerror.h + */ +LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count, + LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count ) +{ + NTSTATUS status; + DWORD total_size; + char buffer[256], *buf_ptr = buffer; + KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; + static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name ); + + TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n", + hkey, index, value, val_count, reserved, type, data, count ); + + if ((data && !count) || reserved || !value || !val_count) + return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); + if (data) total_size += *count; + total_size = min( sizeof(buffer), total_size ); + + status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation, + buffer, total_size, &total_size ); + + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) + { + 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 ); + } + + if (status) goto done; + + 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; + + if (data) + { + if (total_size - info->DataOffset > *count) + { + status = STATUS_BUFFER_OVERFLOW; + goto overflow; + } + memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset ); + if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type)) + { + /* if the type is REG_SZ and data is not 0-terminated + * and there is enough space in the buffer NT appends a \0 */ + WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset); + if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; + } + } + + overflow: + if (type) *type = info->Type; + if (count) *count = info->DataLength; + + done: + if (buf_ptr != buffer) heap_free( buf_ptr ); + return RtlNtStatusToDosError(status); +} + + +/****************************************************************************** + * RegEnumValueA (kernelbase.@) + * + * See RegEnumValueW. + */ +LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count, + LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count ) +{ + NTSTATUS status; + DWORD total_size; + char buffer[256], *buf_ptr = buffer; + KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; + static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name ); + + TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n", + hkey, index, value, val_count, reserved, type, data, count ); + + if ((data && !count) || reserved || !value || !val_count) + return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); + if (data) total_size += *count; + total_size = min( sizeof(buffer), total_size ); + + status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation, + buffer, total_size, &total_size ); + + /* 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. */ + + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) + { + 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 ); + } + + if (status) goto done; + + if (is_string(info->Type)) + { + DWORD len; + RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset), + total_size - info->DataOffset ); + if (data && len) + { + if (len > *count) status = STATUS_BUFFER_OVERFLOW; + else + { + RtlUnicodeToMultiByteN( (char*)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; + } + } + 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 ); + } + + if (!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; + } + } + + if (type) *type = info->Type; + if (count) *count = info->DataLength; + + done: + if (buf_ptr != buffer) heap_free( buf_ptr ); + return RtlNtStatusToDosError(status); +} + +/****************************************************************************** + * RegDeleteValueW (kernelbase.@) + * + * See RegDeleteValueA. + */ +LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name ) +{ + return RegDeleteKeyValueW( hkey, NULL, name ); +} + +/****************************************************************************** + * RegDeleteValueA (kernelbase.@) + * + * 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 + * Success: ERROR_SUCCESS + * Failure: nonzero error code from Winerror.h + */ +LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name ) +{ + return RegDeleteKeyValueA( hkey, NULL, name ); +} + +/****************************************************************************** + * RegDeleteKeyValueW (kernelbase.@) + */ +LONG WINAPI RegDeleteKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name ) +{ + UNICODE_STRING nameW; + 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 (kernelbase.@) + */ +LONG WINAPI RegDeleteKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name ) +{ + UNICODE_STRING nameW; + HKEY hsubkey = 0; + ANSI_STRING nameA; + NTSTATUS status; + + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + if (subkey) + { + LONG ret = RegOpenKeyExA( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey ); + if (ret) + return ret; + hkey = hsubkey; + } + + RtlInitAnsiString( &nameA, name ); + if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) + { + status = NtDeleteValueKey( hkey, &nameW ); + RtlFreeUnicodeString( &nameW ); + } + + if (hsubkey) RegCloseKey( hsubkey ); + return RtlNtStatusToDosError( status ); +} + +/****************************************************************************** + * RegLoadKeyW (kernelbase.@) + * + * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store + * registration information from a specified file into that subkey. + * + * PARAMS + * hkey [I] Handle of open key + * subkey [I] Address of name of subkey + * filename [I] Address of filename for registry information + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: nonzero error code from Winerror.h + */ +LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename ) +{ + OBJECT_ATTRIBUTES destkey, file; + UNICODE_STRING subkeyW, filenameW; + NTSTATUS status; + + if (!(hkey = get_special_root_hkey(hkey, 0))) return ERROR_INVALID_HANDLE; + + 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); + + status = NtLoadKey(&destkey, &file); + RtlFreeUnicodeString(&filenameW); + return RtlNtStatusToDosError( status ); +} + + +/****************************************************************************** + * RegLoadKeyA (kernelbase.@) + * + * See RegLoadKeyW. + */ +LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename ) +{ + UNICODE_STRING subkeyW, filenameW; + STRING subkeyA, filenameA; + NTSTATUS status; + LONG ret; + + RtlInitAnsiString(&subkeyA, subkey); + RtlInitAnsiString(&filenameA, filename); + + 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; +} + + +/****************************************************************************** + * RegSaveKeyExW (kernelbase.@) + */ +LSTATUS WINAPI RegSaveKeyExW( HKEY hkey, LPCWSTR file, SECURITY_ATTRIBUTES *sa, DWORD flags ) +{ + static const WCHAR format[] = + {'r','e','g','%','0','4','x','.','t','m','p',0}; + WCHAR buffer[MAX_PATH]; + int count = 0; + LPWSTR nameW; + DWORD ret, err; + HANDLE handle; + + TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa ); + + if (!file || !*file) return ERROR_INVALID_PARAMETER; + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + err = GetLastError(); + GetFullPathNameW( file, ARRAY_SIZE( buffer ), buffer, &nameW ); + + for (;;) + { + swprintf( nameW, 16, format, count++ ); + handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 ); + if (handle != INVALID_HANDLE_VALUE) break; + if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done; + + /* 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 !\nYou might want to delete all corresponding temp files in that directory.\n", debugstr_w(buffer), count); + } + + ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle)); + + CloseHandle( handle ); + if (!ret) + { + if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING )) + { + ERR( "Failed to move %s to %s\n", debugstr_w(buffer), + debugstr_w(file) ); + ret = GetLastError(); + } + } + if (ret) DeleteFileW( buffer ); + +done: + SetLastError( err ); /* restore last error code */ + return ret; +} + + +/****************************************************************************** + * RegSaveKeyExA (kernelbase.@) + */ +LSTATUS WINAPI RegSaveKeyExA( HKEY hkey, LPCSTR file, SECURITY_ATTRIBUTES *sa, DWORD flags ) +{ + UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString; + NTSTATUS status; + STRING fileA; + + RtlInitAnsiString(&fileA, file); + if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE))) + return RtlNtStatusToDosError( status ); + return RegSaveKeyExW(hkey, fileW->Buffer, sa, flags); +} + + +/****************************************************************************** + * RegRestoreKeyW (kernelbase.@) + * + * Read the registry information from a file and copy it over a key. + * + * PARAMS + * 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 + */ +LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags ) +{ + TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags); + + /* It seems to do this check before the hkey check */ + if (!lpFile || !*lpFile) + return ERROR_INVALID_PARAMETER; + + FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags); + + /* Check for file existence */ + + return ERROR_SUCCESS; +} + + +/****************************************************************************** + * RegRestoreKeyA (kernelbase.@) + * + * See RegRestoreKeyW. + */ +LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags ) +{ + UNICODE_STRING lpFileW; + LONG ret; + + RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile ); + ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags ); + RtlFreeUnicodeString( &lpFileW ); + return ret; +} + + +/****************************************************************************** + * RegUnLoadKeyW (kernelbase.@) + * + * Unload a registry key and its subkeys from the registry. + * + * PARAMS + * 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 + */ +LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey ) +{ + DWORD ret; + HKEY shkey; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING subkey; + + TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey)); + + ret = RegOpenKeyExW( hkey, lpSubKey, 0, MAXIMUM_ALLOWED, &shkey ); + if( ret ) + return ERROR_INVALID_PARAMETER; + + RtlInitUnicodeString(&subkey, lpSubKey); + InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL); + ret = RtlNtStatusToDosError(NtUnloadKey(&attr)); + + RegCloseKey(shkey); + + return ret; +} + + +/****************************************************************************** + * RegUnLoadKeyA (kernelbase.@) + * + * See RegUnLoadKeyW. + */ +LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey ) +{ + UNICODE_STRING lpSubKeyW; + LONG ret; + + RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey ); + ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer ); + RtlFreeUnicodeString( &lpSubKeyW ); + return ret; +} + + +/****************************************************************************** + * RegSetKeySecurity (kernelbase.@) + * + * Set the security of an open registry key. + * + * PARAMS + * 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 + */ +LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo, + PSECURITY_DESCRIPTOR pSecurityDesc ) +{ + TRACE("(%p,%d,%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; + + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + return RtlNtStatusToDosError( NtSetSecurityObject( hkey, SecurityInfo, pSecurityDesc ) ); +} + + +/****************************************************************************** + * RegGetKeySecurity (kernelbase.@) + * + * Get a copy of the security descriptor for a given 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 + */ +LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor, + LPDWORD lpcbSecurityDescriptor ) +{ + TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor, + *lpcbSecurityDescriptor); + + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + return RtlNtStatusToDosError( NtQuerySecurityObject( hkey, + SecurityInformation, pSecurityDescriptor, + *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) ); +} + + +/****************************************************************************** + * RegFlushKey (kernelbase.@) + * + * Immediately write a registry key to registry. + * + * PARAMS + * hkey [I] Handle of key to write + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Error code + */ +LSTATUS WINAPI RegFlushKey( HKEY hkey ) +{ + hkey = get_special_root_hkey( hkey, 0 ); + if (!hkey) return ERROR_INVALID_HANDLE; + + return RtlNtStatusToDosError( NtFlushKey( hkey ) ); +} + + +/****************************************************************************** + * RegNotifyChangeKeyValue (kernelbase.@) + * + * Notify the caller about changes to the attributes or contents of a registry key. + * + * 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 + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: nonzero error code from Winerror.h + */ +LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree, + DWORD fdwNotifyFilter, HANDLE hEvent, + BOOL fAsync ) +{ + NTSTATUS status; + IO_STATUS_BLOCK iosb; + + hkey = get_special_root_hkey( hkey, 0 ); + if (!hkey) return ERROR_INVALID_HANDLE; + + TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter, + hEvent, fAsync); + + status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb, + fdwNotifyFilter, fWatchSubTree, NULL, 0, + fAsync); + + if (status && status != STATUS_PENDING) + return RtlNtStatusToDosError( status ); + + return ERROR_SUCCESS; +} + +/****************************************************************************** + * RegOpenUserClassesRoot (kernelbase.@) + * + * Open the HKEY_CLASSES_ROOT key for a user. + * + * PARAMS + * hToken [I] Handle of token representing the user + * dwOptions [I] Reserved, must be 0 + * samDesired [I] Desired access rights + * phkResult [O] Destination for the resulting key handle + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: nonzero error code from Winerror.h + * + * NOTES + * 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. + */ +LSTATUS WINAPI RegOpenUserClassesRoot( HANDLE hToken, DWORD dwOptions, REGSAM samDesired, PHKEY phkResult ) +{ + FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult); + + *phkResult = HKEY_CLASSES_ROOT; + return ERROR_SUCCESS; +} + + +static void dump_mui_cache(void) +{ + struct mui_cache_entry *ent; + + TRACE("---------- MUI Cache ----------\n"); + LIST_FOR_EACH_ENTRY( ent, ®_mui_cache, struct mui_cache_entry, entry ) + TRACE("entry=%p, %s,-%u [%#x] => %s\n", + ent, wine_dbgstr_w(ent->file_name), ent->index, ent->locale, wine_dbgstr_w(ent->text)); +} + +static inline void free_mui_cache_entry(struct mui_cache_entry *ent) +{ + heap_free(ent->file_name); + heap_free(ent->text); + heap_free(ent); +} + +/* critical section must be held */ +static int reg_mui_cache_get(const WCHAR *file_name, UINT index, WCHAR **buffer) +{ + struct mui_cache_entry *ent; + + TRACE("(%s %u %p)\n", wine_dbgstr_w(file_name), index, buffer); + + LIST_FOR_EACH_ENTRY(ent, ®_mui_cache, struct mui_cache_entry, entry) + { + if (ent->index == index && ent->locale == GetThreadLocale() && + !wcsicmp(ent->file_name, file_name)) + goto found; + } + return 0; + +found: + /* move to the list head */ + if (list_prev(®_mui_cache, &ent->entry)) { + list_remove(&ent->entry); + list_add_head(®_mui_cache, &ent->entry); + } + + TRACE("=> %s\n", wine_dbgstr_w(ent->text)); + *buffer = ent->text; + return lstrlenW(ent->text); +} + +/* critical section must be held */ +static void reg_mui_cache_put(const WCHAR *file_name, UINT index, const WCHAR *buffer, INT size) +{ + struct mui_cache_entry *ent; + TRACE("(%s %u %s %d)\n", wine_dbgstr_w(file_name), index, wine_dbgstr_wn(buffer, size), size); + + ent = heap_calloc(sizeof(*ent), 1); + if (!ent) + return; + ent->file_name = heap_alloc((lstrlenW(file_name) + 1) * sizeof(WCHAR)); + if (!ent->file_name) { + free_mui_cache_entry(ent); + return; + } + lstrcpyW(ent->file_name, file_name); + ent->index = index; + ent->locale = GetThreadLocale(); + ent->text = heap_alloc((size + 1) * sizeof(WCHAR)); + if (!ent->text) { + free_mui_cache_entry(ent); + return; + } + memcpy(ent->text, buffer, size * sizeof(WCHAR)); + ent->text[size] = '\0'; + + TRACE("add %p\n", ent); + list_add_head(®_mui_cache, &ent->entry); + if (reg_mui_cache_count > REG_MUI_CACHE_SIZE) { + ent = LIST_ENTRY( list_tail( ®_mui_cache ), struct mui_cache_entry, entry ); + TRACE("freeing %p\n", ent); + list_remove(&ent->entry); + free_mui_cache_entry(ent); + } + else + reg_mui_cache_count++; + + if (TRACE_ON(reg)) + dump_mui_cache(); + return; +} + +static LONG load_mui_string(const WCHAR *file_name, UINT res_id, WCHAR *buffer, INT max_chars, INT *req_chars, DWORD flags) +{ + HMODULE hModule = NULL; + WCHAR *string = NULL, *full_name; + int size; + LONG result; + + /* Verify the file existence. i.e. We don't rely on PATH variable */ + if (GetFileAttributesW(file_name) == INVALID_FILE_ATTRIBUTES) + return ERROR_FILE_NOT_FOUND; + + size = GetFullPathNameW(file_name, 0, NULL, NULL); + full_name = heap_alloc(size * sizeof(WCHAR)); + if (!size) + return GetLastError(); + GetFullPathNameW(file_name, size, full_name, NULL); + + EnterCriticalSection(®_mui_cs); + size = reg_mui_cache_get(full_name, res_id, &string); + if (!size) { + LeaveCriticalSection(®_mui_cs); + + /* Load the file */ + hModule = LoadLibraryExW(full_name, NULL, + LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + if (!hModule) + return GetLastError(); + + size = LoadStringW(hModule, res_id, (WCHAR *)&string, 0); + if (!size) { + if (string) result = ERROR_NOT_FOUND; + else result = GetLastError(); + goto cleanup; + } + + EnterCriticalSection(®_mui_cs); + reg_mui_cache_put(full_name, res_id, string, size); + LeaveCriticalSection(®_mui_cs); + } + *req_chars = size + 1; + + /* If no buffer is given, skip copying. */ + if (!buffer) { + result = ERROR_MORE_DATA; + goto cleanup; + } + + /* Else copy over the string, respecting the buffer size. */ + if (size < max_chars) + max_chars = size; + else { + if (flags & REG_MUI_STRING_TRUNCATE) + max_chars--; + else { + result = ERROR_MORE_DATA; + goto cleanup; + } + } + if (max_chars >= 0) { + memcpy(buffer, string, max_chars * sizeof(WCHAR)); + buffer[max_chars] = '\0'; + } + + result = ERROR_SUCCESS; + +cleanup: + if (hModule) + FreeLibrary(hModule); + else + LeaveCriticalSection(®_mui_cs); + heap_free(full_name); + return result; +} + +/****************************************************************************** + * RegLoadMUIStringW (kernelbase.@) + * + * 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] Truncate output to fit the buffer if REG_MUI_STRING_TRUNCATE. + * pszBaseDir [I] Base directory of loading path. If NULL, use the current directory. + * + * RETURNS + * Success: ERROR_SUCCESS, + * Failure: nonzero error code from winerror.h + */ +LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer, + LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir) +{ + DWORD dwValueType, cbData; + LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL; + LONG result; + + TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, " + "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer, + cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir)); + + /* Parameter sanity checks. */ + if (!hKey || (!pwszBuffer && cbBuffer) || (cbBuffer % sizeof(WCHAR)) + || ((dwFlags & REG_MUI_STRING_TRUNCATE) && pcbData) + || (dwFlags & ~REG_MUI_STRING_TRUNCATE)) + return ERROR_INVALID_PARAMETER; + + /* Check for value existence and correctness of its type, allocate a buffer and load it. */ + 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; + } + pwszTempBuffer = heap_alloc(cbData); + if (!pwszTempBuffer) { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData); + if (result != ERROR_SUCCESS) goto cleanup; + + /* '@' is the prefix for resource based string entries. */ + if (*pwszTempBuffer != '@') { + result = ERROR_INVALID_DATA; + goto cleanup; + } + + /* Expand environment variables regardless of the type. */ + cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR); + if (!cbData) goto cleanup; + pwszExpandedBuffer = heap_alloc(cbData); + if (!pwszExpandedBuffer) { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData / sizeof(WCHAR)); + + /* Parse the value and load the string. */ + { + WCHAR *pComma = wcsrchr(pwszExpandedBuffer, ','), *pNewBuffer; + const WCHAR backslashW[] = {'\\',0}; + UINT uiStringId; + DWORD baseDirLen; + int reqChars; + + /* Format of the expanded value is 'path_to_dll,-resId' */ + if (!pComma || pComma[1] != '-') { + result = ERROR_INVALID_DATA; + goto cleanup; + } + + uiStringId = wcstol(pComma+2, NULL, 10); + *pComma = '\0'; + + /* Build a resource dll path. */ + baseDirLen = pwszBaseDir ? lstrlenW(pwszBaseDir) : 0; + cbData = (baseDirLen + 1 + lstrlenW(pwszExpandedBuffer + 1) + 1) * sizeof(WCHAR); + pNewBuffer = heap_realloc(pwszTempBuffer, cbData); + if (!pNewBuffer) { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + pwszTempBuffer = pNewBuffer; + pwszTempBuffer[0] = '\0'; + if (baseDirLen) { + lstrcpyW(pwszTempBuffer, pwszBaseDir); + if (pwszBaseDir[baseDirLen - 1] != '\\') + lstrcatW(pwszTempBuffer, backslashW); + } + lstrcatW(pwszTempBuffer, pwszExpandedBuffer + 1); + + /* Load specified string from the file */ + reqChars = 0; + result = load_mui_string(pwszTempBuffer, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR), &reqChars, dwFlags); + if (pcbData && (result == ERROR_SUCCESS || result == ERROR_MORE_DATA)) + *pcbData = reqChars * sizeof(WCHAR); + } + +cleanup: + heap_free(pwszTempBuffer); + heap_free(pwszExpandedBuffer); + return result; +} + +/****************************************************************************** + * RegLoadMUIStringA (kernelbase.@) + * + * Not implemented on native. + */ +LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer, + LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir) +{ + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/****************************************************************************** + * RegDeleteTreeW (kernelbase.@) + * + */ +LSTATUS WINAPI RegDeleteTreeW( HKEY hkey, const WCHAR *subkey ) +{ + static const WCHAR emptyW[] = {0}; + DWORD name_size, max_name, max_subkey; + WCHAR *name_buf = NULL; + LONG ret; + + TRACE( "(%p, %s)\n", hkey, debugstr_w(subkey) ); + + if (subkey && *subkey) + { + ret = RegOpenKeyExW( hkey, subkey, 0, KEY_READ, &hkey ); + if (ret) return ret; + } + + ret = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, &max_subkey, + NULL, NULL, &max_name, NULL, NULL, NULL ); + if (ret) + goto cleanup; + + max_name = max( max_subkey, max_name ) + 1; + if (!(name_buf = heap_alloc( max_name * sizeof(WCHAR) ))) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + + /* Recursively delete subkeys */ + for (;;) + { + name_size = max_name; + ret = RegEnumKeyExW( hkey, 0, name_buf, &name_size, NULL, NULL, NULL, NULL ); + if (ret == ERROR_NO_MORE_ITEMS) break; + if (ret) goto cleanup; + ret = RegDeleteTreeW( hkey, name_buf ); + if (ret) goto cleanup; + } + + /* Delete the key itself */ + if (subkey && *subkey) + { + ret = RegDeleteKeyExW( hkey, emptyW, 0, 0 ); + goto cleanup; + } + + /* Delete values */ + for (;;) + { + name_size = max_name; + ret = RegEnumValueW( hkey, 0, name_buf, &name_size, NULL, NULL, NULL, NULL ); + if (ret == ERROR_NO_MORE_ITEMS) break; + if (ret) goto cleanup; + ret = RegDeleteValueW( hkey, name_buf ); + if (ret) goto cleanup; + } + + ret = ERROR_SUCCESS; + +cleanup: + heap_free( name_buf ); + if (subkey && *subkey) + RegCloseKey( hkey ); + return ret; +} + + +/****************************************************************************** + * RegDeleteTreeA (kernelbase.@) + * + */ +LSTATUS WINAPI RegDeleteTreeA( HKEY hkey, const char *subkey ) +{ + UNICODE_STRING subkeyW; + LONG ret; + + if (subkey) RtlCreateUnicodeStringFromAsciiz( &subkeyW, subkey ); + else subkeyW.Buffer = NULL; + ret = RegDeleteTreeW( hkey, subkeyW.Buffer ); + RtlFreeUnicodeString( &subkeyW ); + return ret; +} + + +/****************************************************************************** + * RegCopyTreeW (kernelbase.@) + * + */ +LSTATUS WINAPI RegCopyTreeW( HKEY hsrc, const WCHAR *subkey, HKEY hdst ) +{ + DWORD name_size, max_name; + DWORD value_size, max_value; + DWORD max_subkey, i, type; + WCHAR *name_buf = NULL; + BYTE *value_buf = NULL; + HKEY hkey; + LONG ret; + + TRACE( "(%p, %s, %p)\n", hsrc, debugstr_w(subkey), hdst ); + + if (subkey) + { + ret = RegOpenKeyExW( hsrc, subkey, 0, KEY_READ, &hsrc ); + if (ret) return ret; + } + + ret = RegQueryInfoKeyW( hsrc, NULL, NULL, NULL, NULL, &max_subkey, + NULL, NULL, &max_name, &max_value, NULL, NULL ); + if (ret) + goto cleanup; + + max_name = max( max_subkey, max_name ) + 1; + if (!(name_buf = heap_alloc( max_name * sizeof(WCHAR) ))) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + + if (!(value_buf = heap_alloc( max_value ))) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + + /* Copy values */ + for (i = 0;; i++) + { + name_size = max_name; + value_size = max_value; + ret = RegEnumValueW( hsrc, i, name_buf, &name_size, NULL, &type, value_buf, &value_size ); + if (ret == ERROR_NO_MORE_ITEMS) break; + if (ret) goto cleanup; + ret = RegSetValueExW( hdst, name_buf, 0, type, value_buf, value_size ); + if (ret) goto cleanup; + } + + /* Recursively copy subkeys */ + for (i = 0;; i++) + { + name_size = max_name; + ret = RegEnumKeyExW( hsrc, i, name_buf, &name_size, NULL, NULL, NULL, NULL ); + if (ret == ERROR_NO_MORE_ITEMS) break; + if (ret) goto cleanup; + ret = RegCreateKeyExW( hdst, name_buf, 0, NULL, 0, KEY_WRITE, NULL, &hkey, NULL ); + if (ret) goto cleanup; + ret = RegCopyTreeW( hsrc, name_buf, hkey ); + RegCloseKey( hkey ); + if (ret) goto cleanup; + } + + ret = ERROR_SUCCESS; + +cleanup: + heap_free( name_buf ); + heap_free( value_buf ); + if (subkey) + RegCloseKey( hsrc ); + return ret; +} + + +/****************************************************************************** + * RegLoadAppKeyA (kernelbase.@) + * + */ +LSTATUS WINAPI RegLoadAppKeyA(const char *file, HKEY *result, REGSAM sam, DWORD options, DWORD reserved) +{ + FIXME("%s %p %u %u %u: stub\n", wine_dbgstr_a(file), result, sam, options, reserved); + + if (!file || reserved) + return ERROR_INVALID_PARAMETER; + + *result = (HKEY)0xdeadbeef; + return ERROR_SUCCESS; +} + +/****************************************************************************** + * RegLoadAppKeyW (kernelbase.@) + * + */ +LSTATUS WINAPI RegLoadAppKeyW(const WCHAR *file, HKEY *result, REGSAM sam, DWORD options, DWORD reserved) +{ + FIXME("%s %p %u %u %u: stub\n", wine_dbgstr_w(file), result, sam, options, reserved); + + if (!file || reserved) + return ERROR_INVALID_PARAMETER; + + *result = (HKEY)0xdeadbeef; + return ERROR_SUCCESS; +} + +/****************************************************************************** + * EnumDynamicTimeZoneInformation (kernelbase.@) + */ +DWORD WINAPI EnumDynamicTimeZoneInformation(const DWORD index, + DYNAMIC_TIME_ZONE_INFORMATION *dtzi) +{ + static const WCHAR mui_stdW[] = { 'M','U','I','_','S','t','d',0 }; + static const WCHAR mui_dltW[] = { 'M','U','I','_','D','l','t',0 }; + WCHAR keyname[ARRAY_SIZE(dtzi->TimeZoneKeyName)]; + HKEY time_zones_key, sub_key; + WCHAR sysdir[MAX_PATH]; + LSTATUS ret; + DWORD size; + struct tz_reg_data + { + LONG bias; + LONG std_bias; + LONG dlt_bias; + SYSTEMTIME std_date; + SYSTEMTIME dlt_date; + } tz_data; + + if (!dtzi) + return ERROR_INVALID_PARAMETER; + + ret = RegOpenKeyExA( HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, + KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE, &time_zones_key ); + if (ret) return ret; + + sub_key = NULL; + size = ARRAY_SIZE(keyname); + ret = RegEnumKeyExW( time_zones_key, index, keyname, &size, NULL, NULL, NULL, NULL ); + if (ret) goto cleanup; + + ret = RegOpenKeyExW( time_zones_key, keyname, 0, KEY_QUERY_VALUE, &sub_key ); + if (ret) goto cleanup; + + GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir)); + size = sizeof(dtzi->StandardName); + ret = RegLoadMUIStringW( sub_key, mui_stdW, dtzi->StandardName, size, NULL, 0, sysdir ); + if (ret) goto cleanup; + + size = sizeof(dtzi->DaylightName); + ret = RegLoadMUIStringW( sub_key, mui_dltW, dtzi->DaylightName, size, NULL, 0, sysdir ); + if (ret) goto cleanup; + + size = sizeof(tz_data); + ret = RegQueryValueExA( sub_key, "TZI", NULL, NULL, (BYTE*)&tz_data, &size ); + if (ret) goto cleanup; + + dtzi->Bias = tz_data.bias; + dtzi->StandardBias = tz_data.std_bias; + dtzi->DaylightBias = tz_data.dlt_bias; + memcpy( &dtzi->StandardDate, &tz_data.std_date, sizeof(tz_data.std_date) ); + memcpy( &dtzi->DaylightDate, &tz_data.dlt_date, sizeof(tz_data.dlt_date) ); + lstrcpyW( dtzi->TimeZoneKeyName, keyname ); + dtzi->DynamicDaylightTimeDisabled = FALSE; + +cleanup: + if (sub_key) RegCloseKey( sub_key ); + RegCloseKey( time_zones_key ); + return ret; +} + + struct USKEY { HKEY HKCUstart; /* Start key in CU hive */ @@ -334,7 +3440,8 @@ LONG WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, const WCHAR *value, DWORD type, vo if (!hKey->HKCUkey) { /* Create the key */ - ret = RegCreateKeyW(hKey->HKCUstart, hKey->path, &hKey->HKCUkey); + ret = RegCreateKeyExW(hKey->HKCUstart, hKey->path, 0, NULL, REG_OPTION_NON_VOLATILE, + MAXIMUM_ALLOWED, NULL, &hKey->HKCUkey, NULL); TRACE("Creating HKCU key, ret = %d\n", ret); if (ret && (flags & SHREGSET_FORCE_HKCU)) { @@ -359,7 +3466,8 @@ LONG WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, const WCHAR *value, DWORD type, vo if (!hKey->HKLMkey) { /* Create the key */ - ret = RegCreateKeyW(hKey->HKLMstart, hKey->path, &hKey->HKLMkey); + ret = RegCreateKeyExW(hKey->HKLMstart, hKey->path, 0, NULL, REG_OPTION_NON_VOLATILE, + MAXIMUM_ALLOWED, NULL, &hKey->HKLMkey, NULL); TRACE("Creating HKLM key, ret = %d\n", ret); if (ret && (flags & (SHREGSET_FORCE_HKLM))) { diff --git a/include/winreg.h b/include/winreg.h index bc001c84a53..c00379150a6 100644 --- a/include/winreg.h +++ b/include/winreg.h @@ -104,6 +104,9 @@ WINADVAPI LSTATUS WINAPI RegCloseKey(HKEY); WINADVAPI LSTATUS WINAPI RegConnectRegistryA(LPCSTR,HKEY,PHKEY); WINADVAPI LSTATUS WINAPI RegConnectRegistryW(LPCWSTR,HKEY,PHKEY); #define RegConnectRegistry WINELIB_NAME_AW(RegConnectRegistry) +WINADVAPI LSTATUS WINAPI RegCopyTreeA(HKEY,const char*,HKEY); +WINADVAPI LSTATUS WINAPI RegCopyTreeW(HKEY,const WCHAR*,HKEY); +#define RegCopyTree WINELIB_NAME_AW(RegCopyTree) WINADVAPI LSTATUS WINAPI RegCreateKeyA(HKEY,LPCSTR,PHKEY); WINADVAPI LSTATUS WINAPI RegCreateKeyW(HKEY,LPCWSTR,PHKEY); #define RegCreateKey WINELIB_NAME_AW(RegCreateKey)