reactos/dll/win32/advapi32_vista/RegLoadMUIString.c
Getequ d559ca9c98 [ADVAPI32][SHELL32][DESK.CPL] Kill copy-paste of RegLoadMUIString. (#748)
RegLoadMUIStringW/A is part of advapi32.dll . shell32.dll and desk.cpl contained exact line-by-line copy of that function.
2018-08-16 16:10:41 +02:00

196 lines
6.1 KiB
C

#include "advapi32_vista.h"
#include <winuser.h>
#include <wine/debug.h>
#include <wine/unicode.h>
WINE_DEFAULT_DEBUG_CHANNEL(reg);
/******************************************************************************
* load_string [Internal]
*
* This is basically a copy of user32/resource.c's LoadStringW. Necessary to
* avoid importing user32, which is higher level than advapi32. Helper for
* RegLoadMUIString.
*/
static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
{
HGLOBAL hMemory;
HRSRC hResource;
WCHAR *pString;
int idxString;
/* Negative values have to be inverted. */
if (HIWORD(resId) == 0xffff)
resId = (UINT)(-((INT)resId));
/* Load the resource into memory and get a pointer to it. */
hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
if (!hResource) return 0;
hMemory = LoadResource(hModule, hResource);
if (!hMemory) return 0;
pString = LockResource(hMemory);
/* Strings are length-prefixed. Lowest nibble of resId is an index. */
idxString = resId & 0xf;
while (idxString--) pString += *pString + 1;
/* If no buffer is given, return length of the string. */
if (!pwszBuffer) return *pString;
/* Else copy over the string, respecting the buffer size. */
cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
if (cMaxChars >= 0)
{
memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
pwszBuffer[cMaxChars] = L'\0';
}
return cMaxChars;
}
/************************************************************************
* RegLoadMUIStringW
*
* @implemented
*/
LONG WINAPI
RegLoadMUIStringW(IN HKEY hKey,
IN LPCWSTR pszValue OPTIONAL,
OUT LPWSTR pszOutBuf,
IN DWORD cbOutBuf,
OUT LPDWORD pcbData OPTIONAL,
IN DWORD Flags,
IN LPCWSTR pszDirectory OPTIONAL)
{
DWORD dwValueType, cbData;
LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
LONG result;
/* Parameter sanity checks. */
if (!hKey || !pszOutBuf)
return ERROR_INVALID_PARAMETER;
if (pszDirectory && *pszDirectory)
{
FIXME("BaseDir parameter not yet supported!\n");
return ERROR_INVALID_PARAMETER;
}
/* Check for value existence and correctness of it's type, allocate a buffer and load it. */
result = RegQueryValueExW(hKey, pszValue, 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 = HeapAlloc(GetProcessHeap(), 0, cbData);
if (!pwszTempBuffer)
{
result = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
if (result != ERROR_SUCCESS) goto cleanup;
/* Expand environment variables, if appropriate, or copy the original string over. */
if (dwValueType == REG_EXPAND_SZ)
{
cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
if (!cbData) goto cleanup;
pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
if (!pwszExpandedBuffer)
{
result = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
}
else
{
pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
}
/* If the value references a resource based string, parse the value and load the string.
* Else just copy over the original value. */
result = ERROR_SUCCESS;
if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
{
lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
}
else
{
WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
UINT uiStringId;
HMODULE hModule;
/* Format of the expanded value is 'path_to_dll,-resId' */
if (!pComma || pComma[1] != L'-')
{
result = ERROR_BADKEY;
goto cleanup;
}
uiStringId = _wtoi(pComma+2);
*pComma = L'\0';
hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
result = ERROR_BADKEY;
FreeLibrary(hModule);
}
cleanup:
HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
return result;
}
/************************************************************************
* RegLoadMUIStringA
*
* @implemented
*/
LONG WINAPI
RegLoadMUIStringA(IN HKEY hKey,
IN LPCSTR pszValue OPTIONAL,
OUT LPSTR pszOutBuf,
IN DWORD cbOutBuf,
OUT LPDWORD pcbData OPTIONAL,
IN DWORD Flags,
IN LPCSTR pszDirectory OPTIONAL)
{
UNICODE_STRING valueW, baseDirW;
WCHAR *pwszBuffer;
DWORD cbData = cbOutBuf * sizeof(WCHAR);
LONG result;
valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
!RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
!(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
{
result = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
baseDirW.Buffer);
if (result == ERROR_SUCCESS)
{
cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
if (pcbData)
*pcbData = cbData;
}
cleanup:
HeapFree(GetProcessHeap(), 0, pwszBuffer);
RtlFreeUnicodeString(&baseDirW);
RtlFreeUnicodeString(&valueW);
return result;
}