[MSI_WINETEST] Fix build with CMake 3.9.0 and higher (attempt #2)
[reactos.git] / dll / win32 / shlwapi / reg.c
1 /*
2 * SHLWAPI registry functions
3 *
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2001 Guy Albertelli
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <stdarg.h>
23 #include <string.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "wine/debug.h"
29 #define NO_SHLWAPI_STREAM
30 #include "shlwapi.h"
31 #include "wine/unicode.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(shell);
34
35 /* Key/Value names for MIME content types */
36 static const char lpszContentTypeA[] = "Content Type";
37 static const WCHAR lpszContentTypeW[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
38
39 static const char szMimeDbContentA[] = "MIME\\Database\\Content Type\\";
40 static const WCHAR szMimeDbContentW[] = { 'M', 'I', 'M','E','\\',
41 'D','a','t','a','b','a','s','e','\\','C','o','n','t','e','n','t',
42 ' ','T','y','p','e','\\', 0 };
43 static const DWORD dwLenMimeDbContent = 27; /* strlen of szMimeDbContentA/W */
44
45 static const char szExtensionA[] = "Extension";
46 static const WCHAR szExtensionW[] = { 'E', 'x', 't','e','n','s','i','o','n','\0' };
47
48 /* internal structure of what the HUSKEY points to */
49 typedef struct {
50 HKEY HKCUstart; /* Start key in CU hive */
51 HKEY HKCUkey; /* Opened key in CU hive */
52 HKEY HKLMstart; /* Start key in LM hive */
53 HKEY HKLMkey; /* Opened key in LM hive */
54 WCHAR lpszPath[MAX_PATH];
55 } SHUSKEY, *LPSHUSKEY;
56
57 INT WINAPI SHStringFromGUIDW(REFGUID,LPWSTR,INT);
58 HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID,LPCWSTR,BOOL,BOOL,PHKEY);
59
60
61 #define REG_HKCU TRUE
62 #define REG_HKLM FALSE
63 /*************************************************************************
64 * REG_GetHKEYFromHUSKEY
65 *
66 * Function: Return the proper registry key from the HUSKEY structure
67 * also allow special predefined values.
68 */
69 static HKEY REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which)
70 {
71 HKEY test = hUSKey;
72 LPSHUSKEY mihk = hUSKey;
73
74 if ((test == HKEY_CLASSES_ROOT) ||
75 (test == HKEY_CURRENT_CONFIG) ||
76 (test == HKEY_CURRENT_USER) ||
77 (test == HKEY_DYN_DATA) ||
78 (test == HKEY_LOCAL_MACHINE) ||
79 (test == HKEY_PERFORMANCE_DATA) ||
80 /* FIXME: need to define for Win2k, ME, XP
81 * (test == HKEY_PERFORMANCE_TEXT) ||
82 * (test == HKEY_PERFORMANCE_NLSTEXT) ||
83 */
84 (test == HKEY_USERS)) return test;
85 if (which == REG_HKCU) return mihk->HKCUkey;
86 return mihk->HKLMkey;
87 }
88
89
90 /*************************************************************************
91 * SHRegOpenUSKeyA [SHLWAPI.@]
92 *
93 * Open a user-specific registry key.
94 *
95 * PARAMS
96 * Path [I] Key name to open
97 * AccessType [I] Access type
98 * hRelativeUSKey [I] Relative user key
99 * phNewUSKey [O] Destination for created key
100 * fIgnoreHKCU [I] TRUE=Don't check HKEY_CURRENT_USER
101 *
102 * RETURNS
103 * Success: ERROR_SUCCESS
104 * Failure: An error code from RegOpenKeyExA().
105 */
106 LONG WINAPI SHRegOpenUSKeyA(LPCSTR Path, REGSAM AccessType, HUSKEY hRelativeUSKey,
107 PHUSKEY phNewUSKey, BOOL fIgnoreHKCU)
108 {
109 WCHAR szPath[MAX_PATH];
110
111 if (Path)
112 MultiByteToWideChar(CP_ACP, 0, Path, -1, szPath, MAX_PATH);
113
114 return SHRegOpenUSKeyW(Path ? szPath : NULL, AccessType, hRelativeUSKey,
115 phNewUSKey, fIgnoreHKCU);
116 }
117
118 /*************************************************************************
119 * SHRegOpenUSKeyW [SHLWAPI.@]
120 *
121 * See SHRegOpenUSKeyA.
122 */
123 LONG WINAPI SHRegOpenUSKeyW(LPCWSTR Path, REGSAM AccessType, HUSKEY hRelativeUSKey,
124 PHUSKEY phNewUSKey, BOOL fIgnoreHKCU)
125 {
126 LONG ret2, ret1 = ~ERROR_SUCCESS;
127 LPSHUSKEY hKey;
128
129 TRACE("(%s,0x%x,%p,%p,%d)\n", debugstr_w(Path),(LONG)AccessType,
130 hRelativeUSKey, phNewUSKey, fIgnoreHKCU);
131
132 if (phNewUSKey)
133 *phNewUSKey = NULL;
134
135 /* Create internal HUSKEY */
136 hKey = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*hKey));
137 lstrcpynW(hKey->lpszPath, Path, sizeof(hKey->lpszPath)/sizeof(WCHAR));
138
139 if (hRelativeUSKey)
140 {
141 hKey->HKCUstart = SHRegDuplicateHKey(REG_GetHKEYFromHUSKEY(hRelativeUSKey, REG_HKCU));
142 hKey->HKLMstart = SHRegDuplicateHKey(REG_GetHKEYFromHUSKEY(hRelativeUSKey, REG_HKLM));
143
144 /* FIXME: if either of these keys is NULL, create the start key from
145 * the relative keys start+path
146 */
147 }
148 else
149 {
150 hKey->HKCUstart = HKEY_CURRENT_USER;
151 hKey->HKLMstart = HKEY_LOCAL_MACHINE;
152 }
153
154 if (!fIgnoreHKCU)
155 {
156 ret1 = RegOpenKeyExW(hKey->HKCUstart, hKey->lpszPath, 0, AccessType, &hKey->HKCUkey);
157 if (ret1)
158 hKey->HKCUkey = 0;
159 }
160
161 ret2 = RegOpenKeyExW(hKey->HKLMstart, hKey->lpszPath, 0, AccessType, &hKey->HKLMkey);
162 if (ret2)
163 hKey->HKLMkey = 0;
164
165 if (ret1 || ret2)
166 TRACE("one or more opens failed: HKCU=%d HKLM=%d\n", ret1, ret2);
167
168 if (ret1 && ret2)
169 {
170 /* Neither open succeeded: fail */
171 SHRegCloseUSKey(hKey);
172 return ret2;
173 }
174
175 TRACE("HUSKEY=%p\n", hKey);
176 if (phNewUSKey)
177 *phNewUSKey = hKey;
178 return ERROR_SUCCESS;
179 }
180
181 /*************************************************************************
182 * SHRegCloseUSKey [SHLWAPI.@]
183 *
184 * Close a user-specific registry key
185 *
186 * RETURNS
187 * Success: ERROR_SUCCESS
188 * Failure: An error code from RegCloseKey().
189 */
190 LONG WINAPI SHRegCloseUSKey(
191 HUSKEY hUSKey) /* [I] Key to close */
192 {
193 LPSHUSKEY hKey = hUSKey;
194 LONG ret = ERROR_SUCCESS;
195
196 if (!hKey)
197 return ERROR_INVALID_PARAMETER;
198
199 if (hKey->HKCUkey)
200 ret = RegCloseKey(hKey->HKCUkey);
201 if (hKey->HKCUstart && hKey->HKCUstart != HKEY_CURRENT_USER)
202 ret = RegCloseKey(hKey->HKCUstart);
203 if (hKey->HKLMkey)
204 ret = RegCloseKey(hKey->HKLMkey);
205 if (hKey->HKLMstart && hKey->HKLMstart != HKEY_LOCAL_MACHINE)
206 ret = RegCloseKey(hKey->HKLMstart);
207
208 HeapFree(GetProcessHeap(), 0, hKey);
209 return ret;
210 }
211
212 /*************************************************************************
213 * SHRegCreateUSKeyA [SHLWAPI.@]
214 *
215 * See SHRegCreateUSKeyW.
216 */
217 LONG WINAPI SHRegCreateUSKeyA(LPCSTR path, REGSAM samDesired, HUSKEY relative_key,
218 PHUSKEY new_uskey, DWORD flags)
219 {
220 WCHAR *pathW;
221 LONG ret;
222
223 TRACE("(%s, 0x%08x, %p, %p, 0x%08x)\n", debugstr_a(path), samDesired, relative_key,
224 new_uskey, flags);
225
226 if (path)
227 {
228 INT len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
229 pathW = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
230 if (!pathW)
231 return ERROR_NOT_ENOUGH_MEMORY;
232 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
233 }
234 else
235 pathW = NULL;
236
237 ret = SHRegCreateUSKeyW(pathW, samDesired, relative_key, new_uskey, flags);
238 HeapFree(GetProcessHeap(), 0, pathW);
239 return ret;
240 }
241
242 /*************************************************************************
243 * SHRegCreateUSKeyW [SHLWAPI.@]
244 *
245 * Create or open a user-specific registry key.
246 *
247 * PARAMS
248 * path [I] Key name to create or open.
249 * samDesired [I] Wanted security access.
250 * relative_key [I] Base path if 'path' is relative. NULL otherwise.
251 * new_uskey [O] Receives a handle to the new or opened key.
252 * flags [I] Base key under which the key should be opened.
253 *
254 * RETURNS
255 * Success: ERROR_SUCCESS
256 * Failure: Nonzero error code from winerror.h
257 */
258 LONG WINAPI SHRegCreateUSKeyW(LPCWSTR path, REGSAM samDesired, HUSKEY relative_key,
259 PHUSKEY new_uskey, DWORD flags)
260 {
261 LONG ret = ERROR_CALL_NOT_IMPLEMENTED;
262 SHUSKEY *ret_key;
263
264 TRACE("(%s, 0x%08x, %p, %p, 0x%08x)\n", debugstr_w(path), samDesired,
265 relative_key, new_uskey, flags);
266
267 if (!new_uskey) return ERROR_INVALID_PARAMETER;
268
269 *new_uskey = NULL;
270
271 if (flags & ~SHREGSET_FORCE_HKCU)
272 {
273 FIXME("unsupported flags 0x%08x\n", flags);
274 return ERROR_SUCCESS;
275 }
276
277 ret_key = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret_key));
278 lstrcpynW(ret_key->lpszPath, path, sizeof(ret_key->lpszPath)/sizeof(WCHAR));
279
280 if (relative_key)
281 {
282 ret_key->HKCUstart = SHRegDuplicateHKey(REG_GetHKEYFromHUSKEY(relative_key, REG_HKCU));
283 ret_key->HKLMstart = SHRegDuplicateHKey(REG_GetHKEYFromHUSKEY(relative_key, REG_HKLM));
284 }
285 else
286 {
287 ret_key->HKCUstart = HKEY_CURRENT_USER;
288 ret_key->HKLMstart = HKEY_LOCAL_MACHINE;
289 }
290
291 if (flags & SHREGSET_FORCE_HKCU)
292 {
293 ret = RegCreateKeyExW(ret_key->HKCUstart, path, 0, NULL, 0, samDesired, NULL, &ret_key->HKCUkey, NULL);
294 if (ret == ERROR_SUCCESS)
295 *new_uskey = ret_key;
296 else
297 HeapFree(GetProcessHeap(), 0, ret_key);
298 }
299
300 return ret;
301 }
302
303 /*************************************************************************
304 * SHRegDeleteEmptyUSKeyA [SHLWAPI.@]
305 *
306 * Delete an empty user-specific registry key.
307 *
308 * PARAMS
309 * hUSKey [I] Handle to an open registry key.
310 * pszValue [I] Empty key name.
311 * delRegFlags [I] Flag that specifies the base from which to delete
312 * the key.
313 *
314 * RETURNS
315 * Success: ERROR_SUCCESS
316 * Failure: Nonzero error code from winerror.h
317 */
318 LONG WINAPI SHRegDeleteEmptyUSKeyA(HUSKEY hUSKey, LPCSTR pszValue, SHREGDEL_FLAGS delRegFlags)
319 {
320 FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_a(pszValue), delRegFlags);
321 return ERROR_SUCCESS;
322 }
323
324 /*************************************************************************
325 * SHRegDeleteEmptyUSKeyW [SHLWAPI.@]
326 *
327 * See SHRegDeleteEmptyUSKeyA.
328 */
329 LONG WINAPI SHRegDeleteEmptyUSKeyW(HUSKEY hUSKey, LPCWSTR pszValue, SHREGDEL_FLAGS delRegFlags)
330 {
331 FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_w(pszValue), delRegFlags);
332 return ERROR_SUCCESS;
333 }
334
335 /*************************************************************************
336 * SHRegDeleteUSValueA [SHLWAPI.@]
337 *
338 * Delete a user-specific registry value.
339 *
340 * PARAMS
341 * hUSKey [I] Handle to an open registry key.
342 * pszValue [I] Specifies the value to delete.
343 * delRegFlags [I] Flag that specifies the base of the key from which to
344 * delete the value.
345 *
346 * RETURNS
347 * Success: ERROR_SUCCESS
348 * Failure: Nonzero error code from winerror.h
349 */
350 LONG WINAPI SHRegDeleteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, SHREGDEL_FLAGS delRegFlags)
351 {
352 FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_a(pszValue), delRegFlags);
353 return ERROR_SUCCESS;
354 }
355
356 /*************************************************************************
357 * SHRegDeleteUSValueW [SHLWAPI.@]
358 *
359 * See SHRegDeleteUSValueA.
360 */
361 LONG WINAPI SHRegDeleteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, SHREGDEL_FLAGS delRegFlags)
362 {
363 FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_w(pszValue), delRegFlags);
364 return ERROR_SUCCESS;
365 }
366
367 /*************************************************************************
368 * SHRegEnumUSValueA [SHLWAPI.@]
369 *
370 * Enumerate values of a specified registry key.
371 *
372 * PARAMS
373 * hUSKey [I] Handle to an open registry key.
374 * dwIndex [I] Index of the value to be retrieved.
375 * pszValueName [O] Buffer to receive the value name.
376 * pcchValueNameLen [I] Size of pszValueName in characters.
377 * pdwType [O] Receives data type of the value.
378 * pvData [O] Receives value data. May be NULL.
379 * pcbData [I/O] Size of pvData in bytes.
380 * enumRegFlags [I] Flag that specifies the base key under which to
381 * enumerate values.
382 *
383 * RETURNS
384 * Success: ERROR_SUCCESS
385 * Failure: Nonzero error code from winerror.h
386 */
387 LONG WINAPI SHRegEnumUSValueA(HUSKEY hUSKey, DWORD dwIndex, LPSTR pszValueName,
388 LPDWORD pcchValueNameLen, LPDWORD pdwType, LPVOID pvData,
389 LPDWORD pcbData, SHREGENUM_FLAGS enumRegFlags)
390 {
391 HKEY dokey;
392
393 TRACE("(%p, 0x%08x, %p, %p, %p, %p, %p, 0x%08x)\n", hUSKey, dwIndex,
394 pszValueName, pcchValueNameLen, pdwType, pvData, pcbData, enumRegFlags);
395
396 if (((enumRegFlags == SHREGENUM_HKCU) ||
397 (enumRegFlags == SHREGENUM_DEFAULT)) &&
398 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
399 return RegEnumValueA(dokey, dwIndex, pszValueName, pcchValueNameLen,
400 NULL, pdwType, pvData, pcbData);
401 }
402
403 if (((enumRegFlags == SHREGENUM_HKLM) ||
404 (enumRegFlags == SHREGENUM_DEFAULT)) &&
405 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
406 return RegEnumValueA(dokey, dwIndex, pszValueName, pcchValueNameLen,
407 NULL, pdwType, pvData, pcbData);
408 }
409 FIXME("no support for SHREGENUM_BOTH\n");
410 return ERROR_INVALID_FUNCTION;
411 }
412
413 /*************************************************************************
414 * SHRegEnumUSValueW [SHLWAPI.@]
415 *
416 * See SHRegEnumUSValueA.
417 */
418 LONG WINAPI SHRegEnumUSValueW(HUSKEY hUSKey, DWORD dwIndex, LPWSTR pszValueName,
419 LPDWORD pcchValueNameLen, LPDWORD pdwType, LPVOID pvData,
420 LPDWORD pcbData, SHREGENUM_FLAGS enumRegFlags)
421 {
422 HKEY dokey;
423
424 TRACE("(%p, 0x%08x, %p, %p, %p, %p, %p, 0x%08x)\n", hUSKey, dwIndex,
425 pszValueName, pcchValueNameLen, pdwType, pvData, pcbData, enumRegFlags);
426
427 if (((enumRegFlags == SHREGENUM_HKCU) ||
428 (enumRegFlags == SHREGENUM_DEFAULT)) &&
429 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
430 return RegEnumValueW(dokey, dwIndex, pszValueName, pcchValueNameLen,
431 NULL, pdwType, pvData, pcbData);
432 }
433
434 if (((enumRegFlags == SHREGENUM_HKLM) ||
435 (enumRegFlags == SHREGENUM_DEFAULT)) &&
436 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
437 return RegEnumValueW(dokey, dwIndex, pszValueName, pcchValueNameLen,
438 NULL, pdwType, pvData, pcbData);
439 }
440 FIXME("no support for SHREGENUM_BOTH\n");
441 return ERROR_INVALID_FUNCTION;
442 }
443
444 /*************************************************************************
445 * SHRegQueryUSValueA [SHLWAPI.@]
446 *
447 * Query a user-specific registry value.
448 *
449 * RETURNS
450 * Success: ERROR_SUCCESS
451 * Failure: An error code from RegQueryValueExA().
452 */
453 LONG WINAPI SHRegQueryUSValueA(
454 HUSKEY hUSKey, /* [I] Key to query */
455 LPCSTR pszValue, /* [I] Value name under hUSKey */
456 LPDWORD pdwType, /* [O] Destination for value type */
457 LPVOID pvData, /* [O] Destination for value data */
458 LPDWORD pcbData, /* [O] Destination for value length */
459 BOOL fIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */
460 LPVOID pvDefaultData, /* [I] Default data if pszValue does not exist */
461 DWORD dwDefaultDataSize) /* [I] Length of pvDefaultData */
462 {
463 LONG ret = ~ERROR_SUCCESS;
464 LONG i, maxmove;
465 HKEY dokey;
466 CHAR *src, *dst;
467
468 /* if user wants HKCU, and it exists, then try it */
469 if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
470 ret = RegQueryValueExA(dokey,
471 pszValue, 0, pdwType, pvData, pcbData);
472 TRACE("HKCU RegQueryValue returned %08x\n", ret);
473 }
474
475 /* if HKCU did not work and HKLM exists, then try it */
476 if ((ret != ERROR_SUCCESS) &&
477 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
478 ret = RegQueryValueExA(dokey,
479 pszValue, 0, pdwType, pvData, pcbData);
480 TRACE("HKLM RegQueryValue returned %08x\n", ret);
481 }
482
483 /* if neither worked, and default data exists, then use it */
484 if (ret != ERROR_SUCCESS) {
485 if (pvDefaultData && (dwDefaultDataSize != 0)) {
486 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
487 src = pvDefaultData;
488 dst = pvData;
489 for(i=0; i<maxmove; i++) *dst++ = *src++;
490 *pcbData = maxmove;
491 TRACE("setting default data\n");
492 ret = ERROR_SUCCESS;
493 }
494 }
495 return ret;
496 }
497
498
499 /*************************************************************************
500 * SHRegQueryUSValueW [SHLWAPI.@]
501 *
502 * See SHRegQueryUSValueA.
503 */
504 LONG WINAPI SHRegQueryUSValueW(
505 HUSKEY hUSKey,
506 LPCWSTR pszValue,
507 LPDWORD pdwType,
508 LPVOID pvData,
509 LPDWORD pcbData,
510 BOOL fIgnoreHKCU,
511 LPVOID pvDefaultData,
512 DWORD dwDefaultDataSize)
513 {
514 LONG ret = ~ERROR_SUCCESS;
515 LONG i, maxmove;
516 HKEY dokey;
517 CHAR *src, *dst;
518
519 /* if user wants HKCU, and it exists, then try it */
520 if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
521 ret = RegQueryValueExW(dokey,
522 pszValue, 0, pdwType, pvData, pcbData);
523 TRACE("HKCU RegQueryValue returned %08x\n", ret);
524 }
525
526 /* if HKCU did not work and HKLM exists, then try it */
527 if ((ret != ERROR_SUCCESS) &&
528 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
529 ret = RegQueryValueExW(dokey,
530 pszValue, 0, pdwType, pvData, pcbData);
531 TRACE("HKLM RegQueryValue returned %08x\n", ret);
532 }
533
534 /* if neither worked, and default data exists, then use it */
535 if (ret != ERROR_SUCCESS) {
536 if (pvDefaultData && (dwDefaultDataSize != 0)) {
537 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
538 src = pvDefaultData;
539 dst = pvData;
540 for(i=0; i<maxmove; i++) *dst++ = *src++;
541 *pcbData = maxmove;
542 TRACE("setting default data\n");
543 ret = ERROR_SUCCESS;
544 }
545 }
546 return ret;
547 }
548
549 /*************************************************************************
550 * SHRegGetUSValueA [SHLWAPI.@]
551 *
552 * Get a user-specific registry value.
553 *
554 * RETURNS
555 * Success: ERROR_SUCCESS
556 * Failure: An error code from SHRegOpenUSKeyA() or SHRegQueryUSValueA().
557 *
558 * NOTES
559 * This function opens pSubKey, queries the value, and then closes the key.
560 */
561 LONG WINAPI SHRegGetUSValueA(
562 LPCSTR pSubKey, /* [I] Key name to open */
563 LPCSTR pValue, /* [I] Value name to open */
564 LPDWORD pwType, /* [O] Destination for the type of the value */
565 LPVOID pvData, /* [O] Destination for the value */
566 LPDWORD pcbData, /* [I] Destination for the length of the value **/
567 BOOL flagIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */
568 LPVOID pDefaultData, /* [I] Default value if it doesn't exist */
569 DWORD wDefaultDataSize) /* [I] Length of pDefaultData */
570 {
571 HUSKEY myhuskey;
572 LONG ret;
573
574 if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
575 TRACE("key '%s', value '%s', datalen %d, %s\n",
576 debugstr_a(pSubKey), debugstr_a(pValue), *pcbData,
577 (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
578
579 ret = SHRegOpenUSKeyA(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
580 if (ret == ERROR_SUCCESS) {
581 ret = SHRegQueryUSValueA(myhuskey, pValue, pwType, pvData,
582 pcbData, flagIgnoreHKCU, pDefaultData,
583 wDefaultDataSize);
584 SHRegCloseUSKey(myhuskey);
585 }
586 return ret;
587 }
588
589 /*************************************************************************
590 * SHRegGetUSValueW [SHLWAPI.@]
591 *
592 * See SHRegGetUSValueA.
593 */
594 LONG WINAPI SHRegGetUSValueW(
595 LPCWSTR pSubKey,
596 LPCWSTR pValue,
597 LPDWORD pwType,
598 LPVOID pvData,
599 LPDWORD pcbData,
600 BOOL flagIgnoreHKCU,
601 LPVOID pDefaultData,
602 DWORD wDefaultDataSize)
603 {
604 HUSKEY myhuskey;
605 LONG ret;
606
607 if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
608 TRACE("key '%s', value '%s', datalen %d, %s\n",
609 debugstr_w(pSubKey), debugstr_w(pValue), *pcbData,
610 (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
611
612 ret = SHRegOpenUSKeyW(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
613 if (ret == ERROR_SUCCESS) {
614 ret = SHRegQueryUSValueW(myhuskey, pValue, pwType, pvData,
615 pcbData, flagIgnoreHKCU, pDefaultData,
616 wDefaultDataSize);
617 SHRegCloseUSKey(myhuskey);
618 }
619 return ret;
620 }
621
622 /*************************************************************************
623 * SHRegSetUSValueA [SHLWAPI.@]
624 *
625 * Set a user-specific registry value.
626 *
627 * PARAMS
628 * pszSubKey [I] Name of key to set the value in
629 * pszValue [I] Name of value under pszSubKey to set the value in
630 * dwType [I] Type of the value
631 * pvData [I] Data to set as the value
632 * cbData [I] length of pvData
633 * dwFlags [I] SHREGSET_ flags from "shlwapi.h"
634 *
635 * RETURNS
636 * Success: ERROR_SUCCESS
637 * Failure: An error code from SHRegOpenUSKeyA() or SHRegWriteUSValueA(), or
638 * ERROR_INVALID_FUNCTION if pvData is NULL.
639 *
640 * NOTES
641 * This function opens pszSubKey, sets the value, and then closes the key.
642 */
643 LONG WINAPI SHRegSetUSValueA(LPCSTR pszSubKey, LPCSTR pszValue, DWORD dwType,
644 LPVOID pvData, DWORD cbData, DWORD dwFlags)
645 {
646 BOOL ignoreHKCU = TRUE;
647 HUSKEY hkey;
648 LONG ret;
649
650 TRACE("(%s,%s,%d,%p,%d,0x%08x\n", debugstr_a(pszSubKey), debugstr_a(pszValue),
651 dwType, pvData, cbData, dwFlags);
652
653 if (!pvData)
654 return ERROR_INVALID_FUNCTION;
655
656 if (dwFlags & SHREGSET_HKCU || dwFlags & SHREGSET_FORCE_HKCU)
657 ignoreHKCU = FALSE;
658
659 ret = SHRegOpenUSKeyA(pszSubKey, KEY_ALL_ACCESS, 0, &hkey, ignoreHKCU);
660 if (ret == ERROR_SUCCESS)
661 {
662 ret = SHRegWriteUSValueA(hkey, pszValue, dwType, pvData, cbData, dwFlags);
663 SHRegCloseUSKey(hkey);
664 }
665 return ret;
666 }
667
668 /*************************************************************************
669 * SHRegSetUSValueW [SHLWAPI.@]
670 *
671 * See SHRegSetUSValueA.
672 */
673 LONG WINAPI SHRegSetUSValueW(LPCWSTR pszSubKey, LPCWSTR pszValue, DWORD dwType,
674 LPVOID pvData, DWORD cbData, DWORD dwFlags)
675 {
676 BOOL ignoreHKCU = TRUE;
677 HUSKEY hkey;
678 LONG ret;
679
680 TRACE("(%s,%s,%d,%p,%d,0x%08x\n", debugstr_w(pszSubKey), debugstr_w(pszValue),
681 dwType, pvData, cbData, dwFlags);
682
683 if (!pvData)
684 return ERROR_INVALID_FUNCTION;
685
686 if (dwFlags & SHREGSET_HKCU || dwFlags & SHREGSET_FORCE_HKCU)
687 ignoreHKCU = FALSE;
688
689 ret = SHRegOpenUSKeyW(pszSubKey, KEY_ALL_ACCESS, 0, &hkey, ignoreHKCU);
690 if (ret == ERROR_SUCCESS)
691 {
692 ret = SHRegWriteUSValueW(hkey, pszValue, dwType, pvData, cbData, dwFlags);
693 SHRegCloseUSKey(hkey);
694 }
695 return ret;
696 }
697
698 /*************************************************************************
699 * SHRegGetBoolUSValueA [SHLWAPI.@]
700 *
701 * Get a user-specific registry boolean value.
702 *
703 * RETURNS
704 * Success: ERROR_SUCCESS
705 * Failure: An error code from SHRegOpenUSKeyA() or SHRegQueryUSValueA().
706 *
707 * NOTES
708 * This function opens pszSubKey, queries the value, and then closes the key.
709 *
710 * Boolean values are one of the following:
711 * True: YES,TRUE,non-zero
712 * False: NO,FALSE,0
713 */
714 BOOL WINAPI SHRegGetBoolUSValueA(
715 LPCSTR pszSubKey, /* [I] Key name to open */
716 LPCSTR pszValue, /* [I] Value name to open */
717 BOOL fIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */
718 BOOL fDefault) /* [I] Default value to use if pszValue is not present */
719 {
720 DWORD type, datalen, work;
721 BOOL ret = fDefault;
722 CHAR data[10];
723
724 TRACE("key '%s', value '%s', %s\n",
725 debugstr_a(pszSubKey), debugstr_a(pszValue),
726 (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
727
728 datalen = sizeof(data)-1;
729 if (!SHRegGetUSValueA( pszSubKey, pszValue, &type,
730 data, &datalen,
731 fIgnoreHKCU, 0, 0)) {
732 /* process returned data via type into bool */
733 switch (type) {
734 case REG_SZ:
735 data[9] = '\0'; /* set end of string */
736 if (lstrcmpiA(data, "YES") == 0) ret = TRUE;
737 if (lstrcmpiA(data, "TRUE") == 0) ret = TRUE;
738 if (lstrcmpiA(data, "NO") == 0) ret = FALSE;
739 if (lstrcmpiA(data, "FALSE") == 0) ret = FALSE;
740 break;
741 case REG_DWORD:
742 work = *(LPDWORD)data;
743 ret = (work != 0);
744 break;
745 case REG_BINARY:
746 if (datalen == 1) {
747 ret = (data[0] != '\0');
748 break;
749 }
750 default:
751 FIXME("Unsupported registry data type %d\n", type);
752 ret = FALSE;
753 }
754 TRACE("got value (type=%d), returning <%s>\n", type,
755 (ret) ? "TRUE" : "FALSE");
756 }
757 else {
758 ret = fDefault;
759 TRACE("returning default data <%s>\n",
760 (ret) ? "TRUE" : "FALSE");
761 }
762 return ret;
763 }
764
765 /*************************************************************************
766 * SHRegGetBoolUSValueW [SHLWAPI.@]
767 *
768 * See SHRegGetBoolUSValueA.
769 */
770 BOOL WINAPI SHRegGetBoolUSValueW(
771 LPCWSTR pszSubKey,
772 LPCWSTR pszValue,
773 BOOL fIgnoreHKCU,
774 BOOL fDefault)
775 {
776 static const WCHAR wYES[]= {'Y','E','S','\0'};
777 static const WCHAR wTRUE[]= {'T','R','U','E','\0'};
778 static const WCHAR wNO[]= {'N','O','\0'};
779 static const WCHAR wFALSE[]={'F','A','L','S','E','\0'};
780 DWORD type, datalen, work;
781 BOOL ret = fDefault;
782 WCHAR data[10];
783
784 TRACE("key '%s', value '%s', %s\n",
785 debugstr_w(pszSubKey), debugstr_w(pszValue),
786 (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
787
788 datalen = (sizeof(data)-1) * sizeof(WCHAR);
789 if (!SHRegGetUSValueW( pszSubKey, pszValue, &type,
790 data, &datalen,
791 fIgnoreHKCU, 0, 0)) {
792 /* process returned data via type into bool */
793 switch (type) {
794 case REG_SZ:
795 data[9] = '\0'; /* set end of string */
796 if (lstrcmpiW(data, wYES)==0 || lstrcmpiW(data, wTRUE)==0)
797 ret = TRUE;
798 else if (lstrcmpiW(data, wNO)==0 || lstrcmpiW(data, wFALSE)==0)
799 ret = FALSE;
800 break;
801 case REG_DWORD:
802 work = *(LPDWORD)data;
803 ret = (work != 0);
804 break;
805 case REG_BINARY:
806 if (datalen == 1) {
807 ret = (data[0] != '\0');
808 break;
809 }
810 default:
811 FIXME("Unsupported registry data type %d\n", type);
812 ret = FALSE;
813 }
814 TRACE("got value (type=%d), returning <%s>\n", type,
815 (ret) ? "TRUE" : "FALSE");
816 }
817 else {
818 ret = fDefault;
819 TRACE("returning default data <%s>\n",
820 (ret) ? "TRUE" : "FALSE");
821 }
822 return ret;
823 }
824
825 /*************************************************************************
826 * SHRegQueryInfoUSKeyA [SHLWAPI.@]
827 *
828 * Get information about a user-specific registry key.
829 *
830 * RETURNS
831 * Success: ERROR_SUCCESS
832 * Failure: An error code from RegQueryInfoKeyA().
833 */
834 LONG WINAPI SHRegQueryInfoUSKeyA(
835 HUSKEY hUSKey, /* [I] Key to query */
836 LPDWORD pcSubKeys, /* [O] Destination for number of sub keys */
837 LPDWORD pcchMaxSubKeyLen, /* [O] Destination for the length of the biggest sub key name */
838 LPDWORD pcValues, /* [O] Destination for number of values */
839 LPDWORD pcchMaxValueNameLen,/* [O] Destination for the length of the biggest value */
840 SHREGENUM_FLAGS enumRegFlags) /* [in] SHREGENUM_ flags from "shlwapi.h" */
841 {
842 HKEY dokey;
843 LONG ret;
844
845 TRACE("(%p,%p,%p,%p,%p,%d)\n",
846 hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
847 pcchMaxValueNameLen,enumRegFlags);
848
849 /* if user wants HKCU, and it exists, then try it */
850 if (((enumRegFlags == SHREGENUM_HKCU) ||
851 (enumRegFlags == SHREGENUM_DEFAULT)) &&
852 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
853 ret = RegQueryInfoKeyA(dokey, 0, 0, 0,
854 pcSubKeys, pcchMaxSubKeyLen, 0,
855 pcValues, pcchMaxValueNameLen, 0, 0, 0);
856 if ((ret == ERROR_SUCCESS) ||
857 (enumRegFlags == SHREGENUM_HKCU))
858 return ret;
859 }
860 if (((enumRegFlags == SHREGENUM_HKLM) ||
861 (enumRegFlags == SHREGENUM_DEFAULT)) &&
862 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
863 return RegQueryInfoKeyA(dokey, 0, 0, 0,
864 pcSubKeys, pcchMaxSubKeyLen, 0,
865 pcValues, pcchMaxValueNameLen, 0, 0, 0);
866 }
867 return ERROR_INVALID_FUNCTION;
868 }
869
870 /*************************************************************************
871 * SHRegQueryInfoUSKeyW [SHLWAPI.@]
872 *
873 * See SHRegQueryInfoUSKeyA.
874 */
875 LONG WINAPI SHRegQueryInfoUSKeyW(
876 HUSKEY hUSKey,
877 LPDWORD pcSubKeys,
878 LPDWORD pcchMaxSubKeyLen,
879 LPDWORD pcValues,
880 LPDWORD pcchMaxValueNameLen,
881 SHREGENUM_FLAGS enumRegFlags)
882 {
883 HKEY dokey;
884 LONG ret;
885
886 TRACE("(%p,%p,%p,%p,%p,%d)\n",
887 hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
888 pcchMaxValueNameLen,enumRegFlags);
889
890 /* if user wants HKCU, and it exists, then try it */
891 if (((enumRegFlags == SHREGENUM_HKCU) ||
892 (enumRegFlags == SHREGENUM_DEFAULT)) &&
893 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
894 ret = RegQueryInfoKeyW(dokey, 0, 0, 0,
895 pcSubKeys, pcchMaxSubKeyLen, 0,
896 pcValues, pcchMaxValueNameLen, 0, 0, 0);
897 if ((ret == ERROR_SUCCESS) ||
898 (enumRegFlags == SHREGENUM_HKCU))
899 return ret;
900 }
901 if (((enumRegFlags == SHREGENUM_HKLM) ||
902 (enumRegFlags == SHREGENUM_DEFAULT)) &&
903 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
904 return RegQueryInfoKeyW(dokey, 0, 0, 0,
905 pcSubKeys, pcchMaxSubKeyLen, 0,
906 pcValues, pcchMaxValueNameLen, 0, 0, 0);
907 }
908 return ERROR_INVALID_FUNCTION;
909 }
910
911 /*************************************************************************
912 * SHRegEnumUSKeyA [SHLWAPI.@]
913 *
914 * Enumerate a user-specific registry key.
915 *
916 * RETURNS
917 * Success: ERROR_SUCCESS
918 * Failure: An error code from RegEnumKeyExA().
919 */
920 LONG WINAPI SHRegEnumUSKeyA(
921 HUSKEY hUSKey, /* [in] Key to enumerate */
922 DWORD dwIndex, /* [in] Index within hUSKey */
923 LPSTR pszName, /* [out] Name of the enumerated value */
924 LPDWORD pcchValueNameLen, /* [in/out] Length of pszName */
925 SHREGENUM_FLAGS enumRegFlags) /* [in] SHREGENUM_ flags from "shlwapi.h" */
926 {
927 HKEY dokey;
928
929 TRACE("(%p,%d,%p,%p(%d),%d)\n",
930 hUSKey, dwIndex, pszName, pcchValueNameLen,
931 *pcchValueNameLen, enumRegFlags);
932
933 if (((enumRegFlags == SHREGENUM_HKCU) ||
934 (enumRegFlags == SHREGENUM_DEFAULT)) &&
935 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
936 return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
937 0, 0, 0, 0);
938 }
939
940 if (((enumRegFlags == SHREGENUM_HKLM) ||
941 (enumRegFlags == SHREGENUM_DEFAULT)) &&
942 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
943 return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
944 0, 0, 0, 0);
945 }
946 FIXME("no support for SHREGENUM_BOTH\n");
947 return ERROR_INVALID_FUNCTION;
948 }
949
950 /*************************************************************************
951 * SHRegEnumUSKeyW [SHLWAPI.@]
952 *
953 * See SHRegEnumUSKeyA.
954 */
955 LONG WINAPI SHRegEnumUSKeyW(
956 HUSKEY hUSKey,
957 DWORD dwIndex,
958 LPWSTR pszName,
959 LPDWORD pcchValueNameLen,
960 SHREGENUM_FLAGS enumRegFlags)
961 {
962 HKEY dokey;
963
964 TRACE("(%p,%d,%p,%p(%d),%d)\n",
965 hUSKey, dwIndex, pszName, pcchValueNameLen,
966 *pcchValueNameLen, enumRegFlags);
967
968 if (((enumRegFlags == SHREGENUM_HKCU) ||
969 (enumRegFlags == SHREGENUM_DEFAULT)) &&
970 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
971 return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
972 0, 0, 0, 0);
973 }
974
975 if (((enumRegFlags == SHREGENUM_HKLM) ||
976 (enumRegFlags == SHREGENUM_DEFAULT)) &&
977 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
978 return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
979 0, 0, 0, 0);
980 }
981 FIXME("no support for SHREGENUM_BOTH\n");
982 return ERROR_INVALID_FUNCTION;
983 }
984
985
986 /*************************************************************************
987 * SHRegWriteUSValueA [SHLWAPI.@]
988 *
989 * Write a user-specific registry value.
990 *
991 * PARAMS
992 * hUSKey [I] Key to write the value to
993 * pszValue [I] Name of value under hUSKey to write the value as
994 * dwType [I] Type of the value
995 * pvData [I] Data to set as the value
996 * cbData [I] length of pvData
997 * dwFlags [I] SHREGSET_ flags from "shlwapi.h"
998 *
999 * RETURNS
1000 * Success: ERROR_SUCCESS.
1001 * Failure: ERROR_INVALID_PARAMETER, if any parameter is invalid, otherwise
1002 * an error code from RegSetValueExA().
1003 *
1004 * NOTES
1005 * dwFlags must have at least SHREGSET_FORCE_HKCU or SHREGSET_FORCE_HKLM set.
1006 */
1007 LONG WINAPI SHRegWriteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, DWORD dwType,
1008 LPVOID pvData, DWORD cbData, DWORD dwFlags)
1009 {
1010 WCHAR szValue[MAX_PATH];
1011
1012 if (pszValue)
1013 MultiByteToWideChar(CP_ACP, 0, pszValue, -1, szValue, MAX_PATH);
1014
1015 return SHRegWriteUSValueW(hUSKey, pszValue ? szValue : NULL, dwType,
1016 pvData, cbData, dwFlags);
1017 }
1018
1019 /*************************************************************************
1020 * SHRegWriteUSValueW [SHLWAPI.@]
1021 *
1022 * See SHRegWriteUSValueA.
1023 */
1024 LONG WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, DWORD dwType,
1025 LPVOID pvData, DWORD cbData, DWORD dwFlags)
1026 {
1027 DWORD dummy;
1028 LPSHUSKEY hKey = hUSKey;
1029 LONG ret = ERROR_SUCCESS;
1030
1031 TRACE("(%p,%s,%d,%p,%d,%d)\n", hUSKey, debugstr_w(pszValue),
1032 dwType, pvData, cbData, dwFlags);
1033
1034 if (!hUSKey || IsBadWritePtr(hUSKey, sizeof(SHUSKEY)) ||
1035 !(dwFlags & (SHREGSET_FORCE_HKCU|SHREGSET_FORCE_HKLM)))
1036 return ERROR_INVALID_PARAMETER;
1037
1038 if (dwFlags & (SHREGSET_FORCE_HKCU|SHREGSET_HKCU))
1039 {
1040 if (!hKey->HKCUkey)
1041 {
1042 /* Create the key */
1043 ret = RegCreateKeyW(hKey->HKCUstart, hKey->lpszPath, &hKey->HKCUkey);
1044 TRACE("Creating HKCU key, ret = %d\n", ret);
1045 if (ret && (dwFlags & (SHREGSET_FORCE_HKCU)))
1046 {
1047 hKey->HKCUkey = 0;
1048 return ret;
1049 }
1050 }
1051
1052 if (!ret)
1053 {
1054 if ((dwFlags & SHREGSET_FORCE_HKCU) ||
1055 RegQueryValueExW(hKey->HKCUkey, pszValue, NULL, NULL, NULL, &dummy))
1056 {
1057 /* Doesn't exist or we are forcing: Write value */
1058 ret = RegSetValueExW(hKey->HKCUkey, pszValue, 0, dwType, pvData, cbData);
1059 TRACE("Writing HKCU value, ret = %d\n", ret);
1060 }
1061 }
1062 }
1063
1064 if (dwFlags & (SHREGSET_FORCE_HKLM|SHREGSET_HKLM))
1065 {
1066 if (!hKey->HKLMkey)
1067 {
1068 /* Create the key */
1069 ret = RegCreateKeyW(hKey->HKLMstart, hKey->lpszPath, &hKey->HKLMkey);
1070 TRACE("Creating HKLM key, ret = %d\n", ret);
1071 if (ret && (dwFlags & (SHREGSET_FORCE_HKLM)))
1072 {
1073 hKey->HKLMkey = 0;
1074 return ret;
1075 }
1076 }
1077
1078 if (!ret)
1079 {
1080 if ((dwFlags & SHREGSET_FORCE_HKLM) ||
1081 RegQueryValueExW(hKey->HKLMkey, pszValue, NULL, NULL, NULL, &dummy))
1082 {
1083 /* Doesn't exist or we are forcing: Write value */
1084 ret = RegSetValueExW(hKey->HKLMkey, pszValue, 0, dwType, pvData, cbData);
1085 TRACE("Writing HKLM value, ret = %d\n", ret);
1086 }
1087 }
1088 }
1089
1090 return ret;
1091 }
1092
1093 /*************************************************************************
1094 * SHRegGetPathA [SHLWAPI.@]
1095 *
1096 * Get a path from the registry.
1097 *
1098 * PARAMS
1099 * hKey [I] Handle to registry key
1100 * lpszSubKey [I] Name of sub key containing path to get
1101 * lpszValue [I] Name of value containing path to get
1102 * lpszPath [O] Buffer for returned path
1103 * dwFlags [I] Reserved
1104 *
1105 * RETURNS
1106 * Success: ERROR_SUCCESS. lpszPath contains the path.
1107 * Failure: An error code from RegOpenKeyExA() or SHQueryValueExA().
1108 */
1109 DWORD WINAPI SHRegGetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
1110 LPSTR lpszPath, DWORD dwFlags)
1111 {
1112 DWORD dwSize = MAX_PATH;
1113
1114 TRACE("(hkey=%p,%s,%s,%p,%d)\n", hKey, debugstr_a(lpszSubKey),
1115 debugstr_a(lpszValue), lpszPath, dwFlags);
1116
1117 return SHGetValueA(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize);
1118 }
1119
1120 /*************************************************************************
1121 * SHRegGetPathW [SHLWAPI.@]
1122 *
1123 * See SHRegGetPathA.
1124 */
1125 DWORD WINAPI SHRegGetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
1126 LPWSTR lpszPath, DWORD dwFlags)
1127 {
1128 DWORD dwSize = MAX_PATH;
1129
1130 TRACE("(hkey=%p,%s,%s,%p,%d)\n", hKey, debugstr_w(lpszSubKey),
1131 debugstr_w(lpszValue), lpszPath, dwFlags);
1132
1133 return SHGetValueW(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize);
1134 }
1135
1136
1137 /*************************************************************************
1138 * SHRegSetPathA [SHLWAPI.@]
1139 *
1140 * Write a path to the registry.
1141 *
1142 * PARAMS
1143 * hKey [I] Handle to registry key
1144 * lpszSubKey [I] Name of sub key containing path to set
1145 * lpszValue [I] Name of value containing path to set
1146 * lpszPath [O] Path to write
1147 * dwFlags [I] Reserved, must be 0.
1148 *
1149 * RETURNS
1150 * Success: ERROR_SUCCESS.
1151 * Failure: An error code from SHSetValueA().
1152 */
1153 DWORD WINAPI SHRegSetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
1154 LPCSTR lpszPath, DWORD dwFlags)
1155 {
1156 char szBuff[MAX_PATH];
1157
1158 FIXME("(hkey=%p,%s,%s,%p,%d) - semi-stub\n",hKey, debugstr_a(lpszSubKey),
1159 debugstr_a(lpszValue), lpszPath, dwFlags);
1160
1161 lstrcpyA(szBuff, lpszPath);
1162
1163 /* FIXME: PathUnExpandEnvStringsA(szBuff); */
1164
1165 return SHSetValueA(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
1166 lstrlenA(szBuff));
1167 }
1168
1169 /*************************************************************************
1170 * SHRegSetPathW [SHLWAPI.@]
1171 *
1172 * See SHRegSetPathA.
1173 */
1174 DWORD WINAPI SHRegSetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
1175 LPCWSTR lpszPath, DWORD dwFlags)
1176 {
1177 WCHAR szBuff[MAX_PATH];
1178
1179 FIXME("(hkey=%p,%s,%s,%p,%d) - semi-stub\n",hKey, debugstr_w(lpszSubKey),
1180 debugstr_w(lpszValue), lpszPath, dwFlags);
1181
1182 lstrcpyW(szBuff, lpszPath);
1183
1184 /* FIXME: PathUnExpandEnvStringsW(szBuff); */
1185
1186 return SHSetValueW(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
1187 lstrlenW(szBuff));
1188 }
1189
1190 /*************************************************************************
1191 * SHGetValueA [SHLWAPI.@]
1192 *
1193 * Get a value from the registry.
1194 *
1195 * PARAMS
1196 * hKey [I] Handle to registry key
1197 * lpszSubKey [I] Name of sub key containing value to get
1198 * lpszValue [I] Name of value to get
1199 * pwType [O] Pointer to the values type
1200 * pvData [O] Pointer to the values data
1201 * pcbData [O] Pointer to the values size
1202 *
1203 * RETURNS
1204 * Success: ERROR_SUCCESS. Output parameters contain the details read.
1205 * Failure: An error code from RegOpenKeyExA() or SHQueryValueExA().
1206 */
1207 DWORD WINAPI SHGetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
1208 LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
1209 {
1210 DWORD dwRet = 0;
1211 HKEY hSubKey = 0;
1212
1213 TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_a(lpszSubKey),
1214 debugstr_a(lpszValue), pwType, pvData, pcbData);
1215
1216 /* lpszSubKey can be 0. In this case the value is taken from the
1217 * current key.
1218 */
1219 if(lpszSubKey)
1220 dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
1221
1222 if (! dwRet)
1223 {
1224 /* SHQueryValueEx expands Environment strings */
1225 dwRet = SHQueryValueExA(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData);
1226 if (hSubKey) RegCloseKey(hSubKey);
1227 }
1228 return dwRet;
1229 }
1230
1231 /*************************************************************************
1232 * SHGetValueW [SHLWAPI.@]
1233 *
1234 * See SHGetValueA.
1235 */
1236 DWORD WINAPI SHGetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
1237 LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
1238 {
1239 DWORD dwRet = 0;
1240 HKEY hSubKey = 0;
1241
1242 TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_w(lpszSubKey),
1243 debugstr_w(lpszValue), pwType, pvData, pcbData);
1244
1245 if(lpszSubKey)
1246 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
1247
1248 if (! dwRet)
1249 {
1250 dwRet = SHQueryValueExW(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData);
1251 if (hSubKey) RegCloseKey(hSubKey);
1252 }
1253 return dwRet;
1254 }
1255
1256 /*************************************************************************
1257 * SHSetValueA [SHLWAPI.@]
1258 *
1259 * Set a value in the registry.
1260 *
1261 * PARAMS
1262 * hKey [I] Handle to registry key
1263 * lpszSubKey [I] Name of sub key under hKey
1264 * lpszValue [I] Name of value to set
1265 * dwType [I] Type of the value
1266 * pvData [I] Data of the value
1267 * cbData [I] Size of the value
1268 *
1269 * RETURNS
1270 * Success: ERROR_SUCCESS. The value is set with the data given.
1271 * Failure: An error code from RegCreateKeyExA() or RegSetValueExA()
1272 *
1273 * NOTES
1274 * If lpszSubKey does not exist, it is created before the value is set. If
1275 * lpszSubKey is NULL or an empty string, then the value is added directly
1276 * to hKey instead.
1277 */
1278 DWORD WINAPI SHSetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
1279 DWORD dwType, LPCVOID pvData, DWORD cbData)
1280 {
1281 DWORD dwRet = ERROR_SUCCESS, dwDummy;
1282 HKEY hSubKey;
1283
1284 TRACE("(hkey=%p,%s,%s,%d,%p,%d)\n", hKey, debugstr_a(lpszSubKey),
1285 debugstr_a(lpszValue), dwType, pvData, cbData);
1286
1287 if (lpszSubKey && *lpszSubKey)
1288 dwRet = RegCreateKeyExA(hKey, lpszSubKey, 0, NULL,
1289 0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
1290 else
1291 hSubKey = hKey;
1292 if (!dwRet)
1293 {
1294 dwRet = RegSetValueExA(hSubKey, lpszValue, 0, dwType, pvData, cbData);
1295 if (hSubKey != hKey)
1296 RegCloseKey(hSubKey);
1297 }
1298 return dwRet;
1299 }
1300
1301 /*************************************************************************
1302 * SHSetValueW [SHLWAPI.@]
1303 *
1304 * See SHSetValueA.
1305 */
1306 DWORD WINAPI SHSetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
1307 DWORD dwType, LPCVOID pvData, DWORD cbData)
1308 {
1309 DWORD dwRet = ERROR_SUCCESS, dwDummy;
1310 HKEY hSubKey;
1311
1312 TRACE("(hkey=%p,%s,%s,%d,%p,%d)\n", hKey, debugstr_w(lpszSubKey),
1313 debugstr_w(lpszValue), dwType, pvData, cbData);
1314
1315 if (lpszSubKey && *lpszSubKey)
1316 dwRet = RegCreateKeyExW(hKey, lpszSubKey, 0, NULL,
1317 0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
1318 else
1319 hSubKey = hKey;
1320 if (!dwRet)
1321 {
1322 dwRet = RegSetValueExW(hSubKey, lpszValue, 0, dwType, pvData, cbData);
1323 if (hSubKey != hKey)
1324 RegCloseKey(hSubKey);
1325 }
1326 return dwRet;
1327 }
1328
1329 /*************************************************************************
1330 * SHQueryInfoKeyA [SHLWAPI.@]
1331 *
1332 * Get information about a registry key. See RegQueryInfoKeyA().
1333 *
1334 * RETURNS
1335 * The result of calling RegQueryInfoKeyA().
1336 */
1337 LONG WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
1338 LPDWORD pwValues, LPDWORD pwValueMax)
1339 {
1340 TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
1341 pwValues, pwValueMax);
1342 return RegQueryInfoKeyA(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
1343 NULL, pwValues, pwValueMax, NULL, NULL, NULL);
1344 }
1345
1346 /*************************************************************************
1347 * SHQueryInfoKeyW [SHLWAPI.@]
1348 *
1349 * See SHQueryInfoKeyA.
1350 */
1351 LONG WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
1352 LPDWORD pwValues, LPDWORD pwValueMax)
1353 {
1354 TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
1355 pwValues, pwValueMax);
1356 return RegQueryInfoKeyW(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
1357 NULL, pwValues, pwValueMax, NULL, NULL, NULL);
1358 }
1359
1360 /*************************************************************************
1361 * SHQueryValueExA [SHLWAPI.@]
1362 *
1363 * Get a value from the registry, expanding environment variable strings.
1364 *
1365 * PARAMS
1366 * hKey [I] Handle to registry key
1367 * lpszValue [I] Name of value to query
1368 * lpReserved [O] Reserved for future use; must be NULL
1369 * pwType [O] Optional pointer updated with the values type
1370 * pvData [O] Optional pointer updated with the values data
1371 * pcbData [O] Optional pointer updated with the values size
1372 *
1373 * RETURNS
1374 * Success: ERROR_SUCCESS. Any non NULL output parameters are updated with
1375 * information about the value.
1376 * Failure: ERROR_OUTOFMEMORY if memory allocation fails, or the type of the
1377 * data is REG_EXPAND_SZ and pcbData is NULL. Otherwise an error
1378 * code from RegQueryValueExA() or ExpandEnvironmentStringsA().
1379 *
1380 * NOTES
1381 * Either pwType, pvData or pcbData may be NULL if the caller doesn't want
1382 * the type, data or size information for the value.
1383 *
1384 * If the type of the data is REG_EXPAND_SZ, it is expanded to REG_SZ. The
1385 * value returned will be truncated if it is of type REG_SZ and bigger than
1386 * the buffer given to store it.
1387 *
1388 * REG_EXPAND_SZ:
1389 * case-1: the unexpanded string is smaller than the expanded one
1390 * subcase-1: the buffer is too small to hold the unexpanded string:
1391 * function fails and returns the size of the unexpanded string.
1392 *
1393 * subcase-2: buffer is too small to hold the expanded string:
1394 * the function return success (!!) and the result is truncated
1395 * *** This is clearly an error in the native implementation. ***
1396 *
1397 * case-2: the unexpanded string is bigger than the expanded one
1398 * The buffer must have enough space to hold the unexpanded
1399 * string even if the result is smaller.
1400 *
1401 */
1402 DWORD WINAPI SHQueryValueExA( HKEY hKey, LPCSTR lpszValue,
1403 LPDWORD lpReserved, LPDWORD pwType,
1404 LPVOID pvData, LPDWORD pcbData)
1405 {
1406 DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen;
1407
1408 TRACE("(hkey=%p,%s,%p,%p,%p,%p=%d)\n", hKey, debugstr_a(lpszValue),
1409 lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1410
1411 if (pcbData) dwUnExpDataLen = *pcbData;
1412
1413 dwRet = RegQueryValueExA(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen);
1414
1415 if (pcbData && (dwType == REG_EXPAND_SZ))
1416 {
1417 DWORD nBytesToAlloc;
1418
1419 /* Expand type REG_EXPAND_SZ into REG_SZ */
1420 LPSTR szData;
1421
1422 /* If the caller didn't supply a buffer or the buffer is too small we have
1423 * to allocate our own
1424 */
1425 if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
1426 {
1427 char cNull = '\0';
1428 nBytesToAlloc = dwUnExpDataLen;
1429
1430 szData = LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc);
1431 RegQueryValueExA (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
1432 dwExpDataLen = ExpandEnvironmentStringsA(szData, &cNull, 1);
1433 dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1434 LocalFree(szData);
1435 }
1436 else
1437 {
1438 nBytesToAlloc = (lstrlenA(pvData)+1) * sizeof (CHAR);
1439 szData = LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc);
1440 lstrcpyA(szData, pvData);
1441 dwExpDataLen = ExpandEnvironmentStringsA(szData, pvData, *pcbData / sizeof(CHAR));
1442 if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
1443 dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1444 LocalFree(szData);
1445 }
1446 }
1447
1448 /* Update the type and data size if the caller wanted them */
1449 if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ;
1450 if ( pwType ) *pwType = dwType;
1451 if ( pcbData ) *pcbData = dwUnExpDataLen;
1452 return dwRet;
1453 }
1454
1455
1456 /*************************************************************************
1457 * SHQueryValueExW [SHLWAPI.@]
1458 *
1459 * See SHQueryValueExA.
1460 */
1461 DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue,
1462 LPDWORD lpReserved, LPDWORD pwType,
1463 LPVOID pvData, LPDWORD pcbData)
1464 {
1465 DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen;
1466
1467 TRACE("(hkey=%p,%s,%p,%p,%p,%p=%d)\n", hKey, debugstr_w(lpszValue),
1468 lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1469
1470 if (pcbData) dwUnExpDataLen = *pcbData;
1471
1472 dwRet = RegQueryValueExW(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen);
1473 if (dwRet!=ERROR_SUCCESS && dwRet!=ERROR_MORE_DATA)
1474 return dwRet;
1475
1476 if (pcbData && (dwType == REG_EXPAND_SZ))
1477 {
1478 DWORD nBytesToAlloc;
1479
1480 /* Expand type REG_EXPAND_SZ into REG_SZ */
1481 LPWSTR szData;
1482
1483 /* If the caller didn't supply a buffer or the buffer is too small we have
1484 * to allocate our own
1485 */
1486 if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
1487 {
1488 WCHAR cNull = '\0';
1489 nBytesToAlloc = dwUnExpDataLen;
1490
1491 szData = LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc);
1492 RegQueryValueExW (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
1493 dwExpDataLen = ExpandEnvironmentStringsW(szData, &cNull, 1);
1494 dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1495 LocalFree(szData);
1496 }
1497 else
1498 {
1499 nBytesToAlloc = (lstrlenW(pvData) + 1) * sizeof(WCHAR);
1500 szData = LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc);
1501 lstrcpyW(szData, pvData);
1502 dwExpDataLen = ExpandEnvironmentStringsW(szData, pvData, *pcbData/sizeof(WCHAR) );
1503 if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
1504 dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1505 LocalFree(szData);
1506 }
1507 }
1508
1509 /* Update the type and data size if the caller wanted them */
1510 if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ;
1511 if ( pwType ) *pwType = dwType;
1512 if ( pcbData ) *pcbData = dwUnExpDataLen;
1513 return dwRet;
1514 }
1515
1516 /*************************************************************************
1517 * SHDeleteKeyA [SHLWAPI.@]
1518 *
1519 * Delete a registry key and any sub keys/values present
1520 *
1521 * This function forwards to the unicode version directly, to avoid
1522 * handling subkeys that are not representable in ASCII.
1523 *
1524 * PARAMS
1525 * hKey [I] Handle to registry key
1526 * lpszSubKey [I] Name of sub key to delete
1527 *
1528 * RETURNS
1529 * Success: ERROR_SUCCESS. The key is deleted.
1530 * Failure: An error code from RegOpenKeyExA(), RegQueryInfoKeyA(),
1531 * RegEnumKeyExA() or RegDeleteKeyA().
1532 */
1533 DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey)
1534 {
1535 WCHAR subkeyW[MAX_PATH];
1536
1537 MultiByteToWideChar (CP_ACP, 0, lpszSubKey, -1, subkeyW, sizeof(subkeyW)/sizeof(WCHAR));
1538 return SHDeleteKeyW(hKey, subkeyW);
1539 }
1540
1541 /*************************************************************************
1542 * SHDeleteKeyW [SHLWAPI.@]
1543 *
1544 * See SHDeleteKeyA.
1545 */
1546 DWORD WINAPI SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1547 {
1548 DWORD dwRet, dwMaxSubkeyLen = 0, dwSize;
1549 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1550 HKEY hSubKey = 0;
1551
1552 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1553
1554 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1555 if(!dwRet)
1556 {
1557 /* Find the maximum subkey length so that we can allocate a buffer */
1558 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
1559 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1560 if(!dwRet)
1561 {
1562 dwMaxSubkeyLen++;
1563 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1564 /* Name too big: alloc a buffer for it */
1565 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1566
1567 if(!lpszName)
1568 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1569 else
1570 {
1571 while (dwRet == ERROR_SUCCESS)
1572 {
1573 dwSize = dwMaxSubkeyLen;
1574 dwRet = RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1575 if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA)
1576 dwRet = SHDeleteKeyW(hSubKey, lpszName);
1577 }
1578 if (dwRet == ERROR_NO_MORE_ITEMS)
1579 dwRet = ERROR_SUCCESS;
1580
1581 if (lpszName != szNameBuf)
1582 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1583 }
1584 }
1585
1586 RegCloseKey(hSubKey);
1587 if(!dwRet)
1588 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1589 }
1590 return dwRet;
1591 }
1592
1593 /*************************************************************************
1594 * SHDeleteEmptyKeyA [SHLWAPI.@]
1595 *
1596 * Delete a registry key with no sub keys.
1597 *
1598 * PARAMS
1599 * hKey [I] Handle to registry key
1600 * lpszSubKey [I] Name of sub key to delete
1601 *
1602 * RETURNS
1603 * Success: ERROR_SUCCESS. The key is deleted.
1604 * Failure: If the key is not empty, returns ERROR_KEY_HAS_CHILDREN. Otherwise
1605 * returns an error code from RegOpenKeyExA(), RegQueryInfoKeyA() or
1606 * RegDeleteKeyA().
1607 */
1608 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hKey, LPCSTR lpszSubKey)
1609 {
1610 DWORD dwRet, dwKeyCount = 0;
1611 HKEY hSubKey = 0;
1612
1613 TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey));
1614
1615 dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1616 if(!dwRet)
1617 {
1618 dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1619 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1620 RegCloseKey(hSubKey);
1621 if(!dwRet)
1622 {
1623 if (!dwKeyCount)
1624 dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1625 else
1626 dwRet = ERROR_KEY_HAS_CHILDREN;
1627 }
1628 }
1629 return dwRet;
1630 }
1631
1632 /*************************************************************************
1633 * SHDeleteEmptyKeyW [SHLWAPI.@]
1634 *
1635 * See SHDeleteEmptyKeyA.
1636 */
1637 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1638 {
1639 DWORD dwRet, dwKeyCount = 0;
1640 HKEY hSubKey = 0;
1641
1642 TRACE("(hkey=%p, %s)\n", hKey, debugstr_w(lpszSubKey));
1643
1644 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1645 if(!dwRet)
1646 {
1647 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1648 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1649 RegCloseKey(hSubKey);
1650 if(!dwRet)
1651 {
1652 if (!dwKeyCount)
1653 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1654 else
1655 dwRet = ERROR_KEY_HAS_CHILDREN;
1656 }
1657 }
1658 return dwRet;
1659 }
1660
1661 /*************************************************************************
1662 * SHDeleteOrphanKeyA [SHLWAPI.@]
1663 *
1664 * Delete a registry key with no sub keys or values.
1665 *
1666 * PARAMS
1667 * hKey [I] Handle to registry key
1668 * lpszSubKey [I] Name of sub key to possibly delete
1669 *
1670 * RETURNS
1671 * Success: ERROR_SUCCESS. The key has been deleted if it was an orphan.
1672 * Failure: An error from RegOpenKeyExA(), RegQueryValueExA(), or RegDeleteKeyA().
1673 */
1674 DWORD WINAPI SHDeleteOrphanKeyA(HKEY hKey, LPCSTR lpszSubKey)
1675 {
1676 HKEY hSubKey;
1677 DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
1678
1679 TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey));
1680
1681 dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1682
1683 if(!dwRet)
1684 {
1685 /* Get subkey and value count */
1686 dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1687 NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
1688
1689 if(!dwRet && !dwKeyCount && !dwValueCount)
1690 {
1691 dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1692 }
1693 RegCloseKey(hSubKey);
1694 }
1695 return dwRet;
1696 }
1697
1698 /*************************************************************************
1699 * SHDeleteOrphanKeyW [SHLWAPI.@]
1700 *
1701 * See SHDeleteOrphanKeyA.
1702 */
1703 DWORD WINAPI SHDeleteOrphanKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1704 {
1705 HKEY hSubKey;
1706 DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
1707
1708 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1709
1710 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1711
1712 if(!dwRet)
1713 {
1714 /* Get subkey and value count */
1715 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1716 NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
1717
1718 if(!dwRet && !dwKeyCount && !dwValueCount)
1719 {
1720 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1721 }
1722 RegCloseKey(hSubKey);
1723 }
1724 return dwRet;
1725 }
1726
1727 /*************************************************************************
1728 * SHDeleteValueA [SHLWAPI.@]
1729 *
1730 * Delete a value from the registry.
1731 *
1732 * PARAMS
1733 * hKey [I] Handle to registry key
1734 * lpszSubKey [I] Name of sub key containing value to delete
1735 * lpszValue [I] Name of value to delete
1736 *
1737 * RETURNS
1738 * Success: ERROR_SUCCESS. The value is deleted.
1739 * Failure: An error code from RegOpenKeyExA() or RegDeleteValueA().
1740 */
1741 DWORD WINAPI SHDeleteValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue)
1742 {
1743 DWORD dwRet;
1744 HKEY hSubKey;
1745
1746 TRACE("(hkey=%p,%s,%s)\n", hKey, debugstr_a(lpszSubKey), debugstr_a(lpszValue));
1747
1748 dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey);
1749 if (!dwRet)
1750 {
1751 dwRet = RegDeleteValueA(hSubKey, lpszValue);
1752 RegCloseKey(hSubKey);
1753 }
1754 return dwRet;
1755 }
1756
1757 /*************************************************************************
1758 * SHDeleteValueW [SHLWAPI.@]
1759 *
1760 * See SHDeleteValueA.
1761 */
1762 DWORD WINAPI SHDeleteValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue)
1763 {
1764 DWORD dwRet;
1765 HKEY hSubKey;
1766
1767 TRACE("(hkey=%p,%s,%s)\n", hKey, debugstr_w(lpszSubKey), debugstr_w(lpszValue));
1768
1769 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey);
1770 if (!dwRet)
1771 {
1772 dwRet = RegDeleteValueW(hSubKey, lpszValue);
1773 RegCloseKey(hSubKey);
1774 }
1775 return dwRet;
1776 }
1777
1778 /*************************************************************************
1779 * SHEnumKeyExA [SHLWAPI.@]
1780 *
1781 * Enumerate sub keys in a registry key.
1782 *
1783 * PARAMS
1784 * hKey [I] Handle to registry key
1785 * dwIndex [I] Index of key to enumerate
1786 * lpszSubKey [O] Pointer updated with the subkey name
1787 * pwLen [O] Pointer updated with the subkey length
1788 *
1789 * RETURNS
1790 * Success: ERROR_SUCCESS. lpszSubKey and pwLen are updated.
1791 * Failure: An error code from RegEnumKeyExA().
1792 */
1793 LONG WINAPI SHEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpszSubKey,
1794 LPDWORD pwLen)
1795 {
1796 TRACE("(hkey=%p,%d,%s,%p)\n", hKey, dwIndex, debugstr_a(lpszSubKey), pwLen);
1797
1798 return RegEnumKeyExA(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL);
1799 }
1800
1801 /*************************************************************************
1802 * SHEnumKeyExW [SHLWAPI.@]
1803 *
1804 * See SHEnumKeyExA.
1805 */
1806 LONG WINAPI SHEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpszSubKey,
1807 LPDWORD pwLen)
1808 {
1809 TRACE("(hkey=%p,%d,%s,%p)\n", hKey, dwIndex, debugstr_w(lpszSubKey), pwLen);
1810
1811 return RegEnumKeyExW(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL);
1812 }
1813
1814 /*************************************************************************
1815 * SHEnumValueA [SHLWAPI.@]
1816 *
1817 * Enumerate values in a registry key.
1818 *
1819 * PARAMS
1820 * hKey [I] Handle to registry key
1821 * dwIndex [I] Index of key to enumerate
1822 * lpszValue [O] Pointer updated with the values name
1823 * pwLen [O] Pointer updated with the values length
1824 * pwType [O] Pointer updated with the values type
1825 * pvData [O] Pointer updated with the values data
1826 * pcbData [O] Pointer updated with the values size
1827 *
1828 * RETURNS
1829 * Success: ERROR_SUCCESS. Output parameters are updated.
1830 * Failure: An error code from RegEnumValueA().
1831 */
1832 LONG WINAPI SHEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpszValue,
1833 LPDWORD pwLen, LPDWORD pwType,
1834 LPVOID pvData, LPDWORD pcbData)
1835 {
1836 TRACE("(hkey=%p,%d,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
1837 debugstr_a(lpszValue), pwLen, pwType, pvData, pcbData);
1838
1839 return RegEnumValueA(hKey, dwIndex, lpszValue, pwLen, NULL,
1840 pwType, pvData, pcbData);
1841 }
1842
1843 /*************************************************************************
1844 * SHEnumValueW [SHLWAPI.@]
1845 *
1846 * See SHEnumValueA.
1847 */
1848 LONG WINAPI SHEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpszValue,
1849 LPDWORD pwLen, LPDWORD pwType,
1850 LPVOID pvData, LPDWORD pcbData)
1851 {
1852 TRACE("(hkey=%p,%d,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
1853 debugstr_w(lpszValue), pwLen, pwType, pvData, pcbData);
1854
1855 return RegEnumValueW(hKey, dwIndex, lpszValue, pwLen, NULL,
1856 pwType, pvData, pcbData);
1857 }
1858
1859 /*************************************************************************
1860 * @ [SHLWAPI.205]
1861 *
1862 * Get a value from the registry.
1863 *
1864 * PARAMS
1865 * hKey [I] Handle to registry key
1866 * pSubKey [I] Name of sub key containing value to get
1867 * pValue [I] Name of value to get
1868 * pwType [O] Destination for the values type
1869 * pvData [O] Destination for the values data
1870 * pbData [O] Destination for the values size
1871 *
1872 * RETURNS
1873 * Success: ERROR_SUCCESS. Output parameters contain the details read.
1874 * Failure: An error code from RegOpenKeyExA() or SHQueryValueExA(),
1875 * or ERROR_INVALID_FUNCTION in the machine is in safe mode.
1876 */
1877 DWORD WINAPI SHGetValueGoodBootA(HKEY hkey, LPCSTR pSubKey, LPCSTR pValue,
1878 LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
1879 {
1880 if (GetSystemMetrics(SM_CLEANBOOT))
1881 return ERROR_INVALID_FUNCTION;
1882 return SHGetValueA(hkey, pSubKey, pValue, pwType, pvData, pbData);
1883 }
1884
1885 /*************************************************************************
1886 * @ [SHLWAPI.206]
1887 *
1888 * Unicode version of SHGetValueGoodBootW.
1889 */
1890 DWORD WINAPI SHGetValueGoodBootW(HKEY hkey, LPCWSTR pSubKey, LPCWSTR pValue,
1891 LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
1892 {
1893 if (GetSystemMetrics(SM_CLEANBOOT))
1894 return ERROR_INVALID_FUNCTION;
1895 return SHGetValueW(hkey, pSubKey, pValue, pwType, pvData, pbData);
1896 }
1897
1898 /*************************************************************************
1899 * @ [SHLWAPI.320]
1900 *
1901 * Set a MIME content type in the registry.
1902 *
1903 * PARAMS
1904 * lpszSubKey [I] Name of key under HKEY_CLASSES_ROOT.
1905 * lpszValue [I] Value to set
1906 *
1907 * RETURNS
1908 * Success: TRUE
1909 * Failure: FALSE
1910 */
1911 BOOL WINAPI RegisterMIMETypeForExtensionA(LPCSTR lpszSubKey, LPCSTR lpszValue)
1912 {
1913 if (!lpszValue)
1914 {
1915 WARN("Invalid lpszValue would crash under Win32!\n");
1916 return FALSE;
1917 }
1918
1919 return !SHSetValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA,
1920 REG_SZ, lpszValue, strlen(lpszValue));
1921 }
1922
1923 /*************************************************************************
1924 * @ [SHLWAPI.321]
1925 *
1926 * Unicode version of RegisterMIMETypeForExtensionA.
1927 */
1928 BOOL WINAPI RegisterMIMETypeForExtensionW(LPCWSTR lpszSubKey, LPCWSTR lpszValue)
1929 {
1930 if (!lpszValue)
1931 {
1932 WARN("Invalid lpszValue would crash under Win32!\n");
1933 return FALSE;
1934 }
1935
1936 return !SHSetValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW,
1937 REG_SZ, lpszValue, strlenW(lpszValue));
1938 }
1939
1940 /*************************************************************************
1941 * @ [SHLWAPI.322]
1942 *
1943 * Delete a MIME content type from the registry.
1944 *
1945 * PARAMS
1946 * lpszSubKey [I] Name of sub key
1947 *
1948 * RETURNS
1949 * Success: TRUE
1950 * Failure: FALSE
1951 */
1952 BOOL WINAPI UnregisterMIMETypeForExtensionA(LPCSTR lpszSubKey)
1953 {
1954 return !SHDeleteValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA);
1955 }
1956
1957 /*************************************************************************
1958 * @ [SHLWAPI.323]
1959 *
1960 * Unicode version of UnregisterMIMETypeForExtensionA.
1961 */
1962 BOOL WINAPI UnregisterMIMETypeForExtensionW(LPCWSTR lpszSubKey)
1963 {
1964 return !SHDeleteValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW);
1965 }
1966
1967 /*************************************************************************
1968 * @ [SHLWAPI.328]
1969 *
1970 * Get the registry path to a MIME content key.
1971 *
1972 * PARAMS
1973 * lpszType [I] Content type to get the path for
1974 * lpszBuffer [O] Destination for path
1975 * dwLen [I] Length of lpszBuffer
1976 *
1977 * RETURNS
1978 * Success: TRUE. lpszBuffer contains the full path.
1979 * Failure: FALSE.
1980 *
1981 * NOTES
1982 * The base path for the key is "MIME\Database\Content Type\"
1983 */
1984 BOOL WINAPI GetMIMETypeSubKeyA(LPCSTR lpszType, LPSTR lpszBuffer, DWORD dwLen)
1985 {
1986 TRACE("(%s,%p,%d)\n", debugstr_a(lpszType), lpszBuffer, dwLen);
1987
1988 if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer)
1989 {
1990 size_t dwStrLen = strlen(lpszType);
1991
1992 if (dwStrLen < dwLen - dwLenMimeDbContent)
1993 {
1994 memcpy(lpszBuffer, szMimeDbContentA, dwLenMimeDbContent);
1995 memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, dwStrLen + 1);
1996 return TRUE;
1997 }
1998 }
1999 return FALSE;
2000 }
2001
2002 /*************************************************************************
2003 * @ [SHLWAPI.329]
2004 *
2005 * Unicode version of GetMIMETypeSubKeyA.
2006 */
2007 BOOL WINAPI GetMIMETypeSubKeyW(LPCWSTR lpszType, LPWSTR lpszBuffer, DWORD dwLen)
2008 {
2009 TRACE("(%s,%p,%d)\n", debugstr_w(lpszType), lpszBuffer, dwLen);
2010
2011 if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer)
2012 {
2013 DWORD dwStrLen = strlenW(lpszType);
2014
2015 if (dwStrLen < dwLen - dwLenMimeDbContent)
2016 {
2017 memcpy(lpszBuffer, szMimeDbContentW, dwLenMimeDbContent * sizeof(WCHAR));
2018 memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, (dwStrLen + 1) * sizeof(WCHAR));
2019 return TRUE;
2020 }
2021 }
2022 return FALSE;
2023 }
2024
2025 /*************************************************************************
2026 * @ [SHLWAPI.330]
2027 *
2028 * Get the file extension for a given Mime type.
2029 *
2030 * PARAMS
2031 * lpszType [I] Mime type to get the file extension for
2032 * lpExt [O] Destination for the resulting extension
2033 * iLen [I] Length of lpExt in characters
2034 *
2035 * RETURNS
2036 * Success: TRUE. lpExt contains the file extension.
2037 * Failure: FALSE, if any parameter is invalid or the extension cannot be
2038 * retrieved. If iLen > 0, lpExt is set to an empty string.
2039 *
2040 * NOTES
2041 * - The extension returned in lpExt always has a leading '.' character, even
2042 * if the registry Mime database entry does not.
2043 * - iLen must be long enough for the file extension for this function to succeed.
2044 */
2045 BOOL WINAPI MIME_GetExtensionA(LPCSTR lpszType, LPSTR lpExt, INT iLen)
2046 {
2047 char szSubKey[MAX_PATH];
2048 DWORD dwlen = iLen - 1, dwType;
2049 BOOL bRet = FALSE;
2050
2051 if (iLen > 0 && lpExt)
2052 *lpExt = '\0';
2053
2054 if (lpszType && lpExt && iLen > 2 &&
2055 GetMIMETypeSubKeyA(lpszType, szSubKey, MAX_PATH) &&
2056 !SHGetValueA(HKEY_CLASSES_ROOT, szSubKey, szExtensionA, &dwType, lpExt + 1, &dwlen) &&
2057 lpExt[1])
2058 {
2059 if (lpExt[1] == '.')
2060 memmove(lpExt, lpExt + 1, strlen(lpExt + 1) + 1);
2061 else
2062 *lpExt = '.'; /* Supply a '.' */
2063 bRet = TRUE;
2064 }
2065 return bRet;
2066 }
2067
2068 /*************************************************************************
2069 * @ [SHLWAPI.331]
2070 *
2071 * Unicode version of MIME_GetExtensionA.
2072 */
2073 BOOL WINAPI MIME_GetExtensionW(LPCWSTR lpszType, LPWSTR lpExt, INT iLen)
2074 {
2075 WCHAR szSubKey[MAX_PATH];
2076 DWORD dwlen = iLen - 1, dwType;
2077 BOOL bRet = FALSE;
2078
2079 if (iLen > 0 && lpExt)
2080 *lpExt = '\0';
2081
2082 if (lpszType && lpExt && iLen > 2 &&
2083 GetMIMETypeSubKeyW(lpszType, szSubKey, MAX_PATH) &&
2084 !SHGetValueW(HKEY_CLASSES_ROOT, szSubKey, szExtensionW, &dwType, lpExt + 1, &dwlen) &&
2085 lpExt[1])
2086 {
2087 if (lpExt[1] == '.')
2088 memmove(lpExt, lpExt + 1, (strlenW(lpExt + 1) + 1) * sizeof(WCHAR));
2089 else
2090 *lpExt = '.'; /* Supply a '.' */
2091 bRet = TRUE;
2092 }
2093 return bRet;
2094 }
2095
2096 /*************************************************************************
2097 * @ [SHLWAPI.324]
2098 *
2099 * Set the file extension for a MIME content key.
2100 *
2101 * PARAMS
2102 * lpszExt [I] File extension to set
2103 * lpszType [I] Content type to set the extension for
2104 *
2105 * RETURNS
2106 * Success: TRUE. The file extension is set in the registry.
2107 * Failure: FALSE.
2108 */
2109 BOOL WINAPI RegisterExtensionForMIMETypeA(LPCSTR lpszExt, LPCSTR lpszType)
2110 {
2111 DWORD dwLen;
2112 char szKey[MAX_PATH];
2113
2114 TRACE("(%s,%s)\n", debugstr_a(lpszExt), debugstr_a(lpszType));
2115
2116 if (!GetMIMETypeSubKeyA(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
2117 return FALSE;
2118
2119 dwLen = strlen(lpszExt) + 1;
2120
2121 if (SHSetValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA, REG_SZ, lpszExt, dwLen))
2122 return FALSE;
2123 return TRUE;
2124 }
2125
2126 /*************************************************************************
2127 * @ [SHLWAPI.325]
2128 *
2129 * Unicode version of RegisterExtensionForMIMETypeA.
2130 */
2131 BOOL WINAPI RegisterExtensionForMIMETypeW(LPCWSTR lpszExt, LPCWSTR lpszType)
2132 {
2133 DWORD dwLen;
2134 WCHAR szKey[MAX_PATH];
2135
2136 TRACE("(%s,%s)\n", debugstr_w(lpszExt), debugstr_w(lpszType));
2137
2138 /* Get the full path to the key */
2139 if (!GetMIMETypeSubKeyW(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
2140 return FALSE;
2141
2142 dwLen = (lstrlenW(lpszExt) + 1) * sizeof(WCHAR);
2143
2144 if (SHSetValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW, REG_SZ, lpszExt, dwLen))
2145 return FALSE;
2146 return TRUE;
2147 }
2148
2149 /*************************************************************************
2150 * @ [SHLWAPI.326]
2151 *
2152 * Delete a file extension from a MIME content type.
2153 *
2154 * PARAMS
2155 * lpszType [I] Content type to delete the extension for
2156 *
2157 * RETURNS
2158 * Success: TRUE. The file extension is deleted from the registry.
2159 * Failure: FALSE. The extension may have been removed but the key remains.
2160 *
2161 * NOTES
2162 * If deleting the extension leaves an orphan key, the key is removed also.
2163 */
2164 BOOL WINAPI UnregisterExtensionForMIMETypeA(LPCSTR lpszType)
2165 {
2166 char szKey[MAX_PATH];
2167
2168 TRACE("(%s)\n", debugstr_a(lpszType));
2169
2170 if (!GetMIMETypeSubKeyA(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
2171 return FALSE;
2172
2173 if (!SHDeleteValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA))
2174 return FALSE;
2175
2176 if (!SHDeleteOrphanKeyA(HKEY_CLASSES_ROOT, szKey))
2177 return FALSE;
2178 return TRUE;
2179 }
2180
2181 /*************************************************************************
2182 * @ [SHLWAPI.327]
2183 *
2184 * Unicode version of UnregisterExtensionForMIMETypeA.
2185 */
2186 BOOL WINAPI UnregisterExtensionForMIMETypeW(LPCWSTR lpszType)
2187 {
2188 WCHAR szKey[MAX_PATH];
2189
2190 TRACE("(%s)\n", debugstr_w(lpszType));
2191
2192 if (!GetMIMETypeSubKeyW(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
2193 return FALSE;
2194
2195 if (!SHDeleteValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW))
2196 return FALSE;
2197
2198 if (!SHDeleteOrphanKeyW(HKEY_CLASSES_ROOT, szKey))
2199 return FALSE;
2200 return TRUE;
2201 }
2202
2203 /*************************************************************************
2204 * SHRegDuplicateHKey [SHLWAPI.@]
2205 *
2206 * Create a duplicate of a registry handle.
2207 *
2208 * PARAMS
2209 * hKey [I] key to duplicate.
2210 *
2211 * RETURNS
2212 * A new handle pointing to the same key as hKey.
2213 */
2214 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
2215 {
2216 HKEY newKey = 0;
2217
2218 RegOpenKeyExA(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
2219 TRACE("new key is %p\n", newKey);
2220 return newKey;
2221 }
2222
2223
2224 /*************************************************************************
2225 * SHCopyKeyA [SHLWAPI.@]
2226 *
2227 * Copy a key and its values/sub keys to another location.
2228 *
2229 * PARAMS
2230 * hKeySrc [I] Source key to copy from
2231 * lpszSrcSubKey [I] Sub key under hKeySrc, or NULL to use hKeySrc directly
2232 * hKeyDst [I] Destination key
2233 * dwReserved [I] Reserved, must be 0
2234 *
2235 * RETURNS
2236 * Success: ERROR_SUCCESS. The key is copied to the destination key.
2237 * Failure: A standard windows error code.
2238 *
2239 * NOTES
2240 * If hKeyDst is a key under hKeySrc, this function will misbehave
2241 * (It will loop until out of stack, or the registry is full). This
2242 * bug is present in Win32 also.
2243 */
2244 DWORD WINAPI SHCopyKeyA(HKEY hKeySrc, LPCSTR lpszSrcSubKey, HKEY hKeyDst, DWORD dwReserved)
2245 {
2246 WCHAR szSubKeyW[MAX_PATH];
2247
2248 TRACE("(hkey=%p,%s,%p08x,%d)\n", hKeySrc, debugstr_a(lpszSrcSubKey), hKeyDst, dwReserved);
2249
2250 if (lpszSrcSubKey)
2251 MultiByteToWideChar(CP_ACP, 0, lpszSrcSubKey, -1, szSubKeyW, MAX_PATH);
2252
2253 return SHCopyKeyW(hKeySrc, lpszSrcSubKey ? szSubKeyW : NULL, hKeyDst, dwReserved);
2254 }
2255
2256 /*************************************************************************
2257 * SHCopyKeyW [SHLWAPI.@]
2258 *
2259 * See SHCopyKeyA.
2260 */
2261 DWORD WINAPI SHCopyKeyW(HKEY hKeySrc, LPCWSTR lpszSrcSubKey, HKEY hKeyDst, DWORD dwReserved)
2262 {
2263 DWORD dwKeyCount = 0, dwValueCount = 0, dwMaxKeyLen = 0;
2264 DWORD dwMaxValueLen = 0, dwMaxDataLen = 0, i;
2265 BYTE buff[1024];
2266 LPVOID lpBuff = buff;
2267 WCHAR szName[MAX_PATH], *lpszName = szName;
2268 DWORD dwRet = S_OK;
2269
2270 TRACE("hkey=%p,%s,%p08x,%d)\n", hKeySrc, debugstr_w(lpszSrcSubKey), hKeyDst, dwReserved);
2271
2272 if(!hKeyDst || !hKeySrc)
2273 dwRet = ERROR_INVALID_PARAMETER;
2274 else
2275 {
2276 /* Open source key */
2277 if(lpszSrcSubKey)
2278 dwRet = RegOpenKeyExW(hKeySrc, lpszSrcSubKey, 0, KEY_ALL_ACCESS, &hKeySrc);
2279
2280 if(dwRet)
2281 hKeyDst = NULL; /* Don't close this key since we didn't open it */
2282 else
2283 {
2284 /* Get details about sub keys and values */
2285 dwRet = RegQueryInfoKeyW(hKeySrc, NULL, NULL, NULL, &dwKeyCount, &dwMaxKeyLen,
2286 NULL, &dwValueCount, &dwMaxValueLen, &dwMaxDataLen,
2287 NULL, NULL);
2288 if(!dwRet)
2289 {
2290 if (dwMaxValueLen > dwMaxKeyLen)
2291 dwMaxKeyLen = dwMaxValueLen; /* Get max size for key/value names */
2292
2293 if (dwMaxKeyLen++ > MAX_PATH - 1)
2294 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxKeyLen * sizeof(WCHAR));
2295
2296 if (dwMaxDataLen > sizeof(buff))
2297 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwMaxDataLen);
2298
2299 if (!lpszName || !lpBuff)
2300 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2301 }
2302 }
2303 }
2304
2305 /* Copy all the sub keys */
2306 for(i = 0; i < dwKeyCount && !dwRet; i++)
2307 {
2308 HKEY hSubKeySrc, hSubKeyDst;
2309 DWORD dwSize = dwMaxKeyLen;
2310
2311 dwRet = RegEnumKeyExW(hKeySrc, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2312
2313 if(!dwRet)
2314 {
2315 /* Open source sub key */
2316 dwRet = RegOpenKeyExW(hKeySrc, lpszName, 0, KEY_READ, &hSubKeySrc);
2317
2318 if(!dwRet)
2319 {
2320 /* Create destination sub key */
2321 dwRet = RegCreateKeyW(hKeyDst, lpszName, &hSubKeyDst);
2322
2323 if(!dwRet)
2324 {
2325 /* Recursively copy keys and values from the sub key */
2326 dwRet = SHCopyKeyW(hSubKeySrc, NULL, hSubKeyDst, 0);
2327 RegCloseKey(hSubKeyDst);
2328 }
2329 }
2330 RegCloseKey(hSubKeySrc);
2331 }
2332 }
2333
2334 /* Copy all the values in this key */
2335 for (i = 0; i < dwValueCount && !dwRet; i++)
2336 {
2337 DWORD dwNameSize = dwMaxKeyLen, dwType, dwLen = dwMaxDataLen;
2338
2339 dwRet = RegEnumValueW(hKeySrc, i, lpszName, &dwNameSize, NULL, &dwType, lpBuff, &dwLen);
2340
2341 if (!dwRet)
2342 dwRet = SHSetValueW(hKeyDst, NULL, lpszName, dwType, lpBuff, dwLen);
2343 }
2344
2345 /* Free buffers if allocated */
2346 if (lpszName != szName)
2347 HeapFree(GetProcessHeap(), 0, lpszName);
2348 if (lpBuff != buff)
2349 HeapFree(GetProcessHeap(), 0, lpBuff);
2350
2351 if (lpszSrcSubKey && hKeyDst)
2352 RegCloseKey(hKeyDst);
2353 return dwRet;
2354 }
2355
2356 /*
2357 * The following functions are ORDINAL ONLY:
2358 */
2359
2360 /*************************************************************************
2361 * @ [SHLWAPI.280]
2362 *
2363 * Read an integer value from the registry, falling back to a default.
2364 *
2365 * PARAMS
2366 * hKey [I] Registry key to read from
2367 * lpszValue [I] Value name to read
2368 * iDefault [I] Default value to return
2369 *
2370 * RETURNS
2371 * The value contained in the given registry value if present, otherwise
2372 * iDefault.
2373 */
2374 int WINAPI SHRegGetIntW(HKEY hKey, LPCWSTR lpszValue, int iDefault)
2375 {
2376 TRACE("(%p,%s,%d)\n", hKey, debugstr_w(lpszValue), iDefault);
2377
2378 if (hKey)
2379 {
2380 WCHAR szBuff[32];
2381 DWORD dwSize = sizeof(szBuff);
2382 szBuff[0] = '\0';
2383 SHQueryValueExW(hKey, lpszValue, 0, 0, szBuff, &dwSize);
2384
2385 if(*szBuff >= '0' && *szBuff <= '9')
2386 return StrToIntW(szBuff);
2387 }
2388 return iDefault;
2389 }
2390
2391 /*************************************************************************
2392 * @ [SHLWAPI.343]
2393 *
2394 * Create or open an explorer ClassId Key.
2395 *
2396 * PARAMS
2397 * guid [I] Explorer ClassId key to open
2398 * lpszValue [I] Value name under the ClassId Key
2399 * bUseHKCU [I] TRUE=Use HKEY_CURRENT_USER, FALSE=Use HKEY_CLASSES_ROOT
2400 * bCreate [I] TRUE=Create the key if it doesn't exist, FALSE=Don't
2401 * phKey [O] Destination for the resulting key handle
2402 *
2403 * RETURNS
2404 * Success: S_OK. phKey contains the resulting registry handle.
2405 * Failure: An HRESULT error code indicating the problem.
2406 */
2407 HRESULT WINAPI SHRegGetCLSIDKeyA(REFGUID guid, LPCSTR lpszValue, BOOL bUseHKCU, BOOL bCreate, PHKEY phKey)
2408 {
2409 WCHAR szValue[MAX_PATH];
2410
2411 if (lpszValue)
2412 MultiByteToWideChar(CP_ACP, 0, lpszValue, -1, szValue, sizeof(szValue)/sizeof(WCHAR));
2413
2414 return SHRegGetCLSIDKeyW(guid, lpszValue ? szValue : NULL, bUseHKCU, bCreate, phKey);
2415 }
2416
2417 /*************************************************************************
2418 * @ [SHLWAPI.344]
2419 *
2420 * Unicode version of SHRegGetCLSIDKeyA.
2421 */
2422 HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID guid, LPCWSTR lpszValue, BOOL bUseHKCU,
2423 BOOL bCreate, PHKEY phKey)
2424 {
2425 static const WCHAR szClassIdKey[] = { 'S','o','f','t','w','a','r','e','\\',
2426 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2427 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2428 'E','x','p','l','o','r','e','r','\\','C','L','S','I','D','\\' };
2429 #define szClassIdKeyLen (sizeof(szClassIdKey)/sizeof(WCHAR))
2430 WCHAR szKey[MAX_PATH];
2431 DWORD dwRet;
2432 HKEY hkey;
2433
2434 /* Create the key string */
2435 memcpy(szKey, szClassIdKey, sizeof(szClassIdKey));
2436 SHStringFromGUIDW(guid, szKey + szClassIdKeyLen, 39); /* Append guid */
2437
2438 if(lpszValue)
2439 {
2440 szKey[szClassIdKeyLen + 39] = '\\';
2441 strcpyW(szKey + szClassIdKeyLen + 40, lpszValue); /* Append value name */
2442 }
2443
2444 hkey = bUseHKCU ? HKEY_CURRENT_USER : HKEY_CLASSES_ROOT;
2445
2446 if(bCreate)
2447 dwRet = RegCreateKeyW(hkey, szKey, phKey);
2448 else
2449 dwRet = RegOpenKeyExW(hkey, szKey, 0, KEY_READ, phKey);
2450
2451 return dwRet ? HRESULT_FROM_WIN32(dwRet) : S_OK;
2452 }
2453
2454 /*************************************************************************
2455 * SHRegisterValidateTemplate [SHLWAPI.@]
2456 *
2457 * observed from the ie 5.5 installer:
2458 * - allocates a buffer with the size of the given file
2459 * - read the file content into the buffer
2460 * - creates the key szTemplateKey
2461 * - sets "205523652929647911071668590831910975402"=dword:00002e37 at
2462 * the key
2463 *
2464 * PARAMS
2465 * filename [I] An existing file its content is read into an allocated
2466 * buffer
2467 * unknown [I]
2468 *
2469 * RETURNS
2470 * Success: ERROR_SUCCESS.
2471 */
2472 HRESULT WINAPI SHRegisterValidateTemplate(LPCWSTR filename, BOOL unknown)
2473 {
2474 /* static const WCHAR szTemplateKey[] = { 'S','o','f','t','w','a','r','e','\\',
2475 * 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2476 * 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2477 * 'E','x','p','l','o','r','e','r','\\',
2478 * 'T','e','m','p','l','a','t','e','R','e','g','i','s','t','r','y',0 };
2479 */
2480 FIXME("stub: %s, %08x\n", debugstr_w(filename), unknown);
2481
2482 return S_OK;
2483 }