[shell32.dll]
[reactos.git] / dll / win32 / shell32 / GlueCode.cpp
1
2 LONG WINAPI RegCopyTreeX(HKEY, LPCWSTR, HKEY)
3 {
4 DebugBreak();
5 return 0;
6 }
7
8 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
9 {
10 HGLOBAL hMemory;
11 HRSRC hResource;
12 WCHAR *pString;
13 int idxString;
14
15 /* Negative values have to be inverted. */
16 if (HIWORD(resId) == 0xffff)
17 resId = (UINT)(-((INT)resId));
18
19 /* Load the resource into memory and get a pointer to it. */
20 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
21 if (!hResource) return 0;
22 hMemory = LoadResource(hModule, hResource);
23 if (!hMemory) return 0;
24 pString = (WCHAR *)LockResource(hMemory);
25
26 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
27 idxString = resId & 0xf;
28 while (idxString--) pString += *pString + 1;
29
30 /* If no buffer is given, return length of the string. */
31 if (!pwszBuffer) return *pString;
32
33 /* Else copy over the string, respecting the buffer size. */
34 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
35 if (cMaxChars >= 0)
36 {
37 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
38 pwszBuffer[cMaxChars] = L'\0';
39 }
40
41 return cMaxChars;
42 }
43
44 LONG WINAPI
45 RegLoadMUIStringWX(IN HKEY hKey,
46 IN LPCWSTR pszValue OPTIONAL,
47 OUT LPWSTR pszOutBuf,
48 IN DWORD cbOutBuf,
49 OUT LPDWORD pcbData OPTIONAL,
50 IN DWORD Flags,
51 IN LPCWSTR pszDirectory OPTIONAL)
52 {
53 DWORD dwValueType, cbData;
54 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
55 LONG result;
56
57 /* Parameter sanity checks. */
58 if (!hKey || !pszOutBuf)
59 return ERROR_INVALID_PARAMETER;
60
61 if (pszDirectory && *pszDirectory)
62 {
63 return ERROR_INVALID_PARAMETER;
64 }
65
66 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
67 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
68 if (result != ERROR_SUCCESS) goto cleanup;
69 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
70 {
71 result = ERROR_FILE_NOT_FOUND;
72 goto cleanup;
73 }
74 pwszTempBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cbData);
75 if (!pwszTempBuffer)
76 {
77 result = ERROR_NOT_ENOUGH_MEMORY;
78 goto cleanup;
79 }
80 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
81 if (result != ERROR_SUCCESS) goto cleanup;
82
83 /* Expand environment variables, if appropriate, or copy the original string over. */
84 if (dwValueType == REG_EXPAND_SZ)
85 {
86 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
87 if (!cbData) goto cleanup;
88 pwszExpandedBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cbData);
89 if (!pwszExpandedBuffer)
90 {
91 result = ERROR_NOT_ENOUGH_MEMORY;
92 goto cleanup;
93 }
94 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
95 }
96 else
97 {
98 pwszExpandedBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cbData);
99 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
100 }
101
102 /* If the value references a resource based string, parse the value and load the string.
103 * Else just copy over the original value. */
104 result = ERROR_SUCCESS;
105 if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
106 {
107 lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
108 }
109 else
110 {
111 WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
112 UINT uiStringId;
113 HMODULE hModule;
114
115 /* Format of the expanded value is 'path_to_dll,-resId' */
116 if (!pComma || pComma[1] != L'-')
117 {
118 result = ERROR_BADKEY;
119 goto cleanup;
120 }
121
122 uiStringId = _wtoi(pComma+2);
123 *pComma = L'\0';
124
125 hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
126 if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
127 result = ERROR_BADKEY;
128 FreeLibrary(hModule);
129 }
130
131 cleanup:
132 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
133 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
134 return result;
135 }
136
137 #if 0
138 VOID WINAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString);
139 #else
140 typedef VOID (WINAPI *PRtlFreeUnicodeString)(PUNICODE_STRING UnicodeString);
141 static VOID WINAPI
142 RtlFreeUnicodeStringx(PUNICODE_STRING UnicodeString)
143 {
144 static PRtlFreeUnicodeString Func = NULL;
145
146 if (Func == NULL)
147 {
148 HMODULE hShlwapi;
149 hShlwapi = LoadLibrary(TEXT("ntdll.DLL"));
150 if (hShlwapi != NULL)
151 {
152 Func = (PRtlFreeUnicodeString)GetProcAddress(hShlwapi, "RtlFreeUnicodeString");
153 }
154 }
155
156 if (Func != NULL)
157 {
158 Func(UnicodeString);
159 return;
160 }
161
162 MessageBox(NULL, TEXT("RtlFreeUnicodeString not available"), NULL, 0);
163 }
164 #endif
165
166 LONG WINAPI
167 RegLoadMUIStringAX(IN HKEY hKey,
168 IN LPCSTR pszValue OPTIONAL,
169 OUT LPSTR pszOutBuf,
170 IN DWORD cbOutBuf,
171 OUT LPDWORD pcbData OPTIONAL,
172 IN DWORD Flags,
173 IN LPCSTR pszDirectory OPTIONAL)
174 {
175 UNICODE_STRING valueW, baseDirW;
176 WCHAR *pwszBuffer;
177 DWORD cbData = cbOutBuf * sizeof(WCHAR);
178 LONG result;
179
180 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
181 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
182 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
183 !(pwszBuffer = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, cbData)))
184 {
185 result = ERROR_NOT_ENOUGH_MEMORY;
186 goto cleanup;
187 }
188
189 result = RegLoadMUIStringWX(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
190 baseDirW.Buffer);
191
192 if (result == ERROR_SUCCESS)
193 {
194 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
195 if (pcbData)
196 *pcbData = cbData;
197 }
198
199 cleanup:
200 HeapFree(GetProcessHeap(), 0, pwszBuffer);
201 RtlFreeUnicodeStringx(&baseDirW);
202 RtlFreeUnicodeStringx(&valueW);
203
204 return result;
205 }
206
207 static VOID
208 RegpApplyRestrictions(DWORD dwFlags,
209 DWORD dwType,
210 DWORD cbData,
211 PLONG ret)
212 {
213 /* Check if the type is restricted by the passed flags */
214 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
215 {
216 DWORD dwMask = 0;
217
218 switch (dwType)
219 {
220 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
221 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
222 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
223 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
224 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
225 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
226 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
227 }
228
229 if (dwFlags & dwMask)
230 {
231 /* Type is not restricted, check for size mismatch */
232 if (dwType == REG_BINARY)
233 {
234 DWORD cbExpect = 0;
235
236 if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
237 cbExpect = 4;
238 else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD)
239 cbExpect = 8;
240
241 if (cbExpect && cbData != cbExpect)
242 *ret = ERROR_DATATYPE_MISMATCH;
243 }
244 }
245 else *ret = ERROR_UNSUPPORTED_TYPE;
246 }
247 }
248
249 LONG WINAPI RegGetValueX(HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData)
250 {
251 DWORD dwType, cbData = pcbData ? *pcbData : 0;
252 PVOID pvBuf = NULL;
253 LONG ret;
254
255 if (pvData && !pcbData)
256 return ERROR_INVALID_PARAMETER;
257 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
258 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
259 return ERROR_INVALID_PARAMETER;
260
261 if (pszSubKey && pszSubKey[0])
262 {
263 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
264 if (ret != ERROR_SUCCESS) return ret;
265 }
266
267 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, (LPBYTE)pvData, &cbData);
268
269 /* If we are going to expand we need to read in the whole the value even
270 * if the passed buffer was too small as the expanded string might be
271 * smaller than the unexpanded one and could fit into cbData bytes. */
272 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
273 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
274 {
275 do
276 {
277 HeapFree(GetProcessHeap(), 0, pvBuf);
278
279 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
280 if (!pvBuf)
281 {
282 ret = ERROR_NOT_ENOUGH_MEMORY;
283 break;
284 }
285
286 if (ret == ERROR_MORE_DATA || !pvData)
287 ret = RegQueryValueExW(hKey, pszValue, NULL,
288 &dwType, (LPBYTE)pvBuf, &cbData);
289 else
290 {
291 /* Even if cbData was large enough we have to copy the
292 * string since ExpandEnvironmentStrings can't handle
293 * overlapping buffers. */
294 CopyMemory(pvBuf, pvData, cbData);
295 }
296
297 /* Both the type or the value itself could have been modified in
298 * between so we have to keep retrying until the buffer is large
299 * enough or we no longer have to expand the value. */
300 }
301 while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
302
303 if (ret == ERROR_SUCCESS)
304 {
305 /* Recheck dwType in case it changed since the first call */
306 if (dwType == REG_EXPAND_SZ)
307 {
308 cbData = ExpandEnvironmentStringsW((LPCWSTR)pvBuf, (LPWSTR)pvData,
309 pcbData ? *pcbData : 0) * sizeof(WCHAR);
310 dwType = REG_SZ;
311 if (pvData && pcbData && cbData > *pcbData)
312 ret = ERROR_MORE_DATA;
313 }
314 else if (pvData)
315 CopyMemory(pvData, pvBuf, *pcbData);
316 }
317
318 HeapFree(GetProcessHeap(), 0, pvBuf);
319 }
320
321 if (pszSubKey && pszSubKey[0])
322 RegCloseKey(hKey);
323
324 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
325
326 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
327 ZeroMemory(pvData, *pcbData);
328
329 if (pdwType)
330 *pdwType = dwType;
331
332 if (pcbData)
333 *pcbData = cbData;
334
335 return ret;
336 }