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