Resource file strings cleanup (#581)
[reactos.git] / dll / win32 / shell32 / vista.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: Copied from advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 * 19990309 EA Stubs
11 * 20050502 Fireball imported some stuff from WINE
12 */
13
14 #include <stdarg.h>
15
16 #define WIN32_NO_STATUS
17 #define _INC_WINDOWS
18 #define COM_NO_WINDOWS_H
19
20 #include <windef.h>
21 #include <winbase.h>
22 #include <winreg.h>
23 #include <winuser.h>
24 #define NTOS_MODE_USER
25 #include <ndk/rtlfuncs.h>
26
27 #include <wine/debug.h>
28 #include <wine/unicode.h>
29
30 WINE_DEFAULT_DEBUG_CHANNEL(shell);
31
32 /******************************************************************************
33 * load_string [Internal]
34 *
35 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
36 * avoid importing user32, which is higher level than advapi32. Helper for
37 * RegLoadMUIString.
38 */
39 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
40 {
41 HGLOBAL hMemory;
42 HRSRC hResource;
43 WCHAR *pString;
44 int idxString;
45
46 /* Negative values have to be inverted. */
47 if (HIWORD(resId) == 0xffff)
48 resId = (UINT)(-((INT)resId));
49
50 /* Load the resource into memory and get a pointer to it. */
51 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
52 if (!hResource) return 0;
53 hMemory = LoadResource(hModule, hResource);
54 if (!hMemory) return 0;
55 pString = LockResource(hMemory);
56
57 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
58 idxString = resId & 0xf;
59 while (idxString--) pString += *pString + 1;
60
61 /* If no buffer is given, return length of the string. */
62 if (!pwszBuffer) return *pString;
63
64 /* Else copy over the string, respecting the buffer size. */
65 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
66 if (cMaxChars >= 0)
67 {
68 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
69 pwszBuffer[cMaxChars] = L'\0';
70 }
71
72 return cMaxChars;
73 }
74
75 /************************************************************************
76 * RegLoadMUIStringW
77 *
78 * @implemented
79 */
80 LONG WINAPI
81 RegLoadMUIStringW(IN HKEY hKey,
82 IN LPCWSTR pszValue OPTIONAL,
83 OUT LPWSTR pszOutBuf,
84 IN DWORD cbOutBuf,
85 OUT LPDWORD pcbData OPTIONAL,
86 IN DWORD Flags,
87 IN LPCWSTR pszDirectory OPTIONAL)
88 {
89 DWORD dwValueType, cbData;
90 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
91 LONG result;
92
93 /* Parameter sanity checks. */
94 if (!hKey || !pszOutBuf)
95 return ERROR_INVALID_PARAMETER;
96
97 if (pszDirectory && *pszDirectory)
98 {
99 FIXME("BaseDir parameter not yet supported!\n");
100 return ERROR_INVALID_PARAMETER;
101 }
102
103 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
104 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
105 if (result != ERROR_SUCCESS) goto cleanup;
106 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
107 {
108 result = ERROR_FILE_NOT_FOUND;
109 goto cleanup;
110 }
111 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
112 if (!pwszTempBuffer)
113 {
114 result = ERROR_NOT_ENOUGH_MEMORY;
115 goto cleanup;
116 }
117 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
118 if (result != ERROR_SUCCESS) goto cleanup;
119
120 /* Expand environment variables, if appropriate, or copy the original string over. */
121 if (dwValueType == REG_EXPAND_SZ)
122 {
123 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
124 if (!cbData) goto cleanup;
125 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
126 if (!pwszExpandedBuffer)
127 {
128 result = ERROR_NOT_ENOUGH_MEMORY;
129 goto cleanup;
130 }
131 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
132 }
133 else
134 {
135 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
136 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
137 }
138
139 /* If the value references a resource based string, parse the value and load the string.
140 * Else just copy over the original value. */
141 result = ERROR_SUCCESS;
142 if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
143 {
144 lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
145 }
146 else
147 {
148 WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
149 UINT uiStringId;
150 HMODULE hModule;
151
152 /* Format of the expanded value is 'path_to_dll,-resId' */
153 if (!pComma || pComma[1] != L'-')
154 {
155 result = ERROR_BADKEY;
156 goto cleanup;
157 }
158
159 uiStringId = _wtoi(pComma+2);
160 *pComma = L'\0';
161
162 hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
163 if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
164 result = ERROR_BADKEY;
165 FreeLibrary(hModule);
166 }
167
168 cleanup:
169 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
170 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
171 return result;
172 }
173
174 /************************************************************************
175 * RegLoadMUIStringA
176 *
177 * @implemented
178 */
179 LONG WINAPI
180 RegLoadMUIStringA(IN HKEY hKey,
181 IN LPCSTR pszValue OPTIONAL,
182 OUT LPSTR pszOutBuf,
183 IN DWORD cbOutBuf,
184 OUT LPDWORD pcbData OPTIONAL,
185 IN DWORD Flags,
186 IN LPCSTR pszDirectory OPTIONAL)
187 {
188 UNICODE_STRING valueW, baseDirW;
189 WCHAR *pwszBuffer;
190 DWORD cbData = cbOutBuf * sizeof(WCHAR);
191 LONG result;
192
193 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
194 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
195 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
196 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
197 {
198 result = ERROR_NOT_ENOUGH_MEMORY;
199 goto cleanup;
200 }
201
202 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
203 baseDirW.Buffer);
204
205 if (result == ERROR_SUCCESS)
206 {
207 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
208 if (pcbData)
209 *pcbData = cbData;
210 }
211
212 cleanup:
213 HeapFree(GetProcessHeap(), 0, pwszBuffer);
214 RtlFreeUnicodeString(&baseDirW);
215 RtlFreeUnicodeString(&valueW);
216
217 return result;
218 }