From 2747b47c79a237e0698864b293107f5474ce079d Mon Sep 17 00:00:00 2001 From: Ged Murphy Date: Wed, 21 Jun 2006 21:19:47 +0000 Subject: [PATCH] Port RegGetValue() from WINE patch by Thomas Weidenmueller svn path=/trunk/; revision=22491 --- reactos/dll/win32/advapi32/advapi32.def | 2 + reactos/dll/win32/advapi32/reg/reg.c | 252 ++++++++++++++++++++++++ 2 files changed, 254 insertions(+) diff --git a/reactos/dll/win32/advapi32/advapi32.def b/reactos/dll/win32/advapi32/advapi32.def index 69643ecc82f..d8e59993188 100644 --- a/reactos/dll/win32/advapi32/advapi32.def +++ b/reactos/dll/win32/advapi32/advapi32.def @@ -494,6 +494,8 @@ RegEnumValueA@32 RegEnumValueW@32 RegFlushKey@4 RegGetKeySecurity@16 +RegGetValueA@28 +RegGetValueW@28 RegLoadKeyA@12 RegLoadKeyW@12 RegLoadMUIStringA@24 diff --git a/reactos/dll/win32/advapi32/reg/reg.c b/reactos/dll/win32/advapi32/reg/reg.c index 8faea3a3990..bc6552379b0 100644 --- a/reactos/dll/win32/advapi32/reg/reg.c +++ b/reactos/dll/win32/advapi32/reg/reg.c @@ -1680,6 +1680,258 @@ RegEnableReflectionKey(IN HKEY hBase) return ERROR_CALL_NOT_IMPLEMENTED; } +/****************************************************************************** + * RegpApplyRestrictions [internal] + * + * Helper function for RegGetValueA/W. + */ +static VOID +RegpApplyRestrictions( 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_DWORD) == RRF_RT_DWORD) + cbExpect = 4; + else if ((dwFlags & RRF_RT_DWORD) == 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 it's content and restricting it's 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 required to + * retrieve the whole content. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: nonzero error code from Winerror.h + * + * NOTES + * - Unless RRF_NOEXPAND is specified REG_EXPAND_SZ is automatically expanded + * and REG_SZ is retrieved instead. + * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ + * without RRF_NOEXPAND is thus not allowed. + */ +LONG WINAPI +RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, + DWORD dwFlags, LPDWORD pdwType, PVOID pvData, + LPDWORD pcbData ) +{ + DWORD dwType, cbData = pcbData ? *pcbData : 0; + PVOID pvBuf = NULL; + LONG ret; + + TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n", + hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType, + pvData, pcbData, cbData); + + if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND)) + 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 { + if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf); + + pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData); + if (!pvBuf) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + if (ret == ERROR_MORE_DATA) + 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) + { + if (dwType == REG_EXPAND_SZ) + { + cbData = ExpandEnvironmentStringsW(pvBuf, pvData, + pcbData ? *pcbData : 0); + dwType = REG_SZ; + if(pcbData && cbData > *pcbData) + ret = ERROR_MORE_DATA; + } + else if (pcbData) + CopyMemory(pvData, pvBuf, *pcbData); + } + + if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf); + } + + if (pszSubKey && pszSubKey[0]) + RegCloseKey(hKey); + + RegpApplyRestrictions(dwFlags, dwType, cbData, &ret); + + if (pcbData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) + ZeroMemory(pvData, *pcbData); + + if (pdwType) *pdwType = dwType; + if (pcbData) *pcbData = cbData; + + return ret; +} + + +/****************************************************************************** + * RegGetValueA [ADVAPI32.@] + * + * See RegGetValueW. + */ +LONG WINAPI +RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue, + DWORD dwFlags, LPDWORD pdwType, PVOID pvData, + LPDWORD pcbData ) +{ + DWORD dwType, cbData = pcbData ? *pcbData : 0; + PVOID pvBuf = NULL; + LONG ret; + + TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n", + hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData, + cbData); + + if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND)) + 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 { + if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf); + + pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData); + if (!pvBuf) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + if (ret == ERROR_MORE_DATA) + 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) + { + if (dwType == REG_EXPAND_SZ) + { + cbData = ExpandEnvironmentStringsA(pvBuf, pvData, + pcbData ? *pcbData : 0); + dwType = REG_SZ; + if(pcbData && cbData > *pcbData) + ret = ERROR_MORE_DATA; + } + else if (pcbData) + CopyMemory(pvData, pvBuf, *pcbData); + } + + if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf); + } + + if (pszSubKey && pszSubKey[0]) + RegCloseKey(hKey); + + RegpApplyRestrictions(dwFlags, dwType, cbData, &ret); + + if (pcbData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) + ZeroMemory(pvData, *pcbData); + + if (pdwType) *pdwType = dwType; + if (pcbData) *pcbData = cbData; + + return ret; +} + /************************************************************************ * RegSetKeyValueW