|
| 1 | +#include "desk.h" |
| 2 | + |
| 3 | +/****************************************************************************** |
| 4 | + * load_string [Internal] |
| 5 | + * |
| 6 | + * This is basically a copy of user32/resource.c's LoadStringW. Necessary to |
| 7 | + * avoid importing user32, which is higher level than advapi32. Helper for |
| 8 | + * RegLoadMUIString. |
| 9 | + */ |
| 10 | +static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars) |
| 11 | +{ |
| 12 | + HGLOBAL hMemory; |
| 13 | + HRSRC hResource; |
| 14 | + WCHAR *pString; |
| 15 | + int idxString; |
| 16 | + |
| 17 | + /* Negative values have to be inverted. */ |
| 18 | + if (HIWORD(resId) == 0xffff) |
| 19 | + resId = (UINT)(-((INT)resId)); |
| 20 | + |
| 21 | + /* Load the resource into memory and get a pointer to it. */ |
| 22 | + hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING); |
| 23 | + if (!hResource) return 0; |
| 24 | + hMemory = LoadResource(hModule, hResource); |
| 25 | + if (!hMemory) return 0; |
| 26 | + pString = LockResource(hMemory); |
| 27 | + |
| 28 | + /* Strings are length-prefixed. Lowest nibble of resId is an index. */ |
| 29 | + idxString = resId & 0xf; |
| 30 | + while (idxString--) pString += *pString + 1; |
| 31 | + |
| 32 | + /* If no buffer is given, return length of the string. */ |
| 33 | + if (!pwszBuffer) return *pString; |
| 34 | + |
| 35 | + /* Else copy over the string, respecting the buffer size. */ |
| 36 | + cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1); |
| 37 | + if (cMaxChars >= 0) |
| 38 | + { |
| 39 | + memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR)); |
| 40 | + pwszBuffer[cMaxChars] = L'\0'; |
| 41 | + } |
| 42 | + |
| 43 | + return cMaxChars; |
| 44 | +} |
| 45 | + |
| 46 | + |
| 47 | +/************************************************************************ |
| 48 | + * RegLoadMUIStringW |
| 49 | + * |
| 50 | + * @implemented |
| 51 | + */ |
| 52 | +LONG |
| 53 | +RegLoadMUIStringW(IN HKEY hKey, |
| 54 | + IN LPCWSTR pszValue OPTIONAL, |
| 55 | + OUT LPWSTR pszOutBuf, |
| 56 | + IN DWORD cbOutBuf, |
| 57 | + OUT LPDWORD pcbData OPTIONAL, |
| 58 | + IN DWORD Flags, |
| 59 | + IN LPCWSTR pszDirectory OPTIONAL) |
| 60 | +{ |
| 61 | + DWORD dwValueType, cbData; |
| 62 | + LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL; |
| 63 | + LONG result; |
| 64 | + |
| 65 | + /* Parameter sanity checks. */ |
| 66 | + if (!hKey || !pszOutBuf) |
| 67 | + return ERROR_INVALID_PARAMETER; |
| 68 | + |
| 69 | + if (pszDirectory && *pszDirectory) |
| 70 | + { |
| 71 | + //FIXME("BaseDir parameter not yet supported!\n"); |
| 72 | + return ERROR_INVALID_PARAMETER; |
| 73 | + } |
| 74 | + |
| 75 | + /* Check for value existence and correctness of it's type, allocate a buffer and load it. */ |
| 76 | + result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData); |
| 77 | + if (result != ERROR_SUCCESS) goto cleanup; |
| 78 | + if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) |
| 79 | + { |
| 80 | + result = ERROR_FILE_NOT_FOUND; |
| 81 | + goto cleanup; |
| 82 | + } |
| 83 | + pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); |
| 84 | + if (!pwszTempBuffer) |
| 85 | + { |
| 86 | + result = ERROR_NOT_ENOUGH_MEMORY; |
| 87 | + goto cleanup; |
| 88 | + } |
| 89 | + result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData); |
| 90 | + if (result != ERROR_SUCCESS) goto cleanup; |
| 91 | + |
| 92 | + /* Expand environment variables, if appropriate, or copy the original string over. */ |
| 93 | + if (dwValueType == REG_EXPAND_SZ) |
| 94 | + { |
| 95 | + cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR); |
| 96 | + if (!cbData) goto cleanup; |
| 97 | + pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); |
| 98 | + if (!pwszExpandedBuffer) |
| 99 | + { |
| 100 | + result = ERROR_NOT_ENOUGH_MEMORY; |
| 101 | + goto cleanup; |
| 102 | + } |
| 103 | + ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData); |
| 104 | + } |
| 105 | + else |
| 106 | + { |
| 107 | + pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); |
| 108 | + memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData); |
| 109 | + } |
| 110 | + |
| 111 | + /* If the value references a resource based string, parse the value and load the string. |
| 112 | + * Else just copy over the original value. */ |
| 113 | + result = ERROR_SUCCESS; |
| 114 | + if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */ |
| 115 | + { |
| 116 | + lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR)); |
| 117 | + } |
| 118 | + else |
| 119 | + { |
| 120 | + WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L','); |
| 121 | + UINT uiStringId; |
| 122 | + HMODULE hModule; |
| 123 | + |
| 124 | + /* Format of the expanded value is 'path_to_dll,-resId' */ |
| 125 | + if (!pComma || pComma[1] != L'-') |
| 126 | + { |
| 127 | + result = ERROR_BADKEY; |
| 128 | + goto cleanup; |
| 129 | + } |
| 130 | + |
| 131 | + uiStringId = _wtoi(pComma+2); |
| 132 | + *pComma = L'\0'; |
| 133 | + |
| 134 | + hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE); |
| 135 | + if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR))) |
| 136 | + result = ERROR_BADKEY; |
| 137 | + FreeLibrary(hModule); |
| 138 | + } |
| 139 | + |
| 140 | +cleanup: |
| 141 | + HeapFree(GetProcessHeap(), 0, pwszTempBuffer); |
| 142 | + HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer); |
| 143 | + return result; |
| 144 | +} |
0 commit comments