Fixed a race condition on RPC worker thread creation, and a typo.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <string.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winerror.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "wine/debug.h"
31 #define NO_SHLWAPI_STREAM
32 #include "shlwapi.h"
33 #include "wine/unicode.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(shell);
36
37 /* Key/Value names for MIME content types */
38 static const char *lpszContentTypeA = "Content Type";
39 static const WCHAR lpszContentTypeW[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
40
41 static const char *szMimeDbContentA = "MIME\\Database\\Content Type\\";
42 static const WCHAR szMimeDbContentW[] = { 'M', 'I', 'M','E','\\',
43   'D','a','t','a','b','a','s','e','\\','C','o','n','t','e','n','t',
44   ' ','T','y','p','e','\\', 0 };
45 static const DWORD dwLenMimeDbContent = 27; /* strlen of szMimeDbContentA/W */
46
47 static const char *szExtensionA = "Extension";
48 static const WCHAR szExtensionW[] = { 'E', 'x', 't','e','n','s','i','o','n','\0' };
49
50 /* internal structure of what the HUSKEY points to */
51 typedef struct {
52     HKEY     HKCUkey;                  /* HKEY of opened HKCU key      */
53     HKEY     HKLMkey;                  /* HKEY of opened HKLM key      */
54     HKEY     start;                    /* HKEY of where to start       */
55     WCHAR    key_string[MAX_PATH];     /* additional path from 'start' */
56 } Internal_HUSKEY, *LPInternal_HUSKEY;
57
58
59 #define REG_HKCU  TRUE
60 #define REG_HKLM  FALSE
61 /*************************************************************************
62  * REG_GetHKEYFromHUSKEY
63  *
64  * Function:  Return the proper registry key from the HUSKEY structure
65  *            also allow special predefined values.
66  */
67 HKEY REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which)
68 {
69         HKEY test = (HKEY) hUSKey;
70         LPInternal_HUSKEY mihk = (LPInternal_HUSKEY) hUSKey;
71
72         if ((test == HKEY_CLASSES_ROOT)        ||
73             (test == HKEY_CURRENT_CONFIG)      ||
74             (test == HKEY_CURRENT_USER)        ||
75             (test == HKEY_DYN_DATA)            ||
76             (test == HKEY_LOCAL_MACHINE)       ||
77             (test == HKEY_PERFORMANCE_DATA)    ||
78 /* FIXME:  need to define for Win2k, ME, XP
79  *          (test == HKEY_PERFORMANCE_TEXT)    ||
80  *          (test == HKEY_PERFORMANCE_NLSTEXT) ||
81  */
82             (test == HKEY_USERS)) return test;
83         if (which == REG_HKCU) return mihk->HKCUkey;
84         return mihk->HKLMkey;
85 }
86
87
88 /*************************************************************************
89  * SHRegOpenUSKeyA      [SHLWAPI.@]
90  *
91  * Opens a user-specific registry key
92  *
93  * RETURNS
94  *  Success: ERROR_SUCCESS
95  *  Failure: An error code from RegOpenKeyExA().
96  */
97 LONG WINAPI SHRegOpenUSKeyA(
98         LPCSTR Path, /* [I] Key name to open */
99         REGSAM AccessType, /* [I] Access type */
100         HUSKEY hRelativeUSKey, /* [I] Relative user key */
101         PHUSKEY phNewUSKey, /* [O] Destination for created key */
102         BOOL fIgnoreHKCU)  /* [I] TRUE=Don't check HKEY_CURRENT_USER */
103 {
104     HKEY openHKCUkey=0;
105     HKEY openHKLMkey=0;
106     LONG ret2, ret1 = ~ERROR_SUCCESS;
107     LPInternal_HUSKEY ihky;
108
109     TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_a(Path),
110           (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey,
111           (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
112
113     /* now create the internal version of HUSKEY */
114     ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 ,
115                                         sizeof(Internal_HUSKEY));
116     MultiByteToWideChar(0, 0, Path, -1, ihky->key_string,
117                         sizeof(ihky->key_string)-1);
118
119     if (hRelativeUSKey) {
120         openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
121         openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
122     }
123     else {
124         openHKCUkey = HKEY_CURRENT_USER;
125         openHKLMkey = HKEY_LOCAL_MACHINE;
126     }
127
128     ihky->HKCUkey = 0;
129     ihky->HKLMkey = 0;
130     if (!fIgnoreHKCU) {
131         ret1 = RegOpenKeyExA(openHKCUkey, Path,
132                              0, AccessType, &ihky->HKCUkey);
133         /* if successful, then save real starting point */
134         if (ret1 != ERROR_SUCCESS)
135             ihky->HKCUkey = 0;
136     }
137     ret2 = RegOpenKeyExA(openHKLMkey, Path,
138                          0, AccessType, &ihky->HKLMkey);
139     if (ret2 != ERROR_SUCCESS)
140         ihky->HKLMkey = 0;
141
142     if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
143         TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
144
145     /* if all attempts have failed then bail */
146     if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
147         HeapFree(GetProcessHeap(), 0, ihky);
148         if (phNewUSKey)
149             *phNewUSKey = NULL;
150         return ret2;
151     }
152
153     TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
154     if (phNewUSKey)
155         *phNewUSKey = (HUSKEY)ihky;
156     return ERROR_SUCCESS;
157 }
158
159 /*************************************************************************
160  * SHRegOpenUSKeyW      [SHLWAPI.@]
161  *
162  * See SHRegOpenUSKeyA.
163  */
164 LONG WINAPI SHRegOpenUSKeyW(
165         LPCWSTR Path,
166         REGSAM AccessType,
167         HUSKEY hRelativeUSKey,
168         PHUSKEY phNewUSKey,
169         BOOL fIgnoreHKCU)
170 {
171     HKEY openHKCUkey=0;
172     HKEY openHKLMkey=0;
173     LONG ret2, ret1 = ~ERROR_SUCCESS;
174     LPInternal_HUSKEY ihky;
175
176     TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_w(Path),
177           (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey,
178           (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
179
180     /* now create the internal version of HUSKEY */
181     ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 ,
182                                         sizeof(Internal_HUSKEY));
183     lstrcpynW(ihky->key_string, Path, sizeof(ihky->key_string));
184
185     if (hRelativeUSKey) {
186         openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
187         openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
188     }
189     else {
190         openHKCUkey = HKEY_CURRENT_USER;
191         openHKLMkey = HKEY_LOCAL_MACHINE;
192     }
193
194     ihky->HKCUkey = 0;
195     ihky->HKLMkey = 0;
196     if (!fIgnoreHKCU) {
197         ret1 = RegOpenKeyExW(openHKCUkey, Path,
198                             0, AccessType, &ihky->HKCUkey);
199         /* if successful, then save real starting point */
200         if (ret1 != ERROR_SUCCESS)
201             ihky->HKCUkey = 0;
202     }
203     ret2 = RegOpenKeyExW(openHKLMkey, Path,
204                         0, AccessType, &ihky->HKLMkey);
205     if (ret2 != ERROR_SUCCESS)
206         ihky->HKLMkey = 0;
207
208     if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
209         TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
210
211     /* if all attempts have failed then bail */
212     if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
213         HeapFree(GetProcessHeap(), 0, ihky);
214         if (phNewUSKey)
215             *phNewUSKey = NULL;
216         return ret2;
217     }
218
219     TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
220     if (phNewUSKey)
221         *phNewUSKey = (HUSKEY)ihky;
222     return ERROR_SUCCESS;
223 }
224
225 /*************************************************************************
226  * SHRegCloseUSKey      [SHLWAPI.@]
227  *
228  * Close a user-specific registry key
229  *
230  * RETURNS
231  *  Success: ERROR_SUCCESS
232  *  Failure: An error code from RegCloseKey().
233  */
234 LONG WINAPI SHRegCloseUSKey(
235         HUSKEY hUSKey) /* [I] Key to close */
236 {
237     LPInternal_HUSKEY mihk = (LPInternal_HUSKEY)hUSKey;
238     LONG ret = ERROR_SUCCESS;
239
240     if (mihk->HKCUkey)
241         ret = RegCloseKey(mihk->HKCUkey);
242     if (mihk->HKLMkey)
243         ret = RegCloseKey(mihk->HKLMkey);
244     HeapFree(GetProcessHeap(), 0, mihk);
245     return ret;
246 }
247
248 /*************************************************************************
249  *      SHRegQueryUSValueA      [SHLWAPI.@]
250  *
251  * Query a user-specific registry value.
252  *
253  * RETURNS
254  *  Success: ERROR_SUCCESS
255  *  Failure: An error code from RegQueryValueExA().
256  */
257 LONG WINAPI SHRegQueryUSValueA(
258         HUSKEY hUSKey, /* [I] Key to query */
259         LPCSTR pszValue, /* [I] Value name under hUSKey */
260         LPDWORD pdwType, /* [O] Destination for value type */
261         LPVOID pvData, /* [O] Destination for value data */
262         LPDWORD pcbData, /* [O] Destination for value length */
263         BOOL fIgnoreHKCU,  /* [I] TRUE=Don't check HKEY_CURRENT_USER */
264         LPVOID pvDefaultData, /* [I] Default data if pszValue does not exist */
265         DWORD dwDefaultDataSize) /* [I] Length of pvDefaultData */
266 {
267         LONG ret = ~ERROR_SUCCESS;
268         LONG i, maxmove;
269         HKEY dokey;
270         CHAR *src, *dst;
271
272         /* if user wants HKCU, and it exists, then try it */
273         if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
274             ret = RegQueryValueExA(dokey,
275                                    pszValue, 0, pdwType, pvData, pcbData);
276             TRACE("HKCU RegQueryValue returned %08lx\n", ret);
277         }
278
279         /* if HKCU did not work and HKLM exists, then try it */
280         if ((ret != ERROR_SUCCESS) &&
281             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
282             ret = RegQueryValueExA(dokey,
283                                    pszValue, 0, pdwType, pvData, pcbData);
284             TRACE("HKLM RegQueryValue returned %08lx\n", ret);
285         }
286
287         /* if neither worked, and default data exists, then use it */
288         if (ret != ERROR_SUCCESS) {
289             if (pvDefaultData && (dwDefaultDataSize != 0)) {
290                 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
291                 src = (CHAR*)pvDefaultData;
292                 dst = (CHAR*)pvData;
293                 for(i=0; i<maxmove; i++) *dst++ = *src++;
294                 *pcbData = maxmove;
295                 TRACE("setting default data\n");
296                 ret = ERROR_SUCCESS;
297             }
298         }
299         return ret;
300 }
301
302
303 /*************************************************************************
304  *      SHRegQueryUSValueW      [SHLWAPI.@]
305  *
306  * See SHRegQueryUSValueA.
307  */
308 LONG WINAPI SHRegQueryUSValueW(
309         HUSKEY hUSKey,
310         LPCWSTR pszValue,
311         LPDWORD pdwType,
312         LPVOID pvData,
313         LPDWORD pcbData,
314         BOOL fIgnoreHKCU,
315         LPVOID pvDefaultData,
316         DWORD dwDefaultDataSize)
317 {
318         LONG ret = ~ERROR_SUCCESS;
319         LONG i, maxmove;
320         HKEY dokey;
321         CHAR *src, *dst;
322
323         /* if user wants HKCU, and it exists, then try it */
324         if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
325             ret = RegQueryValueExW(dokey,
326                                    pszValue, 0, pdwType, pvData, pcbData);
327             TRACE("HKCU RegQueryValue returned %08lx\n", ret);
328         }
329
330         /* if HKCU did not work and HKLM exists, then try it */
331         if ((ret != ERROR_SUCCESS) &&
332             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
333             ret = RegQueryValueExW(dokey,
334                                    pszValue, 0, pdwType, pvData, pcbData);
335             TRACE("HKLM RegQueryValue returned %08lx\n", ret);
336         }
337
338         /* if neither worked, and default data exists, then use it */
339         if (ret != ERROR_SUCCESS) {
340             if (pvDefaultData && (dwDefaultDataSize != 0)) {
341                 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
342                 src = (CHAR*)pvDefaultData;
343                 dst = (CHAR*)pvData;
344                 for(i=0; i<maxmove; i++) *dst++ = *src++;
345                 *pcbData = maxmove;
346                 TRACE("setting default data\n");
347                 ret = ERROR_SUCCESS;
348             }
349         }
350         return ret;
351 }
352
353 /*************************************************************************
354  * SHRegGetUSValueA     [SHLWAPI.@]
355  *
356  * Get a user-specific registry value.
357  *
358  * RETURNS
359  *  Success: ERROR_SUCCESS
360  *  Failure: An error code from SHRegOpenUSKeyA() or SHRegQueryUSValueA().
361  *
362  * NOTES
363  *   This function opens pSubKey, queries the value, and then closes the key.
364  */
365 LONG WINAPI SHRegGetUSValueA(
366         LPCSTR   pSubKey, /* [I] Key name to open */
367         LPCSTR   pValue, /* [I] Value name to open */
368         LPDWORD  pwType, /* [O] Destination for the type of the value */
369         LPVOID   pvData, /* [O] Destination for the value */
370         LPDWORD  pcbData, /* [I] Destination for the length of the value **/
371         BOOL     flagIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */
372         LPVOID   pDefaultData, /* [I] Default value if it doesn't exist */
373         DWORD    wDefaultDataSize) /* [I] Length of pDefaultData */
374 {
375         HUSKEY myhuskey;
376         LONG ret;
377
378         if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
379         TRACE("key '%s', value '%s', datalen %ld,  %s\n",
380               debugstr_a(pSubKey), debugstr_a(pValue), *pcbData,
381               (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
382
383         ret = SHRegOpenUSKeyA(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
384         if (ret == ERROR_SUCCESS) {
385             ret = SHRegQueryUSValueA(myhuskey, pValue, pwType, pvData,
386                                      pcbData, flagIgnoreHKCU, pDefaultData,
387                                      wDefaultDataSize);
388             SHRegCloseUSKey(myhuskey);
389         }
390         return ret;
391 }
392
393 /*************************************************************************
394  * SHRegGetUSValueW     [SHLWAPI.@]
395  *
396  * See SHRegGetUSValueA.
397  */
398 LONG WINAPI SHRegGetUSValueW(
399         LPCWSTR  pSubKey,
400         LPCWSTR  pValue,
401         LPDWORD  pwType,
402         LPVOID   pvData,
403         LPDWORD  pcbData,
404         BOOL     flagIgnoreHKCU,
405         LPVOID   pDefaultData,
406         DWORD    wDefaultDataSize)
407 {
408         HUSKEY myhuskey;
409         LONG ret;
410
411         if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
412         TRACE("key '%s', value '%s', datalen %ld,  %s\n",
413               debugstr_w(pSubKey), debugstr_w(pValue), *pcbData,
414               (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
415
416         ret = SHRegOpenUSKeyW(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
417         if (ret == ERROR_SUCCESS) {
418             ret = SHRegQueryUSValueW(myhuskey, pValue, pwType, pvData,
419                                      pcbData, flagIgnoreHKCU, pDefaultData,
420                                      wDefaultDataSize);     
421             SHRegCloseUSKey(myhuskey);
422         }
423         return ret;
424 }
425
426 /*************************************************************************
427  * SHRegSetUSValueA   [SHLWAPI.@]
428  */
429 LONG WINAPI SHRegSetUSValueA(
430         LPCSTR pszSubKey,
431         LPCSTR pszValue,
432         DWORD   dwType,
433         LPVOID  pvData,
434         DWORD   cbData,
435         DWORD   dwFlags)
436 {
437         HUSKEY myhuskey;
438         LONG   ret;
439         BOOL   ignoreHKCU;
440
441         if (!pvData) return ERROR_INVALID_FUNCTION;
442         TRACE("key '%s', value '%s', datalen %ld\n",
443               debugstr_a(pszSubKey), debugstr_a(pszValue), cbData);
444         
445         ignoreHKCU = ((dwFlags == SHREGSET_HKLM) || (dwFlags == SHREGSET_FORCE_HKLM));
446
447         ret = SHRegOpenUSKeyA(pszSubKey, 0x1, 0, &myhuskey, ignoreHKCU);
448         if (ret == ERROR_SUCCESS) {
449           ret = SHRegWriteUSValueA(myhuskey, pszValue, dwType, pvData, 
450                                    cbData, dwFlags);
451             SHRegCloseUSKey(myhuskey);
452         }
453         return ret;
454 }
455
456 /*************************************************************************
457  * SHRegSetUSValueW   [SHLWAPI.@]
458  */
459 LONG WINAPI SHRegSetUSValueW(
460         LPCWSTR pszSubKey,
461         LPCWSTR pszValue,
462         DWORD   dwType,
463         LPVOID  pvData,
464         DWORD   cbData,
465         DWORD   dwFlags)
466 {
467         HUSKEY myhuskey;
468         LONG   ret;
469         BOOL   ignoreHKCU;
470
471         if (!pvData) return ERROR_INVALID_FUNCTION;
472         TRACE("key '%s', value '%s', datalen %ld\n",
473               debugstr_w(pszSubKey), debugstr_w(pszValue), cbData);
474         
475         ignoreHKCU = ((dwFlags == SHREGSET_HKLM) || (dwFlags == SHREGSET_FORCE_HKLM));
476
477         ret = SHRegOpenUSKeyW(pszSubKey, 0x1, 0, &myhuskey, ignoreHKCU);
478         if (ret == ERROR_SUCCESS) {
479           ret = SHRegWriteUSValueW(myhuskey, pszValue, dwType, pvData, 
480                                    cbData, dwFlags);
481             SHRegCloseUSKey(myhuskey);
482         }
483         return ret;
484 }
485
486 /*************************************************************************
487  * SHRegGetBoolUSValueA   [SHLWAPI.@]
488  *
489  * Get a user-specific registry boolean value.
490  *
491  * RETURNS
492  *  Success: ERROR_SUCCESS
493  *  Failure: An error code from SHRegOpenUSKeyA() or SHRegQueryUSValueA().
494  *
495  * NOTES
496  *   This function opens pszSubKey, queries the value, and then closes the key.
497  *
498  *   Boolean values are one of the following:
499  *   True: YES,TRUE,non-zero
500  *   False: NO,FALSE,0
501  */
502 BOOL WINAPI SHRegGetBoolUSValueA(
503         LPCSTR pszSubKey, /* [I] Key name to open */
504         LPCSTR pszValue, /* [I] Value name to open */
505         BOOL fIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */
506         BOOL fDefault) /* [I] Default value to use if pszValue is not present */
507 {
508         LONG retvalue;
509         DWORD type, datalen, work;
510         BOOL ret = fDefault;
511         CHAR data[10];
512
513         TRACE("key '%s', value '%s', %s\n",
514               debugstr_a(pszSubKey), debugstr_a(pszValue),
515               (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
516
517         datalen = sizeof(data)-1;
518         if (!(retvalue = SHRegGetUSValueA( pszSubKey, pszValue, &type,
519                                            data, &datalen,
520                                            fIgnoreHKCU, 0, 0))) {
521             /* process returned data via type into bool */
522             switch (type) {
523             case REG_SZ:
524                 data[9] = '\0';     /* set end of string */
525                 if (lstrcmpiA(data, "YES") == 0) ret = TRUE;
526                 if (lstrcmpiA(data, "TRUE") == 0) ret = TRUE;
527                 if (lstrcmpiA(data, "NO") == 0) ret = FALSE;
528                 if (lstrcmpiA(data, "FALSE") == 0) ret = FALSE;
529                 break;
530             case REG_DWORD:
531                 work = *(LPDWORD)data;
532                 ret = (work != 0);
533                 break;
534             case REG_BINARY:
535                 if (datalen == 1) {
536                     ret = (data[0] != '\0');
537                     break;
538                 }
539             default:
540                 FIXME("Unsupported registry data type %ld\n", type);
541                 ret = FALSE;
542             }
543             TRACE("got value (type=%ld), returing <%s>\n", type,
544                   (ret) ? "TRUE" : "FALSE");
545         }
546         else {
547             ret = fDefault;
548             TRACE("returning default data <%s>\n",
549                   (ret) ? "TRUE" : "FALSE");
550         }
551         return ret;
552 }
553
554 /*************************************************************************
555  * SHRegGetBoolUSValueW   [SHLWAPI.@]
556  *
557  * See SHRegGetBoolUSValueA.
558  */
559 BOOL WINAPI SHRegGetBoolUSValueW(
560         LPCWSTR pszSubKey,
561         LPCWSTR pszValue,
562         BOOL fIgnoreHKCU,
563         BOOL fDefault)
564 {
565         static const WCHAR wYES[]=  {'Y','E','S','\0'};
566         static const WCHAR wTRUE[]= {'T','R','U','E','\0'};
567         static const WCHAR wNO[]=   {'N','O','\0'};
568         static const WCHAR wFALSE[]={'F','A','L','S','E','\0'};
569         LONG retvalue;
570         DWORD type, datalen, work;
571         BOOL ret = fDefault;
572         WCHAR data[10];
573
574         TRACE("key '%s', value '%s', %s\n",
575               debugstr_w(pszSubKey), debugstr_w(pszValue),
576               (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
577
578         datalen = (sizeof(data)-1) * sizeof(WCHAR);
579         if (!(retvalue = SHRegGetUSValueW( pszSubKey, pszValue, &type,
580                                            data, &datalen,
581                                            fIgnoreHKCU, 0, 0))) {
582             /* process returned data via type into bool */
583             switch (type) {
584             case REG_SZ:
585                 data[9] = L'\0';     /* set end of string */
586                 if (lstrcmpiW(data, wYES)==0 || lstrcmpiW(data, wTRUE)==0)
587                     ret = TRUE;
588                 else if (lstrcmpiW(data, wNO)==0 || lstrcmpiW(data, wFALSE)==0)
589                     ret = FALSE;
590                 break;
591             case REG_DWORD:
592                 work = *(LPDWORD)data;
593                 ret = (work != 0);
594                 break;
595             case REG_BINARY:
596                 if (datalen == 1) {
597                     ret = (data[0] != L'\0');
598                     break;
599                 }
600             default:
601                 FIXME("Unsupported registry data type %ld\n", type);
602                 ret = FALSE;
603             }
604             TRACE("got value (type=%ld), returing <%s>\n", type,
605                   (ret) ? "TRUE" : "FALSE");
606         }
607         else {
608             ret = fDefault;
609             TRACE("returning default data <%s>\n",
610                   (ret) ? "TRUE" : "FALSE");
611         }
612         return ret;
613 }
614
615 /*************************************************************************
616  *      SHRegQueryInfoUSKeyA    [SHLWAPI.@]
617  *
618  * Get information about a user-specific registry key.
619  *
620  * RETURNS
621  *  Success: ERROR_SUCCESS
622  *  Failure: An error code from RegQueryInfoKeyA().
623  */
624 LONG WINAPI SHRegQueryInfoUSKeyA(
625         HUSKEY hUSKey, /* [I] Key to query */
626         LPDWORD pcSubKeys, /* [O] Destination for number of sub keys */
627         LPDWORD pcchMaxSubKeyLen, /* [O] Destination for the length of the biggest sub key name */
628         LPDWORD pcValues, /* [O] Destination for number of values */
629         LPDWORD pcchMaxValueNameLen,/* [O] Destination for the length of the biggest value */
630         SHREGENUM_FLAGS enumRegFlags)  /* [in] SHREGENUM_ flags from "shlwapi.h" */
631 {
632         HKEY dokey;
633         LONG ret;
634
635         TRACE("(0x%lx,%p,%p,%p,%p,%d)\n",
636               (LONG)hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
637               pcchMaxValueNameLen,enumRegFlags);
638
639         /* if user wants HKCU, and it exists, then try it */
640         if (((enumRegFlags == SHREGENUM_HKCU) ||
641              (enumRegFlags == SHREGENUM_DEFAULT)) &&
642             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
643             ret = RegQueryInfoKeyA(dokey, 0, 0, 0,
644                                    pcSubKeys, pcchMaxSubKeyLen, 0,
645                                    pcValues, pcchMaxValueNameLen, 0, 0, 0);
646             if ((ret == ERROR_SUCCESS) ||
647                 (enumRegFlags == SHREGENUM_HKCU))
648                 return ret;
649         }
650         if (((enumRegFlags == SHREGENUM_HKLM) ||
651              (enumRegFlags == SHREGENUM_DEFAULT)) &&
652             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
653             return RegQueryInfoKeyA(dokey, 0, 0, 0,
654                                     pcSubKeys, pcchMaxSubKeyLen, 0,
655                                     pcValues, pcchMaxValueNameLen, 0, 0, 0);
656         }
657         return ERROR_INVALID_FUNCTION;
658 }
659
660 /*************************************************************************
661  *      SHRegQueryInfoUSKeyW    [SHLWAPI.@]
662  *
663  * See SHRegQueryInfoUSKeyA.
664  */
665 LONG WINAPI SHRegQueryInfoUSKeyW(
666         HUSKEY hUSKey,
667         LPDWORD pcSubKeys,
668         LPDWORD pcchMaxSubKeyLen,
669         LPDWORD pcValues,
670         LPDWORD pcchMaxValueNameLen,
671         SHREGENUM_FLAGS enumRegFlags)
672 {
673         HKEY dokey;
674         LONG ret;
675
676         TRACE("(0x%lx,%p,%p,%p,%p,%d)\n",
677               (LONG)hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
678               pcchMaxValueNameLen,enumRegFlags);
679
680         /* if user wants HKCU, and it exists, then try it */
681         if (((enumRegFlags == SHREGENUM_HKCU) ||
682              (enumRegFlags == SHREGENUM_DEFAULT)) &&
683             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
684             ret = RegQueryInfoKeyW(dokey, 0, 0, 0,
685                                    pcSubKeys, pcchMaxSubKeyLen, 0,
686                                    pcValues, pcchMaxValueNameLen, 0, 0, 0);
687             if ((ret == ERROR_SUCCESS) ||
688                 (enumRegFlags == SHREGENUM_HKCU))
689                 return ret;
690         }
691         if (((enumRegFlags == SHREGENUM_HKLM) ||
692              (enumRegFlags == SHREGENUM_DEFAULT)) &&
693             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
694             return RegQueryInfoKeyW(dokey, 0, 0, 0,
695                                     pcSubKeys, pcchMaxSubKeyLen, 0,
696                                     pcValues, pcchMaxValueNameLen, 0, 0, 0);
697         }
698         return ERROR_INVALID_FUNCTION;
699 }
700
701 /*************************************************************************
702  *      SHRegEnumUSKeyA         [SHLWAPI.@]
703  *
704  * Enumerate a user-specific registry key.
705  *
706  * RETURNS
707  *  Success: ERROR_SUCCESS
708  *  Failure: An error code from RegEnumKeyExA().
709  */
710 LONG WINAPI SHRegEnumUSKeyA(
711         HUSKEY hUSKey,                 /* [in] Key to enumerate */
712         DWORD dwIndex,                 /* [in] Index within hUSKey */
713         LPSTR pszName,                 /* [out] Name of the enumerated value */
714         LPDWORD pcchValueNameLen,      /* [in/out] Length of pszName */
715         SHREGENUM_FLAGS enumRegFlags)  /* [in] SHREGENUM_ flags from "shlwapi.h" */
716 {
717         HKEY dokey;
718
719         TRACE("(0x%lx,%ld,%p,%p(%ld),%d)\n",
720               (LONG)hUSKey, dwIndex, pszName, pcchValueNameLen,
721               *pcchValueNameLen, enumRegFlags);
722
723         if (((enumRegFlags == SHREGENUM_HKCU) ||
724              (enumRegFlags == SHREGENUM_DEFAULT)) &&
725             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
726             return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
727                                 0, 0, 0, 0);
728         }
729
730         if (((enumRegFlags == SHREGENUM_HKLM) ||
731              (enumRegFlags == SHREGENUM_DEFAULT)) &&
732             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
733             return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
734                                 0, 0, 0, 0);
735         }
736         FIXME("no support for SHREGENUM_BOTH\n");
737         return ERROR_INVALID_FUNCTION;
738 }
739
740 /*************************************************************************
741  *      SHRegEnumUSKeyW         [SHLWAPI.@]
742  *
743  * See SHRegEnumUSKeyA.
744  */
745 LONG WINAPI SHRegEnumUSKeyW(
746         HUSKEY hUSKey,
747         DWORD dwIndex,
748         LPWSTR pszName,
749         LPDWORD pcchValueNameLen,
750         SHREGENUM_FLAGS enumRegFlags)
751 {
752         HKEY dokey;
753
754         TRACE("(0x%lx,%ld,%p,%p(%ld),%d)\n",
755               (LONG)hUSKey, dwIndex, pszName, pcchValueNameLen,
756               *pcchValueNameLen, enumRegFlags);
757
758         if (((enumRegFlags == SHREGENUM_HKCU) ||
759              (enumRegFlags == SHREGENUM_DEFAULT)) &&
760             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
761             return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
762                                 0, 0, 0, 0);
763         }
764
765         if (((enumRegFlags == SHREGENUM_HKLM) ||
766              (enumRegFlags == SHREGENUM_DEFAULT)) &&
767             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
768             return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
769                                 0, 0, 0, 0);
770         }
771         FIXME("no support for SHREGENUM_BOTH\n");
772         return ERROR_INVALID_FUNCTION;
773 }
774
775 /*************************************************************************
776  *      SHRegWriteUSValueA      [SHLWAPI.@]
777  *
778  *
779  */
780 LONG  WINAPI SHRegWriteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, DWORD dwType,
781                                 LPVOID pvData, DWORD cbData, DWORD dwFlags)
782 {
783     HKEY dokey;
784
785     TRACE("(0x%lx,%s,%ld,%p,%ld,%ld)\n",
786           (LONG)hUSKey, debugstr_a(pszValue), dwType, pvData, cbData, dwFlags);
787
788     if ((dwFlags & SHREGSET_FORCE_HKCU) &&
789             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
790         RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
791     }
792
793     if ((dwFlags & SHREGSET_FORCE_HKLM) &&
794             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
795         RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
796     }
797
798     if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM))
799         return ERROR_SUCCESS;
800
801     FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
802     return ERROR_SUCCESS;
803 }
804
805 /*************************************************************************
806  *      SHRegWriteUSValueW      [SHLWAPI.@]
807  *
808  * See SHRegWriteUSValueA.
809  */
810 LONG  WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, DWORD dwType,
811                                 LPVOID pvData, DWORD cbData, DWORD dwFlags)
812 {
813     HKEY dokey;
814
815     TRACE("(0x%lx,%s,%ld,%p,%ld,%ld)\n",
816           (LONG)hUSKey, debugstr_w(pszValue), dwType, pvData, cbData, dwFlags);
817
818     if ((dwFlags & SHREGSET_FORCE_HKCU) &&
819             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
820         RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
821     }
822
823     if ((dwFlags & SHREGSET_FORCE_HKLM) &&
824             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
825         RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
826     }
827
828     if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM))
829         return ERROR_SUCCESS;
830
831     FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
832     return ERROR_SUCCESS;
833 }
834
835 /*************************************************************************
836  * SHRegGetPathA   [SHLWAPI.@]
837  *
838  * Get a path from the registry.
839  *
840  * PARAMS
841  *   hKey       [I] Handle to registry key
842  *   lpszSubKey [I] Name of sub key containing path to get
843  *   lpszValue  [I] Name of value containing path to get
844  *   lpszPath   [O] Buffer for returned path
845  *   dwFlags    [I] Reserved
846  *
847  * RETURNS
848  *   Success: ERROR_SUCCESS. lpszPath contains the path.
849  *   Failure: An error code from RegOpenKeyExA() or SHQueryValueExA().
850  */
851 DWORD WINAPI SHRegGetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
852                            LPSTR lpszPath, DWORD dwFlags)
853 {
854   DWORD dwSize = MAX_PATH;
855
856   TRACE("(hkey=%p,%s,%s,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
857         debugstr_a(lpszValue), lpszPath, dwFlags);
858
859   return SHGetValueA(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize);
860 }
861
862 /*************************************************************************
863  * SHRegGetPathW   [SHLWAPI.@]
864  *
865  * See SHRegGetPathA.
866  */
867 DWORD WINAPI SHRegGetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
868                            LPWSTR lpszPath, DWORD dwFlags)
869 {
870   DWORD dwSize = MAX_PATH;
871
872   TRACE("(hkey=%p,%s,%s,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
873         debugstr_w(lpszValue), lpszPath, dwFlags);
874
875   return SHGetValueW(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize);
876 }
877
878
879 /*************************************************************************
880  * SHRegSetPathA   [SHLWAPI.@]
881  *
882  * Write a path to the registry.
883  *
884  * PARAMS
885  *   hKey       [I] Handle to registry key
886  *   lpszSubKey [I] Name of sub key containing path to set
887  *   lpszValue  [I] Name of value containing path to set
888  *   lpszPath   [O] Path to write
889  *   dwFlags    [I] Reserved, must be 0.
890  *
891  * RETURNS
892  *   Success: ERROR_SUCCESS.
893  *   Failure: An error code from SHSetValueA.
894  */
895 DWORD WINAPI SHRegSetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
896                            LPCSTR lpszPath, DWORD dwFlags)
897 {
898   char szBuff[MAX_PATH];
899
900   FIXME("(hkey=%p,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_a(lpszSubKey),
901         debugstr_a(lpszValue), lpszPath, dwFlags);
902
903   lstrcpyA(szBuff, lpszPath);
904
905   /* FIXME: PathUnExpandEnvStringsA(szBuff); */
906
907   return SHSetValueA(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
908                      lstrlenA(szBuff));
909 }
910
911 /*************************************************************************
912  * SHRegSetPathW   [SHLWAPI.@]
913  *
914  * See SHRegSetPathA.
915  */
916 DWORD WINAPI SHRegSetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
917                            LPCWSTR lpszPath, DWORD dwFlags)
918 {
919   WCHAR szBuff[MAX_PATH];
920
921   FIXME("(hkey=%p,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_w(lpszSubKey),
922         debugstr_w(lpszValue), lpszPath, dwFlags);
923
924   lstrcpyW(szBuff, lpszPath);
925
926   /* FIXME: PathUnExpandEnvStringsW(szBuff); */
927
928   return SHSetValueW(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
929                      lstrlenW(szBuff));
930 }
931
932 /*************************************************************************
933  * SHGetValueA   [SHLWAPI.@]
934  *
935  * Get a value from the registry.
936  *
937  * PARAMS
938  *   hKey       [I] Handle to registry key
939  *   lpszSubKey [I] Name of sub key containing value to get
940  *   lpszValue  [I] Name of value to get
941  *   pwType     [O] Pointer to the values type
942  *   pvData     [O] Pointer to the values data
943  *   pcbData    [O] Pointer to the values size
944  *
945  * RETURNS
946  *   Success: ERROR_SUCCESS. Output parameters contain the details read.
947  *   Failure: An error code from RegOpenKeyExA() or SHQueryValueExA().
948  */
949 DWORD WINAPI SHGetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
950                          LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
951 {
952   DWORD dwRet = 0;
953   HKEY hSubKey = 0;
954
955   TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_a(lpszSubKey),
956         debugstr_a(lpszValue), pwType, pvData, pcbData);
957
958   /*   lpszSubKey can be 0. In this case the value is taken from the
959    *   current key.
960    */
961   if(lpszSubKey)
962     dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
963
964   if (! dwRet)
965   {
966     /* SHQueryValueEx expands Environment strings */
967     dwRet = SHQueryValueExA(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData);
968     if (hSubKey) RegCloseKey(hSubKey);
969   }
970   return dwRet;
971 }
972
973 /*************************************************************************
974  * SHGetValueW   [SHLWAPI.@]
975  *
976  * See SHGetValueA.
977  */
978 DWORD WINAPI SHGetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
979                          LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
980 {
981   DWORD dwRet = 0;
982   HKEY hSubKey = 0;
983
984   TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_w(lpszSubKey),
985         debugstr_w(lpszValue), pwType, pvData, pcbData);
986
987   if(lpszSubKey)
988     dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
989
990   if (! dwRet)
991   {
992     dwRet = SHQueryValueExW(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData);
993     if (hSubKey) RegCloseKey(hSubKey);
994   }
995   return dwRet;
996 }
997
998 /*************************************************************************
999  * SHSetValueA   [SHLWAPI.@]
1000  *
1001  * Set a value in the registry.
1002  *
1003  * PARAMS
1004  *   hKey       [I] Handle to registry key
1005  *   lpszSubKey [I] Name of sub key under hKey
1006  *   lpszValue  [I] Name of value to set
1007  *   dwType     [I] Type of the value
1008  *   pvData     [I] Data of the value
1009  *   cbData     [I] Size of the value
1010  *
1011  * RETURNS
1012  *   Success: ERROR_SUCCESS. The value is set with the data given.
1013  *   Failure: An error code from RegCreateKeyExA() or RegSetValueExA()
1014  *
1015  * NOTES
1016  *   If lpszSubKey does not exist, it is created before the value is set. If
1017  *   lpszSubKey is NULL or an empty string, then the value is added directly
1018  *   to hKey instead.
1019  */
1020 DWORD WINAPI SHSetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
1021                          DWORD dwType, LPCVOID pvData, DWORD cbData)
1022 {
1023   DWORD dwRet = ERROR_SUCCESS, dwDummy;
1024   HKEY  hSubKey;
1025   LPSTR szEmpty = "";
1026
1027   TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
1028           debugstr_a(lpszValue), dwType, pvData, cbData);
1029
1030   if (lpszSubKey && *lpszSubKey)
1031     dwRet = RegCreateKeyExA(hKey, lpszSubKey, 0, szEmpty,
1032                             0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
1033   else
1034     hSubKey = hKey;
1035   if (!dwRet)
1036   {
1037     dwRet = RegSetValueExA(hSubKey, lpszValue, 0, dwType, pvData, cbData);
1038     if (hSubKey != hKey)
1039       RegCloseKey(hSubKey);
1040   }
1041   return dwRet;
1042 }
1043
1044 /*************************************************************************
1045  * SHSetValueW   [SHLWAPI.@]
1046  *
1047  * See SHSetValueA.
1048  */
1049 DWORD WINAPI SHSetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
1050                          DWORD dwType, LPCVOID pvData, DWORD cbData)
1051 {
1052   DWORD dwRet = ERROR_SUCCESS, dwDummy;
1053   HKEY  hSubKey;
1054   WCHAR szEmpty[] = { '\0' };
1055
1056   TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
1057         debugstr_w(lpszValue), dwType, pvData, cbData);
1058
1059   if (lpszSubKey && *lpszSubKey)
1060     dwRet = RegCreateKeyExW(hKey, lpszSubKey, 0, szEmpty,
1061                             0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
1062   else
1063     hSubKey = hKey;
1064   if (!dwRet)
1065   {
1066     dwRet = RegSetValueExW(hSubKey, lpszValue, 0, dwType, pvData, cbData);
1067     if (hSubKey != hKey)
1068       RegCloseKey(hSubKey);
1069   }
1070   return dwRet;
1071 }
1072
1073 /*************************************************************************
1074  * SHQueryInfoKeyA   [SHLWAPI.@]
1075  *
1076  * Get information about a registry key. See RegQueryInfoKeyA().
1077  */
1078 LONG WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
1079                             LPDWORD pwValues, LPDWORD pwValueMax)
1080 {
1081   TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
1082         pwValues, pwValueMax);
1083   return RegQueryInfoKeyA(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
1084                           NULL, pwValues, pwValueMax, NULL, NULL, NULL);
1085 }
1086
1087 /*************************************************************************
1088  * SHQueryInfoKeyW   [SHLWAPI.@]
1089  *
1090  * See SHQueryInfoKeyA
1091  */
1092 LONG WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
1093                             LPDWORD pwValues, LPDWORD pwValueMax)
1094 {
1095   TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
1096         pwValues, pwValueMax);
1097   return RegQueryInfoKeyW(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
1098                           NULL, pwValues, pwValueMax, NULL, NULL, NULL);
1099 }
1100
1101 /*************************************************************************
1102  * SHQueryValueExA   [SHLWAPI.@]
1103  *
1104  * Get a value from the registry, expanding environment variable strings.
1105  *
1106  * PARAMS
1107  *   hKey       [I] Handle to registry key
1108  *   lpszValue  [I] Name of value to query
1109  *   lpReserved [O] Reserved for future use; must be NULL
1110  *   pwType     [O] Optional pointer updated with the values type
1111  *   pvData     [O] Optional pointer updated with the values data
1112  *   pcbData    [O] Optional pointer updated with the values size
1113  *
1114  * RETURNS
1115  *   Success: ERROR_SUCCESS. Any non NULL output parameters are updated with
1116  *            information about the value.
1117  *   Failure: ERROR_OUTOFMEMORY if memory allocation fails, or the type of the
1118  *            data is REG_EXPAND_SZ and pcbData is NULL. Otherwise an error
1119  *            code from RegQueryValueExA() or ExpandEnvironmentStringsA().
1120  *
1121  * NOTES
1122  *   Either pwType, pvData or pcbData may be NULL if the caller doesn't want
1123  *   the type, data or size information for the value.
1124  *
1125  *   If the type of the data is REG_EXPAND_SZ, it is expanded to REG_SZ. The
1126  *   value returned will be truncated if it is of type REG_SZ and bigger than
1127  *   the buffer given to store it.
1128  *
1129  *   REG_EXPAND_SZ:
1130  *     case-1: the unexpanded string is smaller than the expanded one
1131  *       subcase-1: the buffer is to small to hold the unexpanded string:
1132  *          function fails and returns the size of the unexpanded string.
1133  *
1134  *       subcase-2: buffer is to small to hold the expanded string:
1135  *          the function return success (!!) and the result is truncated
1136  *          *** This is clearly a error in the native implementation. ***
1137  *
1138  *     case-2: the unexpanded string is bigger than the expanded one
1139  *       The buffer must have enough space to hold the unexpanded
1140  *       string even if the result is smaller.
1141  *
1142  */
1143 DWORD WINAPI SHQueryValueExA( HKEY hKey, LPCSTR lpszValue,
1144                               LPDWORD lpReserved, LPDWORD pwType,
1145                               LPVOID pvData, LPDWORD pcbData)
1146 {
1147   DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen;
1148
1149   TRACE("(hkey=%p,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_a(lpszValue),
1150         lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1151
1152   if (pcbData) dwUnExpDataLen = *pcbData;
1153
1154   dwRet = RegQueryValueExA(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen);
1155
1156   if (pcbData && (dwType == REG_EXPAND_SZ))
1157   {
1158     DWORD nBytesToAlloc;
1159
1160     /* Expand type REG_EXPAND_SZ into REG_SZ */
1161     LPSTR szData;
1162
1163     /* If the caller didn't supply a buffer or the buffer is to small we have
1164      * to allocate our own
1165      */
1166     if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
1167     {
1168       char cNull = '\0';
1169       nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData;
1170
1171       szData = (LPSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc);
1172       RegQueryValueExA (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
1173       dwExpDataLen = ExpandEnvironmentStringsA(szData, &cNull, 1);
1174       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1175       LocalFree((HLOCAL) szData);
1176     }
1177     else
1178     {
1179       nBytesToAlloc = lstrlenA(pvData) * sizeof (CHAR);
1180       szData = (LPSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc + 1);
1181       lstrcpyA(szData, pvData);
1182       dwExpDataLen = ExpandEnvironmentStringsA(szData, pvData, *pcbData / sizeof(CHAR));
1183       if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
1184       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1185       LocalFree((HLOCAL) szData);
1186     }
1187   }
1188
1189   /* Update the type and data size if the caller wanted them */
1190   if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ;
1191   if ( pwType ) *pwType = dwType;
1192   if ( pcbData ) *pcbData = dwUnExpDataLen;
1193   return dwRet;
1194 }
1195
1196
1197 /*************************************************************************
1198  * SHQueryValueExW   [SHLWAPI.@]
1199  *
1200  * See SHQueryValueExA.
1201  */
1202 DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue,
1203                              LPDWORD lpReserved, LPDWORD pwType,
1204                              LPVOID pvData, LPDWORD pcbData)
1205 {
1206   DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen;
1207
1208   TRACE("(hkey=%p,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_w(lpszValue),
1209         lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1210
1211   if (pcbData) dwUnExpDataLen = *pcbData;
1212
1213   dwRet = RegQueryValueExW(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen);
1214
1215   if (pcbData && (dwType == REG_EXPAND_SZ))
1216   {
1217     DWORD nBytesToAlloc;
1218
1219     /* Expand type REG_EXPAND_SZ into REG_SZ */
1220     LPWSTR szData;
1221
1222     /* If the caller didn't supply a buffer or the buffer is to small we have
1223      * to allocate our own
1224      */
1225     if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
1226     {
1227       WCHAR cNull = '\0';
1228       nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData;
1229
1230       szData = (LPWSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc);
1231       RegQueryValueExW (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
1232       dwExpDataLen = ExpandEnvironmentStringsW(szData, &cNull, 1);
1233       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1234       LocalFree((HLOCAL) szData);
1235     }
1236     else
1237     {
1238       nBytesToAlloc = lstrlenW(pvData) * sizeof(WCHAR);
1239       szData = (LPWSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc + 1);
1240       lstrcpyW(szData, pvData);
1241       dwExpDataLen = ExpandEnvironmentStringsW(szData, pvData, *pcbData/sizeof(WCHAR) );
1242       if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
1243       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1244       LocalFree((HLOCAL) szData);
1245     }
1246   }
1247
1248   /* Update the type and data size if the caller wanted them */
1249   if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ;
1250   if ( pwType ) *pwType = dwType;
1251   if ( pcbData ) *pcbData = dwUnExpDataLen;
1252   return dwRet;
1253 }
1254
1255 /*************************************************************************
1256  * SHDeleteKeyA   [SHLWAPI.@]
1257  *
1258  * Delete a registry key and any sub keys/values present
1259  *
1260  * PARAMS
1261  *   hKey       [I] Handle to registry key
1262  *   lpszSubKey [I] Name of sub key to delete
1263  *
1264  * RETURNS
1265  *   Success: ERROR_SUCCESS. The key is deleted.
1266  *   Failure: An error code from RegOpenKeyExA(), RegQueryInfoKeyA(),
1267  *            RegEnumKeyExA() or RegDeleteKeyA().
1268  */
1269 DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey)
1270 {
1271   DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1272   CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1273   HKEY hSubKey = 0;
1274
1275   TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey));
1276
1277   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1278   if(!dwRet)
1279   {
1280     /* Find how many subkeys there are */
1281     dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1282                              &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1283     if(!dwRet)
1284     {
1285       dwMaxSubkeyLen++;
1286       if (dwMaxSubkeyLen > sizeof(szNameBuf))
1287         /* Name too big: alloc a buffer for it */
1288         lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(CHAR));
1289
1290       if(!lpszName)
1291         dwRet = ERROR_NOT_ENOUGH_MEMORY;
1292       else
1293       {
1294         /* Recursively delete all the subkeys */
1295         for(i = 0; i < dwKeyCount && !dwRet; i++)
1296         {
1297           dwSize = dwMaxSubkeyLen;
1298           dwRet = RegEnumKeyExA(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1299           if(!dwRet)
1300             dwRet = SHDeleteKeyA(hSubKey, lpszName);
1301         }
1302         if (lpszName != szNameBuf)
1303           HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1304       }
1305     }
1306
1307     RegCloseKey(hSubKey);
1308     if(!dwRet)
1309       dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1310   }
1311   return dwRet;
1312 }
1313
1314 /*************************************************************************
1315  * SHDeleteKeyW   [SHLWAPI.@]
1316  *
1317  * See SHDeleteKeyA.
1318  */
1319 DWORD WINAPI SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1320 {
1321   DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1322   WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1323   HKEY hSubKey = 0;
1324
1325   TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1326
1327   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1328   if(!dwRet)
1329   {
1330     /* Find how many subkeys there are */
1331     dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1332                              &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1333     if(!dwRet)
1334     {
1335       dwMaxSubkeyLen++;
1336       if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1337         /* Name too big: alloc a buffer for it */
1338         lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1339
1340       if(!lpszName)
1341         dwRet = ERROR_NOT_ENOUGH_MEMORY;
1342       else
1343       {
1344         /* Recursively delete all the subkeys */
1345         for(i = 0; i < dwKeyCount && !dwRet; i++)
1346         {
1347           dwSize = dwMaxSubkeyLen;
1348           dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1349           if(!dwRet)
1350             dwRet = SHDeleteKeyW(hSubKey, lpszName);
1351         }
1352
1353         if (lpszName != szNameBuf)
1354           HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1355       }
1356     }
1357
1358     RegCloseKey(hSubKey);
1359     if(!dwRet)
1360       dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1361   }
1362   return dwRet;
1363 }
1364
1365 /*************************************************************************
1366  * SHDeleteEmptyKeyA   [SHLWAPI.@]
1367  *
1368  * Delete a registry key with no sub keys.
1369  *
1370  * PARAMS
1371  *   hKey       [I] Handle to registry key
1372  *   lpszSubKey [I] Name of sub key to delete
1373  *
1374  * RETURNS
1375  *   Success: ERROR_SUCCESS. The key is deleted.
1376  *   Failure: If the key is not empty, returns ERROR_KEY_HAS_CHILDREN. Otherwise
1377  *            returns an error code from RegOpenKeyExA(), RegQueryInfoKeyA() or
1378  *            RegDeleteKeyA().
1379  */
1380 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hKey, LPCSTR lpszSubKey)
1381 {
1382   DWORD dwRet, dwKeyCount = 0;
1383   HKEY hSubKey = 0;
1384
1385   TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey));
1386
1387   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1388   if(!dwRet)
1389   {
1390     dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1391                              NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1392     RegCloseKey(hSubKey);
1393     if(!dwRet)
1394     {
1395       if (!dwKeyCount)
1396         dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1397       else
1398         dwRet = ERROR_KEY_HAS_CHILDREN;
1399     }
1400   }
1401   return dwRet;
1402 }
1403
1404 /*************************************************************************
1405  * SHDeleteEmptyKeyW   [SHLWAPI.@]
1406  *
1407  * See SHDeleteEmptyKeyA.
1408  */
1409 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1410 {
1411   DWORD dwRet, dwKeyCount = 0;
1412   HKEY hSubKey = 0;
1413
1414   TRACE("(hkey=%p, %s)\n", hKey, debugstr_w(lpszSubKey));
1415
1416   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1417   if(!dwRet)
1418   {
1419     dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1420                              NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1421     RegCloseKey(hSubKey);
1422     if(!dwRet)
1423     {
1424       if (!dwKeyCount)
1425         dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1426       else
1427         dwRet = ERROR_KEY_HAS_CHILDREN;
1428     }
1429   }
1430   return dwRet;
1431 }
1432
1433 /*************************************************************************
1434  * SHDeleteOrphanKeyA   [SHLWAPI.@]
1435  *
1436  * Delete a registry key with no sub keys or values.
1437  *
1438  * PARAMS
1439  *   hKey       [I] Handle to registry key
1440  *   lpszSubKey [I] Name of sub key to possibly delete
1441  *
1442  * RETURNS
1443  *   Success: ERROR_SUCCESS. The key has been deleted if it was an orphan.
1444  *   Failure: An error from RegOpenKeyExA(), RegQueryValueExA(), or RegDeleteKeyA().
1445  */
1446 DWORD WINAPI SHDeleteOrphanKeyA(HKEY hKey, LPCSTR lpszSubKey)
1447 {
1448   HKEY hSubKey;
1449   DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
1450
1451   TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey));
1452
1453   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1454
1455   if(!dwRet)
1456   {
1457     /* Get subkey and value count */
1458     dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1459                              NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
1460
1461     if(!dwRet && !dwKeyCount && !dwValueCount)
1462     {
1463       dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1464     }
1465     RegCloseKey(hSubKey);
1466   }
1467   return dwRet;
1468 }
1469
1470 /*************************************************************************
1471  * SHDeleteOrphanKeyW   [SHLWAPI.@]
1472  *
1473  * See SHDeleteOrphanKeyA.
1474  */
1475 DWORD WINAPI SHDeleteOrphanKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1476 {
1477   HKEY hSubKey;
1478   DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
1479
1480   TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1481
1482   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1483
1484   if(!dwRet)
1485   {
1486     /* Get subkey and value count */
1487     dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1488                              NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
1489
1490     if(!dwRet && !dwKeyCount && !dwValueCount)
1491     {
1492       dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1493     }
1494     RegCloseKey(hSubKey);
1495   }
1496   return dwRet;
1497 }
1498
1499 /*************************************************************************
1500  * SHDeleteValueA   [SHLWAPI.@]
1501  *
1502  * Delete a value from the registry.
1503  *
1504  * PARAMS
1505  *   hKey       [I] Handle to registry key
1506  *   lpszSubKey [I] Name of sub key containing value to delete
1507  *   lpszValue  [I] Name of value to delete
1508  *
1509  * RETURNS
1510  *   Success: ERROR_SUCCESS. The value is deleted.
1511  *   Failure: An error code from RegOpenKeyExA() or RegDeleteValueA().
1512  */
1513 DWORD WINAPI SHDeleteValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue)
1514 {
1515   DWORD dwRet;
1516   HKEY hSubKey;
1517
1518   TRACE("(hkey=%p,%s,%s)\n", hKey, debugstr_a(lpszSubKey), debugstr_a(lpszValue));
1519
1520   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey);
1521   if (!dwRet)
1522   {
1523     dwRet = RegDeleteValueA(hSubKey, lpszValue);
1524     RegCloseKey(hSubKey);
1525   }
1526   return dwRet;
1527 }
1528
1529 /*************************************************************************
1530  * SHDeleteValueW   [SHLWAPI.@]
1531  *
1532  * See SHDeleteValueA.
1533  */
1534 DWORD WINAPI SHDeleteValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue)
1535 {
1536   DWORD dwRet;
1537   HKEY hSubKey;
1538
1539   TRACE("(hkey=%p,%s,%s)\n", hKey, debugstr_w(lpszSubKey), debugstr_w(lpszValue));
1540
1541   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey);
1542   if (!dwRet)
1543   {
1544     dwRet = RegDeleteValueW(hSubKey, lpszValue);
1545     RegCloseKey(hSubKey);
1546   }
1547   return dwRet;
1548 }
1549
1550 /*************************************************************************
1551  * SHEnumKeyExA   [SHLWAPI.@]
1552  *
1553  * Enumerate sub keys in a registry key.
1554  *
1555  * PARAMS
1556  *   hKey       [I] Handle to registry key
1557  *   dwIndex    [I] Index of key to enumerate
1558  *   lpszSubKey [O] Pointer updated with the subkey name
1559  *   pwLen      [O] Pointer updated with the subkey length
1560  *
1561  * RETURN
1562  *   Success: ERROR_SUCCESS. lpszSubKey and pwLen are updated.
1563  *   Failure: An error code from RegEnumKeyExA().
1564  */
1565 LONG WINAPI SHEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpszSubKey,
1566                          LPDWORD pwLen)
1567 {
1568   TRACE("(hkey=%p,%ld,%s,%p)\n", hKey, dwIndex, debugstr_a(lpszSubKey), pwLen);
1569
1570   return RegEnumKeyExA(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL);
1571 }
1572
1573 /*************************************************************************
1574  * SHEnumKeyExW   [SHLWAPI.@]
1575  *
1576  * See SHEnumKeyExA.
1577  */
1578 LONG WINAPI SHEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpszSubKey,
1579                          LPDWORD pwLen)
1580 {
1581   TRACE("(hkey=%p,%ld,%s,%p)\n", hKey, dwIndex, debugstr_w(lpszSubKey), pwLen);
1582
1583   return RegEnumKeyExW(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL);
1584 }
1585
1586 /*************************************************************************
1587  * SHEnumValueA   [SHLWAPI.@]
1588  *
1589  * Enumerate values in a registry key.
1590  *
1591  * PARAMS
1592  *   hKey      [I] Handle to registry key
1593  *   dwIndex   [I] Index of key to enumerate
1594  *   lpszValue [O] Pointer updated with the values name
1595  *   pwLen     [O] Pointer updated with the values length
1596  *   pwType    [O] Pointer updated with the values type
1597  *   pvData    [O] Pointer updated with the values data
1598  *   pcbData   [O] Pointer updated with the values size
1599  *
1600  * RETURNS
1601  *   Success: ERROR_SUCCESS. Output parameters are updated.
1602  *   Failure: An error code from RegEnumValueA().
1603  */
1604 LONG WINAPI SHEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpszValue,
1605                          LPDWORD pwLen, LPDWORD pwType,
1606                          LPVOID pvData, LPDWORD pcbData)
1607 {
1608   TRACE("(hkey=%p,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
1609         debugstr_a(lpszValue), pwLen, pwType, pvData, pcbData);
1610
1611   return RegEnumValueA(hKey, dwIndex, lpszValue, pwLen, NULL,
1612                        pwType, pvData, pcbData);
1613 }
1614
1615 /*************************************************************************
1616  * SHEnumValueW   [SHLWAPI.@]
1617  *
1618  * See SHEnumValueA.
1619  */
1620 LONG WINAPI SHEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpszValue,
1621                          LPDWORD pwLen, LPDWORD pwType,
1622                          LPVOID pvData, LPDWORD pcbData)
1623 {
1624   TRACE("(hkey=%p,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
1625         debugstr_w(lpszValue), pwLen, pwType, pvData, pcbData);
1626
1627   return RegEnumValueW(hKey, dwIndex, lpszValue, pwLen, NULL,
1628                        pwType, pvData, pcbData);
1629 }
1630
1631 /*************************************************************************
1632  * @   [SHLWAPI.205]
1633  *
1634  * Get a value from the registry.
1635  *
1636  * PARAMS
1637  *   hKey    [I] Handle to registry key
1638  *   pSubKey [I] Name of sub key containing value to get
1639  *   pValue  [I] Name of value to get
1640  *   pwType  [O] Destination for the values type
1641  *   pvData  [O] Destination for the values data
1642  *   pbData  [O] Destination for the values size
1643  *
1644  * RETURNS
1645  *   Success: ERROR_SUCCESS. Output parameters contain the details read.
1646  *   Failure: An error code from RegOpenKeyExA() or SHQueryValueExA(),
1647  *            or ERROR_INVALID_FUNCTION in the machine is in safe mode.
1648  */
1649 DWORD WINAPI SHLWAPI_205(HKEY hkey, LPCSTR pSubKey, LPCSTR pValue,
1650                          LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
1651 {
1652   if (GetSystemMetrics(SM_CLEANBOOT))
1653     return ERROR_INVALID_FUNCTION;
1654   return SHGetValueA(hkey, pSubKey, pValue, pwType, pvData, pbData);
1655 }
1656
1657 /*************************************************************************
1658  * @   [SHLWAPI.206]
1659  *
1660  * Unicode version of SHLWAPI_205.
1661  */
1662 DWORD WINAPI SHLWAPI_206(HKEY hkey, LPCWSTR pSubKey, LPCWSTR pValue,
1663                          LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
1664 {
1665   if (GetSystemMetrics(SM_CLEANBOOT))
1666     return ERROR_INVALID_FUNCTION;
1667   return SHGetValueW(hkey, pSubKey, pValue, pwType, pvData, pbData);
1668 }
1669
1670 /*************************************************************************
1671  * @   [SHLWAPI.320]
1672  *
1673  * Set a MIME content type in the registry.
1674  *
1675  * PARAMS
1676  *   hKey       [I] Handle to registry key
1677  *   lpszSubKey [I] Name of sub key under hKey
1678  *   lpszValue  [I] Value to set
1679  *
1680  * RETURNS
1681  *   Success: TRUE
1682  *   Failure: FALSE
1683  */
1684 BOOL WINAPI SHLWAPI_320(LPCSTR lpszSubKey, LPCSTR lpszValue)
1685 {
1686   DWORD dwRet;
1687
1688   if (!lpszValue)
1689   {
1690     WARN("Invalid lpszValue would crash under Win32!\n");
1691     return FALSE;
1692   }
1693
1694   dwRet = SHSetValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA,
1695                       REG_SZ, lpszValue, strlen(lpszValue));
1696   return dwRet ? FALSE : TRUE;
1697 }
1698
1699 /*************************************************************************
1700  * @   [SHLWAPI.321]
1701  *
1702  * Unicode version of SHLWAPI_320.
1703  */
1704 BOOL WINAPI SHLWAPI_321(LPCWSTR lpszSubKey, LPCWSTR lpszValue)
1705 {
1706   DWORD dwRet;
1707
1708   if (!lpszValue)
1709   {
1710     WARN("Invalid lpszValue would crash under Win32!\n");
1711     return FALSE;
1712   }
1713
1714   dwRet = SHSetValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW,
1715                       REG_SZ, lpszValue, strlenW(lpszValue));
1716   return dwRet ? FALSE : TRUE;
1717 }
1718
1719 /*************************************************************************
1720  * @   [SHLWAPI.322]
1721  *
1722  * Delete a MIME content type from the registry.
1723  *
1724  * PARAMS
1725  *   lpszSubKey [I] Name of sub key
1726  *
1727  * RETURNS
1728  *   Success: TRUE
1729  *   Failure: FALSE
1730  */
1731 BOOL WINAPI SHLWAPI_322(LPCSTR lpszSubKey)
1732 {
1733   HRESULT ret = SHDeleteValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA);
1734   return ret ? FALSE : TRUE;
1735 }
1736
1737 /*************************************************************************
1738  * @   [SHLWAPI.323]
1739  *
1740  * Unicode version of SHLWAPI_322.
1741  */
1742 BOOL WINAPI SHLWAPI_323(LPCWSTR lpszSubKey)
1743 {
1744   HRESULT ret = SHDeleteValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW);
1745   return ret ? FALSE : TRUE;
1746 }
1747
1748 /*************************************************************************
1749  * @   [SHLWAPI.328]
1750  *
1751  * Get the registry path to a MIME content key.
1752  *
1753  * PARAMS
1754  *   lpszType   [I] Content type to get the path for
1755  *   lpszBuffer [O] Destination for path
1756  *   dwLen      [I] Length of lpszBuffer
1757  *
1758  * RETURNS
1759  *   Success: TRUE. lpszBuffer contains the full path.
1760  *   Failure: FALSE.
1761  *
1762  * NOTES
1763  *   The base path for the key is "MIME\Database\Content Type\"
1764  */
1765 BOOL WINAPI SHLWAPI_328(LPCSTR lpszType, LPSTR lpszBuffer, DWORD dwLen)
1766 {
1767   TRACE("(%s,%p,%ld)\n", debugstr_a(lpszType), lpszBuffer, dwLen);
1768
1769   if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer)
1770   {
1771     DWORD dwStrLen = strlen(lpszType);
1772
1773     if (dwStrLen < dwLen - dwLenMimeDbContent)
1774     {
1775       memcpy(lpszBuffer, szMimeDbContentA, dwLenMimeDbContent);
1776       memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, dwStrLen + 1);
1777       return TRUE;
1778     }
1779   }
1780   return FALSE;
1781 }
1782
1783 /*************************************************************************
1784  * @   [SHLWAPI.329]
1785  *
1786  * Unicode version of SHLWAPI_328.
1787  */
1788 BOOL WINAPI SHLWAPI_329(LPCWSTR lpszType, LPWSTR lpszBuffer, DWORD dwLen)
1789 {
1790   TRACE("(%s,%p,%ld)\n", debugstr_w(lpszType), lpszBuffer, dwLen);
1791
1792   if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer)
1793   {
1794     DWORD dwStrLen = strlenW(lpszType);
1795
1796     if (dwStrLen < dwLen - dwLenMimeDbContent)
1797     {
1798       memcpy(lpszBuffer, szMimeDbContentA, dwLenMimeDbContent * sizeof(WCHAR));
1799       memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, (dwStrLen + 1) * sizeof(WCHAR));
1800       return TRUE;
1801     }
1802   }
1803   return FALSE;
1804 }
1805
1806 /*************************************************************************
1807  * @   [SHLWAPI.324]
1808  *
1809  * Set the file extension for a MIME content key.
1810  *
1811  * PARAMS
1812  *   lpszExt  [I] File extension to set
1813  *   lpszType [I] Content type to set the extension for
1814  *
1815  * RETURNS
1816  *   Success: TRUE. The file extension is set in the registry.
1817  *   Failure: FALSE.
1818  */
1819 BOOL WINAPI SHLWAPI_324(LPCSTR lpszExt, LPCSTR lpszType)
1820 {
1821   DWORD dwLen;
1822   char szKey[MAX_PATH];
1823
1824   TRACE("(%s,%s)\n", debugstr_a(lpszExt), debugstr_a(lpszType));
1825
1826   if (!SHLWAPI_328(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1827     return FALSE;
1828
1829   dwLen = strlen(lpszExt) + 1;
1830
1831   if (SHSetValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA, REG_SZ, lpszExt, dwLen))
1832     return FALSE;
1833   return TRUE;
1834 }
1835
1836 /*************************************************************************
1837  * @   [SHLWAPI.325]
1838  *
1839  * Unicode version of SHLWAPI_324.
1840  */
1841 BOOL WINAPI SHLWAPI_325(LPCWSTR lpszExt, LPCWSTR lpszType)
1842 {
1843   DWORD dwLen;
1844   WCHAR szKey[MAX_PATH];
1845
1846   TRACE("(%s,%s)\n", debugstr_w(lpszExt), debugstr_w(lpszType));
1847
1848   /* Get the full path to the key */
1849   if (!SHLWAPI_329(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1850     return FALSE;
1851
1852   dwLen = (lstrlenW(lpszExt) + 1) * sizeof(WCHAR);
1853
1854   if (SHSetValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW, REG_SZ, lpszExt, dwLen))
1855     return FALSE;
1856   return TRUE;
1857 }
1858
1859 /*************************************************************************
1860  * @   [SHLWAPI.326]
1861  *
1862  * Delete a file extension from a MIME content type.
1863  *
1864  * PARAMS
1865  *   lpszType [I] Content type to delete the extension for
1866  *
1867  * RETURNS
1868  *   Success: TRUE. The file extension is deleted from the registry.
1869  *   Failure: FALSE. The extension may have been removed but the key remains.
1870  *
1871  * NOTES
1872  *   If deleting the extension leaves an orphan key, the key is removed also.
1873  */
1874 BOOL WINAPI SHLWAPI_326(LPCSTR lpszType)
1875 {
1876   char szKey[MAX_PATH];
1877
1878   TRACE("(%s)\n", debugstr_a(lpszType));
1879
1880   if (!SHLWAPI_328(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1881     return FALSE;
1882
1883   if (!SHDeleteValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA))
1884     return FALSE;
1885
1886   if (!SHDeleteOrphanKeyA(HKEY_CLASSES_ROOT, szKey))
1887     return FALSE;
1888   return TRUE;
1889 }
1890
1891 /*************************************************************************
1892  * @   [SHLWAPI.327]
1893  *
1894  * Unicode version of SHLWAPI_326.
1895  */
1896 BOOL WINAPI SHLWAPI_327(LPCWSTR lpszType)
1897 {
1898   WCHAR szKey[MAX_PATH];
1899
1900   TRACE("(%s)\n", debugstr_w(lpszType));
1901
1902   if (!SHLWAPI_329(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1903     return FALSE;
1904
1905   if (!SHDeleteValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW))
1906     return FALSE;
1907
1908   if (!SHDeleteOrphanKeyW(HKEY_CLASSES_ROOT, szKey))
1909     return FALSE;
1910   return TRUE;
1911 }
1912
1913 /*************************************************************************
1914  * SHRegDuplicateHKey   [SHLWAPI.@]
1915  *
1916  * Create a duplicate of a registry handle.
1917  *
1918  * PARAMS
1919  *  hKey [I] key to duplicate.
1920  *
1921  * RETURNS
1922  *  A new handle pointing to the same key as hKey.
1923  */
1924 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1925 {
1926     HKEY newKey = 0;
1927
1928     RegOpenKeyExA(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1929     TRACE("new key is %p\n", newKey);
1930     return newKey;
1931 }
1932
1933
1934 /*************************************************************************
1935  * SHCopyKeyA   [SHLWAPI.@]
1936  *
1937  * Copy a key and its values/sub keys to another location.
1938  *
1939  * PARAMS
1940  *  hKeyDst    [I] Destination key
1941  *  lpszSubKey [I] Sub key under hKeyDst, or NULL to use hKeyDst directly
1942  *  hKeySrc    [I] Source key to copy from
1943  *  dwReserved [I] Reserved, must be 0
1944  *
1945  * RETURNS
1946  *  Success: ERROR_SUCCESS. The key is copied to the destination key.
1947  *  Failure: A standard windows error code.
1948  *
1949  * NOTES
1950  *  If hKeyDst is a key under hKeySrc, this function will misbehave
1951  *  (It will loop until out of stack, or the registry is full). This
1952  *  bug is present in Win32 also.
1953  */
1954 DWORD WINAPI SHCopyKeyA(HKEY hKeyDst, LPCSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved)
1955 {
1956   WCHAR szSubKeyW[MAX_PATH];
1957
1958   TRACE("(hkey=%p,%s,%p08x,%ld)\n", hKeyDst, debugstr_a(lpszSubKey), hKeySrc, dwReserved);
1959
1960   if (lpszSubKey)
1961     MultiByteToWideChar(0, 0, lpszSubKey, -1, szSubKeyW, MAX_PATH);
1962
1963   return SHCopyKeyW(hKeyDst, lpszSubKey ? szSubKeyW : NULL, hKeySrc, dwReserved);
1964 }
1965
1966 /*************************************************************************
1967  * SHCopyKeyW   [SHLWAPI.@]
1968  *
1969  * See SHCopyKeyA.
1970  */
1971 DWORD WINAPI SHCopyKeyW(HKEY hKeyDst, LPCWSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved)
1972 {
1973   DWORD dwKeyCount = 0, dwValueCount = 0, dwMaxKeyLen = 0;
1974   DWORD  dwMaxValueLen = 0, dwMaxDataLen = 0, i;
1975   BYTE buff[1024];
1976   LPVOID lpBuff = (LPVOID)buff;
1977   WCHAR szName[MAX_PATH], *lpszName = szName;
1978   DWORD dwRet = S_OK;
1979
1980   TRACE("hkey=%p,%s,%p08x,%ld)\n", hKeyDst, debugstr_w(lpszSubKey), hKeySrc, dwReserved);
1981
1982   if(!hKeyDst || !hKeySrc)
1983     dwRet = ERROR_INVALID_PARAMETER;
1984   else
1985   {
1986     /* Open destination key */
1987     if(lpszSubKey)
1988       dwRet = RegOpenKeyExW(hKeyDst, lpszSubKey, 0, KEY_ALL_ACCESS, &hKeyDst);
1989
1990     if(dwRet)
1991       hKeyDst = 0; /* Don't close this key since we didn't open it */
1992     else
1993     {
1994       /* Get details about sub keys and values */
1995       dwRet = RegQueryInfoKeyW(hKeySrc, NULL, NULL, NULL, &dwKeyCount, &dwMaxKeyLen,
1996                                NULL, &dwValueCount, &dwMaxValueLen, &dwMaxDataLen,
1997                                NULL, NULL);
1998       if(!dwRet)
1999       {
2000         if (dwMaxValueLen > dwMaxKeyLen)
2001           dwMaxKeyLen = dwMaxValueLen; /* Get max size for key/value names */
2002
2003         if (dwMaxKeyLen++ > MAX_PATH - 1)
2004           lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxKeyLen * sizeof(WCHAR));
2005
2006         if (dwMaxDataLen > sizeof(buff))
2007           lpBuff = HeapAlloc(GetProcessHeap(), 0, dwMaxDataLen);
2008
2009         if (!lpszName || !lpBuff)
2010           dwRet = ERROR_NOT_ENOUGH_MEMORY;
2011       }
2012     }
2013   }
2014
2015   /* Copy all the sub keys */
2016   for(i = 0; i < dwKeyCount && !dwRet; i++)
2017   {
2018     HKEY hSubKeySrc, hSubKeyDst;
2019     DWORD dwSize = dwMaxKeyLen;
2020
2021     dwRet = RegEnumKeyExW(hKeySrc, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2022
2023     if(!dwRet)
2024     {
2025       /* Open source sub key */
2026       dwRet = RegOpenKeyExW(hKeySrc, lpszName, 0, KEY_READ, &hSubKeySrc);
2027
2028       if(!dwRet)
2029       {
2030         /* Create destination sub key */
2031         dwRet = RegCreateKeyW(hKeyDst, lpszName, &hSubKeyDst);
2032
2033         if(!dwRet)
2034         {
2035           /* Recursively copy keys and values from the sub key */
2036           dwRet = SHCopyKeyW(hSubKeyDst, NULL, hSubKeySrc, 0);
2037           RegCloseKey(hSubKeyDst);
2038         }
2039       }
2040       RegCloseKey(hSubKeySrc);
2041     }
2042   }
2043
2044   /* Copy all the values in this key */
2045   for (i = 0; i < dwValueCount && !dwRet; i++)
2046   {
2047     DWORD dwNameSize = dwMaxKeyLen, dwType, dwLen = dwMaxDataLen;
2048
2049     dwRet = RegEnumValueW(hKeySrc, i, lpszName, &dwNameSize, NULL, &dwType, buff, &dwLen);
2050
2051     if (!dwRet)
2052       dwRet = SHSetValueW(hKeyDst, NULL, lpszName, dwType, lpBuff, dwLen);
2053   }
2054
2055   /* Free buffers if allocated */
2056   if (lpszName != szName)
2057     HeapFree(GetProcessHeap(), 0, lpszName);
2058   if (lpBuff != buff)
2059     HeapFree(GetProcessHeap(), 0, lpBuff);
2060
2061   if (lpszSubKey && hKeyDst)
2062     RegCloseKey(hKeyDst);
2063   return dwRet;
2064 }