xref: /reactos/dll/win32/shlwapi/reg.c (revision 682f85ad)
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 #ifndef __REACTOS__
2426   static const WCHAR szClassIdKey[] = { 'S','o','f','t','w','a','r','e','\\',
2427     'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2428     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2429     'E','x','p','l','o','r','e','r','\\','C','L','S','I','D','\\' };
2430 #endif
2431 #define szClassIdKeyLen (sizeof(szClassIdKey)/sizeof(WCHAR))
2432   WCHAR szKey[MAX_PATH];
2433   DWORD dwRet;
2434   HKEY hkey;
2435 
2436   /* Create the key string */
2437 #ifdef __REACTOS__
2438   // https://www.geoffchappell.com/studies/windows/shell/shlwapi/api/reg/reggetclsidkey.htm
2439   WCHAR* ptr;
2440 
2441   wcscpy(szKey, bUseHKCU ? L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\" : L"CLSID\\");
2442   ptr = szKey + wcslen(szKey);
2443   SHStringFromGUIDW(guid, ptr, 39); /* Append guid */
2444   if (lpszValue)
2445   {
2446       ptr = szKey + wcslen(szKey);
2447       wcscat(ptr, L"\\");
2448       wcscat(++ptr, lpszValue);
2449   }
2450 #else
2451   memcpy(szKey, szClassIdKey, sizeof(szClassIdKey));
2452   SHStringFromGUIDW(guid, szKey + szClassIdKeyLen, 39); /* Append guid */
2453 
2454   if(lpszValue)
2455   {
2456     szKey[szClassIdKeyLen + 39] = '\\';
2457     strcpyW(szKey + szClassIdKeyLen + 40, lpszValue); /* Append value name */
2458   }
2459 #endif
2460 
2461   hkey = bUseHKCU ? HKEY_CURRENT_USER : HKEY_CLASSES_ROOT;
2462 
2463   if(bCreate)
2464     dwRet = RegCreateKeyW(hkey, szKey, phKey);
2465   else
2466     dwRet = RegOpenKeyExW(hkey, szKey, 0, KEY_READ, phKey);
2467 
2468   return dwRet ? HRESULT_FROM_WIN32(dwRet) : S_OK;
2469 }
2470 
2471 /*************************************************************************
2472  * SHRegisterValidateTemplate	[SHLWAPI.@]
2473  *
2474  * observed from the ie 5.5 installer:
2475  *  - allocates a buffer with the size of the given file
2476  *  - read the file content into the buffer
2477  *  - creates the key szTemplateKey
2478  *  - sets "205523652929647911071668590831910975402"=dword:00002e37 at
2479  *    the key
2480  *
2481  * PARAMS
2482  *  filename [I] An existing file its content is read into an allocated
2483  *               buffer
2484  *  unknown  [I]
2485  *
2486  * RETURNS
2487  *  Success: ERROR_SUCCESS.
2488  */
2489 HRESULT WINAPI SHRegisterValidateTemplate(LPCWSTR filename, BOOL unknown)
2490 {
2491 /* static const WCHAR szTemplateKey[] = { 'S','o','f','t','w','a','r','e','\\',
2492  *  'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2493  *  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2494  *  'E','x','p','l','o','r','e','r','\\',
2495  *  'T','e','m','p','l','a','t','e','R','e','g','i','s','t','r','y',0 };
2496  */
2497   FIXME("stub: %s, %08x\n", debugstr_w(filename), unknown);
2498 
2499   return S_OK;
2500 }
2501