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