Added LGPL standard comment, and copyright notices where necessary.
[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 typedef DWORD (WINAPI *RegQueryFn)(HKEY,LPCVOID,LPDWORD,LPDWORD,LPBYTE,LPDWORD);
38
39 static const char *lpszContentTypeA = "Content Type";
40 static const WCHAR lpszContentTypeW[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
41
42 /* internal structure of what the HUSKEY points to */
43 typedef struct {
44     HKEY     HKCUkey;                  /* HKEY of opened HKCU key      */
45     HKEY     HKLMkey;                  /* HKEY of opened HKLM key      */
46     HKEY     start;                    /* HKEY of where to start       */
47     WCHAR    key_string[MAX_PATH];     /* additional path from 'start' */
48 } Internal_HUSKEY, *LPInternal_HUSKEY;
49
50
51 #define REG_HKCU  TRUE
52 #define REG_HKLM  FALSE
53 /*************************************************************************
54  * REG_GetHKEYFromHUSKEY
55  *
56  * Function:  Return the proper registry key from the HUSKEY structure
57  *            also allow special predefined values.
58  */
59 HKEY REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which)
60 {
61         HKEY test = (HKEY) hUSKey;
62         LPInternal_HUSKEY mihk = (LPInternal_HUSKEY) hUSKey;
63
64         if ((test == HKEY_CLASSES_ROOT)        ||
65             (test == HKEY_CURRENT_CONFIG)      ||
66             (test == HKEY_CURRENT_USER)        ||
67             (test == HKEY_DYN_DATA)            ||
68             (test == HKEY_LOCAL_MACHINE)       ||
69             (test == HKEY_PERFORMANCE_DATA)    ||
70 /* FIXME:  need to define for Win2k, ME, XP
71  *          (test == HKEY_PERFORMANCE_TEXT)    ||
72  *          (test == HKEY_PERFORMANCE_NLSTEXT) ||
73  */
74             (test == HKEY_USERS)) return test;
75         if (which == REG_HKCU) return mihk->HKCUkey;
76         return mihk->HKLMkey;
77 }
78
79
80 /*************************************************************************
81  * SHRegOpenUSKeyA      [SHLWAPI.@]
82  *
83  * Opens a user-specific registry key
84  */
85 LONG WINAPI SHRegOpenUSKeyA(
86         LPCSTR Path,
87         REGSAM AccessType,
88         HUSKEY hRelativeUSKey,
89         PHUSKEY phNewUSKey,
90         BOOL fIgnoreHKCU)
91 {
92     HKEY openHKCUkey=0;
93     HKEY openHKLMkey=0;
94     LONG ret2, ret1 = ~ERROR_SUCCESS;
95     LPInternal_HUSKEY ihky;
96
97     TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_a(Path), 
98           (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey, 
99           (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
100
101     /* now create the internal version of HUSKEY */
102     ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 , 
103                                         sizeof(Internal_HUSKEY));
104     MultiByteToWideChar(0, 0, Path, -1, ihky->key_string,
105                         sizeof(ihky->key_string)-1);
106
107     if (hRelativeUSKey) {
108         openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
109         openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
110     }
111     else {
112         openHKCUkey = HKEY_CURRENT_USER;
113         openHKLMkey = HKEY_LOCAL_MACHINE;
114     }
115
116     ihky->HKCUkey = 0;
117     ihky->HKLMkey = 0;
118     if (!fIgnoreHKCU) {
119         ret1 = RegOpenKeyExA(openHKCUkey, Path, 
120                              0, AccessType, &ihky->HKCUkey);
121         /* if successful, then save real starting point */
122         if (ret1 != ERROR_SUCCESS)
123             ihky->HKCUkey = 0;
124     }
125     ret2 = RegOpenKeyExA(openHKLMkey, Path, 
126                          0, AccessType, &ihky->HKLMkey);
127     if (ret2 != ERROR_SUCCESS)
128         ihky->HKLMkey = 0;
129
130     if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
131         TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
132
133     /* if all attempts have failed then bail */
134     if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
135         HeapFree(GetProcessHeap(), 0, ihky);
136         if (phNewUSKey)
137             *phNewUSKey = (HUSKEY)0;
138         return ret2;
139     }
140
141     TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
142     if (phNewUSKey)
143         *phNewUSKey = (HUSKEY)ihky;
144     return ERROR_SUCCESS;
145 }
146
147 /*************************************************************************
148  * SHRegOpenUSKeyW      [SHLWAPI.@]
149  *
150  * Opens a user-specific registry key
151  */
152 LONG WINAPI SHRegOpenUSKeyW(
153         LPCWSTR Path,
154         REGSAM AccessType,
155         HUSKEY hRelativeUSKey,
156         PHUSKEY phNewUSKey,
157         BOOL fIgnoreHKCU)
158 {
159     HKEY openHKCUkey=0;
160     HKEY openHKLMkey=0;
161     LONG ret2, ret1 = ~ERROR_SUCCESS;
162     LPInternal_HUSKEY ihky;
163
164     TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_w(Path), 
165           (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey, 
166           (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
167
168     /* now create the internal version of HUSKEY */
169     ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 , 
170                                         sizeof(Internal_HUSKEY));
171     lstrcpynW(ihky->key_string, Path, sizeof(ihky->key_string));
172
173     if (hRelativeUSKey) {
174         openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
175         openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
176     }
177     else {
178         openHKCUkey = HKEY_CURRENT_USER;
179         openHKLMkey = HKEY_LOCAL_MACHINE;
180     }
181
182     ihky->HKCUkey = 0;
183     ihky->HKLMkey = 0;
184     if (!fIgnoreHKCU) {
185         ret1 = RegOpenKeyExW(openHKCUkey, Path, 
186                             0, AccessType, &ihky->HKCUkey);
187         /* if successful, then save real starting point */
188         if (ret1 != ERROR_SUCCESS)
189             ihky->HKCUkey = 0;
190     }
191     ret2 = RegOpenKeyExW(openHKLMkey, Path, 
192                         0, AccessType, &ihky->HKLMkey);
193     if (ret2 != ERROR_SUCCESS)
194         ihky->HKLMkey = 0;
195
196     if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
197         TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
198
199     /* if all attempts have failed then bail */
200     if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
201         HeapFree(GetProcessHeap(), 0, ihky);
202         if (phNewUSKey)
203             *phNewUSKey = (HUSKEY)0;
204         return ret2;
205     }
206
207     TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
208     if (phNewUSKey)
209         *phNewUSKey = (HUSKEY)ihky;
210     return ERROR_SUCCESS;
211 }
212
213 /*************************************************************************
214  * SHRegCloseUSKey      [SHLWAPI.@]
215  *
216  * Closes a user-specific registry key
217  */
218 LONG WINAPI SHRegCloseUSKey(
219         HUSKEY hUSKey)
220 {
221     LPInternal_HUSKEY mihk = (LPInternal_HUSKEY)hUSKey;
222     LONG ret = ERROR_SUCCESS;
223
224     if (mihk->HKCUkey)
225         ret = RegCloseKey(mihk->HKCUkey);
226     if (mihk->HKLMkey)
227         ret = RegCloseKey(mihk->HKLMkey);
228     HeapFree(GetProcessHeap(), 0, mihk);
229     return ret;
230 }
231
232 /*************************************************************************
233  *      SHRegQueryUSValueA      [SHLWAPI.@]
234  */
235 LONG WINAPI SHRegQueryUSValueA(
236         HUSKEY hUSKey,             /* [in]  */
237         LPCSTR pszValue,
238         LPDWORD pdwType,
239         LPVOID pvData,
240         LPDWORD pcbData,
241         BOOL fIgnoreHKCU,
242         LPVOID pvDefaultData,
243         DWORD dwDefaultDataSize)
244 {
245         LONG ret = ~ERROR_SUCCESS;
246         LONG i, maxmove;
247         HKEY dokey;
248         CHAR *src, *dst;
249
250         /* if user wants HKCU, and it exists, then try it */
251         if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
252             ret = RegQueryValueExA(dokey,
253                                    pszValue, 0, pdwType, pvData, pcbData);
254             TRACE("HKCU RegQueryValue returned %08lx\n", ret);
255         }
256
257         /* if HKCU did not work and HKLM exists, then try it */
258         if ((ret != ERROR_SUCCESS) &&
259             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
260             ret = RegQueryValueExA(dokey,
261                                    pszValue, 0, pdwType, pvData, pcbData);
262             TRACE("HKLM RegQueryValue returned %08lx\n", ret);
263         }
264
265         /* if neither worked, and default data exists, then use it */
266         if (ret != ERROR_SUCCESS) {
267             if (pvDefaultData && (dwDefaultDataSize != 0)) {
268                 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
269                 src = (CHAR*)pvDefaultData;
270                 dst = (CHAR*)pvData;
271                 for(i=0; i<maxmove; i++) *dst++ = *src++;
272                 *pcbData = maxmove;
273                 TRACE("setting default data\n");
274                 ret = ERROR_SUCCESS;
275             }
276         }
277         return ret;
278 }
279
280
281 /*************************************************************************
282  *      SHRegQueryUSValueW      [SHLWAPI.@]
283  */
284 LONG WINAPI SHRegQueryUSValueW(
285         HUSKEY hUSKey,             /* [in]  */
286         LPCWSTR pszValue,
287         LPDWORD pdwType,
288         LPVOID pvData,
289         LPDWORD pcbData,
290         BOOL fIgnoreHKCU,
291         LPVOID pvDefaultData,
292         DWORD dwDefaultDataSize)
293 {
294         LONG ret = ~ERROR_SUCCESS;
295         LONG i, maxmove;
296         HKEY dokey;
297         CHAR *src, *dst;
298
299         /* if user wants HKCU, and it exists, then try it */
300         if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
301             ret = RegQueryValueExW(dokey,
302                                    pszValue, 0, pdwType, pvData, pcbData);
303             TRACE("HKCU RegQueryValue returned %08lx\n", ret);
304         }
305
306         /* if HKCU did not work and HKLM exists, then try it */
307         if ((ret != ERROR_SUCCESS) &&
308             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
309             ret = RegQueryValueExW(dokey,
310                                    pszValue, 0, pdwType, pvData, pcbData);
311             TRACE("HKLM RegQueryValue returned %08lx\n", ret);
312         }
313
314         /* if neither worked, and default data exists, then use it */
315         if (ret != ERROR_SUCCESS) {
316             if (pvDefaultData && (dwDefaultDataSize != 0)) {
317                 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
318                 src = (CHAR*)pvDefaultData;
319                 dst = (CHAR*)pvData;
320                 for(i=0; i<maxmove; i++) *dst++ = *src++;
321                 *pcbData = maxmove;
322                 TRACE("setting default data\n");
323                 ret = ERROR_SUCCESS;
324             }
325         }
326         return ret;
327 }
328
329 /*************************************************************************
330  * SHRegGetUSValueA     [SHLWAPI.@]
331  *
332  * Gets a user-specific registry value
333  *   Will open the key, query the value, and close the key
334  */
335 LONG WINAPI SHRegGetUSValueA(
336         LPCSTR   pSubKey,
337         LPCSTR   pValue,
338         LPDWORD  pwType,
339         LPVOID   pvData,
340         LPDWORD  pcbData,
341         BOOL     flagIgnoreHKCU,
342         LPVOID   pDefaultData,
343         DWORD    wDefaultDataSize)
344 {
345         HUSKEY myhuskey;
346         LONG ret;
347
348         if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
349         TRACE("key '%s', value '%s', datalen %ld,  %s\n",
350               debugstr_a(pSubKey), debugstr_a(pValue), *pcbData,
351               (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
352
353         ret = SHRegOpenUSKeyA(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
354         if (ret == ERROR_SUCCESS) {
355             ret = SHRegQueryUSValueA(myhuskey, pValue, pwType, pvData,
356                                      pcbData, flagIgnoreHKCU, pDefaultData,
357                                      wDefaultDataSize);
358             SHRegCloseUSKey(myhuskey);
359         }
360         return ret;
361 }
362
363 /*************************************************************************
364  * SHRegGetUSValueW     [SHLWAPI.@]
365  *
366  * Gets a user-specific registry value
367  *   Will open the key, query the value, and close the key
368  */
369 LONG WINAPI SHRegGetUSValueW(
370         LPCWSTR  pSubKey,
371         LPCWSTR  pValue,
372         LPDWORD  pwType,
373         LPVOID   pvData,
374         LPDWORD  pcbData,
375         BOOL     flagIgnoreHKCU,
376         LPVOID   pDefaultData,
377         DWORD    wDefaultDataSize)
378 {
379         HUSKEY myhuskey;
380         LONG ret;
381
382         if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
383         TRACE("key '%s', value '%s', datalen %ld,  %s\n",
384               debugstr_w(pSubKey), debugstr_w(pValue), *pcbData,
385               (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
386
387         ret = SHRegOpenUSKeyW(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
388         if (ret == ERROR_SUCCESS) {
389             ret = SHRegQueryUSValueW(myhuskey, pValue, pwType, pvData,
390                                      pcbData, flagIgnoreHKCU, pDefaultData,
391                                      wDefaultDataSize);
392             SHRegCloseUSKey(myhuskey);
393         }
394         return ret;
395 }
396
397 /*************************************************************************
398  * SHRegGetBoolUSValueA   [SHLWAPI.@]
399  */
400 BOOL WINAPI SHRegGetBoolUSValueA(
401         LPCSTR pszSubKey,
402         LPCSTR pszValue,
403         BOOL fIgnoreHKCU,
404         BOOL fDefault)
405 {
406         LONG retvalue;
407         DWORD type, datalen, work;
408         BOOL ret = fDefault;
409         CHAR data[10];
410
411         TRACE("key '%s', value '%s', %s\n",
412               debugstr_a(pszSubKey), debugstr_a(pszValue),
413               (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
414
415         datalen = sizeof(data)-1;
416         if (!(retvalue = SHRegGetUSValueA( pszSubKey, pszValue, &type, 
417                                            data, &datalen,
418                                            fIgnoreHKCU, 0, 0))) {
419             /* process returned data via type into bool */
420             switch (type) {
421             case REG_SZ:
422                 data[9] = '\0';     /* set end of string */
423                 if (lstrcmpiA(data, "YES") == 0) ret = TRUE;
424                 if (lstrcmpiA(data, "TRUE") == 0) ret = TRUE;
425                 if (lstrcmpiA(data, "NO") == 0) ret = FALSE;
426                 if (lstrcmpiA(data, "FALSE") == 0) ret = FALSE;
427                 break;
428             case REG_DWORD:
429                 work = *(LPDWORD)data;
430                 ret = (work != 0);
431                 break;
432             case REG_BINARY:
433                 if (datalen == 1) {
434                     ret = (data[0] != '\0');
435                     break;
436                 }
437             default:
438                 FIXME("Unsupported registry data type %ld\n", type);
439                 ret = FALSE;
440             }
441             TRACE("got value (type=%ld), returing <%s>\n", type,
442                   (ret) ? "TRUE" : "FALSE");
443         }
444         else {
445             ret = fDefault;
446             TRACE("returning default data <%s>\n",
447                   (ret) ? "TRUE" : "FALSE");
448         }
449         return ret;
450 }
451
452 /*************************************************************************
453  * SHRegGetBoolUSValueW   [SHLWAPI.@]
454  */
455 BOOL WINAPI SHRegGetBoolUSValueW(
456         LPCWSTR pszSubKey,
457         LPCWSTR pszValue,
458         BOOL fIgnoreHKCU,
459         BOOL fDefault)
460 {
461         static const WCHAR wYES[]=  {'Y','E','S','\0'};
462         static const WCHAR wTRUE[]= {'T','R','U','E','\0'};
463         static const WCHAR wNO[]=   {'N','O','\0'};
464         static const WCHAR wFALSE[]={'F','A','L','S','E','\0'};
465         LONG retvalue;
466         DWORD type, datalen, work;
467         BOOL ret = fDefault;
468         WCHAR data[10];
469
470         TRACE("key '%s', value '%s', %s\n",
471               debugstr_w(pszSubKey), debugstr_w(pszValue),
472               (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
473
474         datalen = (sizeof(data)-1) * sizeof(WCHAR);
475         if (!(retvalue = SHRegGetUSValueW( pszSubKey, pszValue, &type, 
476                                            data, &datalen,
477                                            fIgnoreHKCU, 0, 0))) {
478             /* process returned data via type into bool */
479             switch (type) {
480             case REG_SZ:
481                 data[9] = L'\0';     /* set end of string */
482                 if (lstrcmpiW(data, wYES)==0 || lstrcmpiW(data, wTRUE)==0)
483                     ret = TRUE;
484                 else if (lstrcmpiW(data, wNO)==0 || lstrcmpiW(data, wFALSE)==0)
485                     ret = FALSE;
486                 break;
487             case REG_DWORD:
488                 work = *(LPDWORD)data;
489                 ret = (work != 0);
490                 break;
491             case REG_BINARY:
492                 if (datalen == 1) {
493                     ret = (data[0] != L'\0');
494                     break;
495                 }
496             default:
497                 FIXME("Unsupported registry data type %ld\n", type);
498                 ret = FALSE;
499             }
500             TRACE("got value (type=%ld), returing <%s>\n", type,
501                   (ret) ? "TRUE" : "FALSE");
502         }
503         else {
504             ret = fDefault;
505             TRACE("returning default data <%s>\n",
506                   (ret) ? "TRUE" : "FALSE");
507         }
508         return ret;
509 }
510
511 /*************************************************************************
512  *      SHRegQueryInfoUSKeyA    [SHLWAPI.@]
513  */
514 LONG WINAPI SHRegQueryInfoUSKeyA(
515         HUSKEY hUSKey,             /* [in]  */
516         LPDWORD pcSubKeys,
517         LPDWORD pcchMaxSubKeyLen,
518         LPDWORD pcValues,
519         LPDWORD pcchMaxValueNameLen,
520         SHREGENUM_FLAGS enumRegFlags)
521 {
522         HKEY dokey;
523         LONG ret;
524
525         TRACE("(0x%lx,%p,%p,%p,%p,%d)\n",
526               (LONG)hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
527               pcchMaxValueNameLen,enumRegFlags);
528
529         /* if user wants HKCU, and it exists, then try it */
530         if (((enumRegFlags == SHREGENUM_HKCU) ||
531              (enumRegFlags == SHREGENUM_DEFAULT)) &&
532             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
533             ret = RegQueryInfoKeyA(dokey, 0, 0, 0,
534                                    pcSubKeys, pcchMaxSubKeyLen, 0,
535                                    pcValues, pcchMaxValueNameLen, 0, 0, 0);
536             if ((ret == ERROR_SUCCESS) ||
537                 (enumRegFlags == SHREGENUM_HKCU)) 
538                 return ret;
539         }
540         if (((enumRegFlags == SHREGENUM_HKLM) ||
541              (enumRegFlags == SHREGENUM_DEFAULT)) && 
542             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
543             return RegQueryInfoKeyA(dokey, 0, 0, 0,
544                                     pcSubKeys, pcchMaxSubKeyLen, 0,
545                                     pcValues, pcchMaxValueNameLen, 0, 0, 0);
546         }
547         return ERROR_INVALID_FUNCTION;
548 }
549
550 /*************************************************************************
551  *      SHRegQueryInfoUSKeyW    [SHLWAPI.@]
552  */
553 LONG WINAPI SHRegQueryInfoUSKeyW(
554         HUSKEY hUSKey,             /* [in]  */
555         LPDWORD pcSubKeys,
556         LPDWORD pcchMaxSubKeyLen,
557         LPDWORD pcValues,
558         LPDWORD pcchMaxValueNameLen,
559         SHREGENUM_FLAGS enumRegFlags)
560 {
561         HKEY dokey;
562         LONG ret;
563
564         TRACE("(0x%lx,%p,%p,%p,%p,%d)\n",
565               (LONG)hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
566               pcchMaxValueNameLen,enumRegFlags);
567
568         /* if user wants HKCU, and it exists, then try it */
569         if (((enumRegFlags == SHREGENUM_HKCU) ||
570              (enumRegFlags == SHREGENUM_DEFAULT)) && 
571             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
572             ret = RegQueryInfoKeyW(dokey, 0, 0, 0,
573                                    pcSubKeys, pcchMaxSubKeyLen, 0,
574                                    pcValues, pcchMaxValueNameLen, 0, 0, 0);
575             if ((ret == ERROR_SUCCESS) ||
576                 (enumRegFlags == SHREGENUM_HKCU)) 
577                 return ret;
578         }
579         if (((enumRegFlags == SHREGENUM_HKLM) ||
580              (enumRegFlags == SHREGENUM_DEFAULT)) && 
581             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
582             return RegQueryInfoKeyW(dokey, 0, 0, 0,
583                                     pcSubKeys, pcchMaxSubKeyLen, 0,
584                                     pcValues, pcchMaxValueNameLen, 0, 0, 0);
585         }
586         return ERROR_INVALID_FUNCTION;
587 }
588
589 /*************************************************************************
590  *      SHRegEnumUSKeyA         [SHLWAPI.@]
591  */
592 LONG WINAPI SHRegEnumUSKeyA(
593         HUSKEY hUSKey,                 /* [in]  */
594         DWORD dwIndex,                 /* [in]  */
595         LPSTR pszName,                 /* [out] */
596         LPDWORD pcchValueNameLen,      /* [in/out] */
597         SHREGENUM_FLAGS enumRegFlags)  /* [in]  */
598 {
599         HKEY dokey;
600
601         TRACE("(0x%lx,%ld,%p,%p(%ld),%d)\n",
602               (LONG)hUSKey, dwIndex, pszName, pcchValueNameLen,
603               *pcchValueNameLen, enumRegFlags);
604
605         if (((enumRegFlags == SHREGENUM_HKCU) ||
606              (enumRegFlags == SHREGENUM_DEFAULT)) && 
607             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
608             return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen, 
609                                 0, 0, 0, 0);
610         }
611
612         if (((enumRegFlags == SHREGENUM_HKLM) ||
613              (enumRegFlags == SHREGENUM_DEFAULT)) && 
614             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
615             return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
616                                 0, 0, 0, 0);
617         }
618         FIXME("no support for SHREGNUM_BOTH\n");
619         return ERROR_INVALID_FUNCTION;
620 }
621
622 /*************************************************************************
623  *      SHRegEnumUSKeyW         [SHLWAPI.@]
624  */
625 LONG WINAPI SHRegEnumUSKeyW(
626         HUSKEY hUSKey,                 /* [in]  */
627         DWORD dwIndex,                 /* [in]  */
628         LPWSTR pszName,                /* [out] */
629         LPDWORD pcchValueNameLen,      /* [in/out] */
630         SHREGENUM_FLAGS enumRegFlags)  /* [in]  */
631 {
632         HKEY dokey;
633
634         TRACE("(0x%lx,%ld,%p,%p(%ld),%d)\n",
635               (LONG)hUSKey, dwIndex, pszName, pcchValueNameLen,
636               *pcchValueNameLen, enumRegFlags);
637
638         if (((enumRegFlags == SHREGENUM_HKCU) ||
639              (enumRegFlags == SHREGENUM_DEFAULT)) && 
640             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
641             return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
642                                 0, 0, 0, 0);
643         }
644
645         if (((enumRegFlags == SHREGENUM_HKLM) ||
646              (enumRegFlags == SHREGENUM_DEFAULT)) &&
647             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
648             return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
649                                 0, 0, 0, 0);
650         }
651         FIXME("no support for SHREGNUM_BOTH\n");
652         return ERROR_INVALID_FUNCTION;
653 }
654
655 /*************************************************************************
656  *      SHRegWriteUSValueA      [SHLWAPI.@]
657  */
658 LONG  WINAPI SHRegWriteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, DWORD dwType,
659                                 LPVOID pvData, DWORD cbData, DWORD dwFlags)
660 {
661     HKEY dokey;
662
663     TRACE("(0x%lx,%s,%ld,%p,%ld,%ld)\n",
664           (LONG)hUSKey, debugstr_a(pszValue), dwType, pvData, cbData, dwFlags);
665
666     if ((dwFlags & SHREGSET_FORCE_HKCU) && 
667             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
668         RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
669     }
670
671     if ((dwFlags & SHREGSET_FORCE_HKLM) && 
672             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
673         RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
674     }
675
676     if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM)) 
677         return ERROR_SUCCESS;
678
679     FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
680     return ERROR_SUCCESS;
681 }
682
683 /*************************************************************************
684  *      SHRegWriteUSValueW      [SHLWAPI.@]
685  */
686 LONG  WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, DWORD dwType,
687                                 LPVOID pvData, DWORD cbData, DWORD dwFlags)
688 {
689     HKEY dokey;
690
691     TRACE("(0x%lx,%s,%ld,%p,%ld,%ld)\n",
692           (LONG)hUSKey, debugstr_w(pszValue), dwType, pvData, cbData, dwFlags);
693
694     if ((dwFlags & SHREGSET_FORCE_HKCU) && 
695             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
696         RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
697     }
698
699     if ((dwFlags & SHREGSET_FORCE_HKLM) && 
700             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
701         RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
702     }
703
704     if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM)) 
705         return ERROR_SUCCESS;
706
707     FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
708     return ERROR_SUCCESS;
709 }
710
711 /*************************************************************************
712  * SHRegGetPathA   [SHLWAPI.@]
713  *
714  * Get a path from the registry.
715  *
716  * PARAMS
717  *   hKey       [I] Handle to registry key
718  *   lpszSubKey [I] Name of sub key containing path to get
719  *   lpszValue  [I] Name of value containing path to get
720  *   lpszPath   [O] Buffer for returned path
721  *   dwFlags    [I] Reserved
722  *
723  * RETURNS
724  *   Success: ERROR_SUCCESS. lpszPath contains the path.
725  *   Failure: An error code from RegOpenKeyExA or SHQueryValueExA.
726  */
727 DWORD WINAPI SHRegGetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
728                            LPSTR lpszPath, DWORD dwFlags)
729 {
730   HKEY hSubKey;
731   DWORD dwType = REG_SZ, dwSize = MAX_PATH, dwRet = ERROR_SUCCESS;
732
733   TRACE("(hkey=0x%08x,%s,%s,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
734         debugstr_a(lpszValue), lpszPath, dwFlags);
735
736   if (lpszSubKey && *lpszSubKey)
737     dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
738   else
739     hSubKey = hKey;
740
741   if (!dwRet)
742     dwRet = SHQueryValueExA(hSubKey, lpszValue, NULL, &dwType, lpszPath, &dwSize);
743
744   if (hSubKey != hKey)
745     RegCloseKey(hSubKey);
746
747   return dwRet;
748 }
749
750 /*************************************************************************
751  * SHRegGetPathW   [SHLWAPI.@]
752  *
753  * See SHRegGetPathA.
754  */
755 DWORD WINAPI SHRegGetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
756                            LPWSTR lpszPath, DWORD dwFlags)
757 {
758   HKEY hSubKey;
759   DWORD dwType = REG_SZ, dwSize = MAX_PATH, dwRet = ERROR_SUCCESS;
760
761   TRACE("(hkey=0x%08x,%s,%s,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
762         debugstr_w(lpszValue), lpszPath, dwFlags);
763
764   if (lpszSubKey && *lpszSubKey)
765     dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
766   else
767     hSubKey = hKey;
768
769   if (!dwRet)
770     dwRet = SHQueryValueExW(hSubKey, lpszValue, NULL, &dwType, lpszPath, &dwSize);
771
772   if (hSubKey != hKey)
773     RegCloseKey(hSubKey);
774
775   return dwRet;
776 }
777
778
779 /*************************************************************************
780  * SHRegSetPathA   [SHLWAPI.@]
781  *
782  * Write a path to the registry.
783  *
784  * PARAMS
785  *   hKey       [I] Handle to registry key
786  *   lpszSubKey [I] Name of sub key containing path to set
787  *   lpszValue  [I] Name of value containing path to set
788  *   lpszPath   [O] Path to write
789  *   dwFlags    [I] Reserved
790  *
791  * RETURNS
792  *   Success: ERROR_SUCCESS.
793  *   Failure: An error code from SHSetValueA.
794  */
795 DWORD WINAPI SHRegSetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
796                            LPCSTR lpszPath, DWORD dwFlags)
797 {
798   char szBuff[MAX_PATH];
799
800   FIXME("(hkey=0x%08x,%s,%s,%p,%ld) - semi-stub",hKey, debugstr_a(lpszSubKey),
801         debugstr_a(lpszValue), lpszPath, dwFlags);
802
803   lstrcpyA(szBuff, lpszPath);
804
805   /* FIXME: PathUnExpandEnvStringsA(szBuff); */
806
807   return SHSetValueA(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
808                      lstrlenA(szBuff));
809 }
810
811 /*************************************************************************
812  * SHRegSetPathW   [SHLWAPI.@]
813  *
814  * See SHRegSetPathA.
815  */
816 DWORD WINAPI SHRegSetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
817                            LPCWSTR lpszPath, DWORD dwFlags)
818 {
819   WCHAR szBuff[MAX_PATH];
820
821   FIXME("(hkey=0x%08x,%s,%s,%p,%ld) - semi-stub",hKey, debugstr_w(lpszSubKey),
822         debugstr_w(lpszValue), lpszPath, dwFlags);
823
824   lstrcpyW(szBuff, lpszPath);
825
826   /* FIXME: PathUnExpandEnvStringsW(szBuff); */
827
828   return SHSetValueW(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
829                      lstrlenW(szBuff));
830 }
831
832 /*************************************************************************
833  * SHGetValueA   [SHLWAPI.@]
834  *
835  * Get a value from the registry.
836  *
837  * PARAMS
838  *   hKey       [I] Handle to registry key
839  *   lpszSubKey [I] Name of sub key containing value to get
840  *   lpszValue  [I] Name of value to get
841  *   pwType     [O] Pointer to the values type
842  *   pvData     [O] Pointer to the values data
843  *   pcbData    [O] Pointer to the values size
844  *
845  * RETURNS
846  *   Success: ERROR_SUCCESS. Output parameters contain the details read.
847  *   Failure: An error code from RegOpenKeyExA or RegQueryValueExA.
848  */
849 DWORD WINAPI SHGetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
850                          LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
851 {
852   DWORD dwRet;
853   HKEY hSubKey;
854
855   TRACE("(hkey=0x%08x,%s,%s,%p,%p,%p)\n", hKey, debugstr_a(lpszSubKey),
856         debugstr_a(lpszValue), pwType, pvData, pcbData);
857
858   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
859   if (!dwRet)
860   {
861     dwRet = RegQueryValueExA(hSubKey, lpszValue, 0, pwType, pvData, pcbData);
862     RegCloseKey(hSubKey);
863   }
864   return dwRet;
865 }
866
867 /*************************************************************************
868  * SHGetValueW   [SHLWAPI.@]
869  *
870  * See SHGetValueA.
871  */
872 DWORD WINAPI SHGetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
873                          LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
874 {
875   DWORD dwRet;
876   HKEY hSubKey;
877
878   TRACE("(hkey=0x%08x,%s,%s,%p,%p,%p)\n", hKey, debugstr_w(lpszSubKey),
879         debugstr_w(lpszValue), pwType, pvData, pcbData);
880
881   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
882   if (!dwRet)
883   {
884     dwRet = RegQueryValueExW(hSubKey, lpszValue, 0, pwType, pvData, pcbData);
885     RegCloseKey(hSubKey);
886   }
887   return dwRet;
888 }
889
890 /*************************************************************************
891  * SHSetValueA   [SHLWAPI.@]
892  *
893  * Set a value in the registry.
894  *
895  * PARAMS
896  *   hKey       [I] Handle to registry key
897  *   lpszSubKey [I] Name of sub key under hKey
898  *   lpszValue  [I] Name of value to set
899  *   dwType     [I] Type of the value
900  *   pvData     [I] Data of the value
901  *   cbData     [I] Size of the value
902  *
903  * RETURNS
904  *   Success: ERROR_SUCCESS. The value is set with the data given.
905  *   Failure: An error code from RegCreateKeyExA or RegSetValueExA
906  *
907  * NOTES
908  *   If the sub key does not exist, it is created before the value is set. If
909  *   The sub key is NULL or an empty string, then the value is added directly
910  *   to hKey instead.
911  */
912 DWORD WINAPI SHSetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
913                          DWORD dwType, LPCVOID pvData, DWORD cbData)
914 {
915   DWORD dwRet = ERROR_SUCCESS, dwDummy;
916   HKEY  hSubKey;
917   LPSTR szEmpty = "";
918
919   TRACE("(hkey=0x%08x,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
920           debugstr_a(lpszValue), dwType, pvData, cbData);
921
922   if (lpszSubKey && *lpszSubKey)
923     dwRet = RegCreateKeyExA(hKey, lpszSubKey, 0, szEmpty,
924                             0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
925   else
926     hSubKey = hKey;
927   if (!dwRet)
928   {
929     dwRet = RegSetValueExA(hSubKey, lpszValue, 0, dwType, pvData, cbData);
930     if (hSubKey != hKey)
931       RegCloseKey(hSubKey);
932   }
933   return dwRet;
934 }
935
936 /*************************************************************************
937  * SHSetValueW   [SHLWAPI.@]
938  *
939  * See SHSetValueA.
940  */
941 DWORD WINAPI SHSetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
942                          DWORD dwType, LPCVOID pvData, DWORD cbData)
943 {
944   DWORD dwRet = ERROR_SUCCESS, dwDummy;
945   HKEY  hSubKey;
946   WCHAR szEmpty[] = { '\0' };
947
948   TRACE("(hkey=0x%08x,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
949         debugstr_w(lpszValue), dwType, pvData, cbData);
950
951   if (lpszSubKey && *lpszSubKey)
952     dwRet = RegCreateKeyExW(hKey, lpszSubKey, 0, szEmpty,
953                             0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
954   else
955     hSubKey = hKey;
956   if (!dwRet)
957   {
958     dwRet = RegSetValueExW(hSubKey, lpszValue, 0, dwType, pvData, cbData);
959     if (hSubKey != hKey)
960       RegCloseKey(hSubKey);
961   }
962   return dwRet;
963 }
964
965 /*************************************************************************
966  * SHQueryInfoKeyA   [SHLWAPI.@]
967  *
968  * Get information about a registry key. See RegQueryInfoKeyA.
969  */
970 LONG WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
971                             LPDWORD pwValues, LPDWORD pwValueMax)
972 {
973   TRACE("(hkey=0x%08x,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
974         pwValues, pwValueMax);
975   return RegQueryInfoKeyA(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
976                           NULL, pwValues, pwValueMax, NULL, NULL, NULL);
977 }
978
979 /*************************************************************************
980  * SHQueryInfoKeyW   [SHLWAPI.@]
981  *
982  * See SHQueryInfoKeyA
983  */
984 LONG WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
985                             LPDWORD pwValues, LPDWORD pwValueMax)
986 {
987   TRACE("(hkey=0x%08x,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
988         pwValues, pwValueMax);
989   return RegQueryInfoKeyW(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
990                           NULL, pwValues, pwValueMax, NULL, NULL, NULL);
991 }
992
993 /*************************************************************************
994  * SHQueryValueExAW
995  *
996  * Internal implementation of SHQueryValueExA/SHQueryValueExW.
997  */
998 static DWORD WINAPI SHQueryValueExAW(RegQueryFn pfn,
999                                      HKEY hKey, LPCVOID lpszValue,
1000                                      LPDWORD lpReserved, LPDWORD pwType,
1001                                      LPBYTE pvData, LPDWORD pcbData)
1002 {
1003   DWORD dwRet, dwType, dwDataLen;
1004
1005   if (pcbData)
1006     dwDataLen = *pcbData;
1007
1008   dwRet = pfn(hKey, lpszValue, lpReserved, &dwType, pvData, &dwDataLen);
1009   if (!dwRet)
1010   {
1011     if (dwType == REG_EXPAND_SZ)
1012     {
1013       /* Expand type REG_EXPAND_SZ into REG_SZ */
1014       LPSTR szExpand;
1015       LPBYTE pData = pvData;
1016
1017       if (!pData)
1018       {
1019         /* Create a buffer to hold the data, to get the size */
1020         if (!pcbData ||
1021             !(pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pcbData)))
1022           return ERROR_OUTOFMEMORY;
1023         /* Read the data in to the buffer */
1024         if ((dwRet = pfn(hKey, lpszValue, lpReserved, &dwType,
1025                          pData, &dwDataLen)))
1026           return dwRet;
1027       }
1028
1029       if (!pcbData && pData != pvData)
1030       {
1031         /* Note: In this case the caller will crash under Win32 */
1032         WARN("Invalid pcbData would crash under Win32!");
1033         return ERROR_OUTOFMEMORY;
1034       }
1035
1036       szExpand = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pcbData);
1037       if (!szExpand)
1038       {
1039         if (pData != pvData)
1040           HeapFree(GetProcessHeap(), 0, pData);
1041         return ERROR_OUTOFMEMORY;
1042       }
1043       if ((ExpandEnvironmentStringsA(pvData, szExpand, *pcbData) <= 0))
1044       {
1045         dwDataLen = strlen(szExpand) + 1;
1046         strncpy(pvData, szExpand, *pcbData);
1047       }
1048       else
1049       {
1050         if (pData != pvData)
1051           HeapFree(GetProcessHeap(), 0, pData);
1052         HeapFree(GetProcessHeap(), 0, szExpand);
1053         return GetLastError();
1054       }
1055       if (pData != pvData)
1056         HeapFree(GetProcessHeap(), 0, pData);
1057       HeapFree(GetProcessHeap(), 0, szExpand);
1058       dwType = REG_SZ;
1059     }
1060     if (dwType == REG_SZ && pvData && pcbData && dwDataLen >= *pcbData)
1061     {
1062       /* String type too long: truncate it */
1063       pvData[*pcbData] = '\0';
1064     }
1065   }
1066   /* Update the type and data size if the caller wanted them */
1067   if (pwType)
1068     *pwType = dwType;
1069   if (pcbData)
1070     *pcbData  = dwDataLen;
1071   return dwRet;
1072 }
1073
1074 /*************************************************************************
1075  * SHQueryValueExA   [SHLWAPI.@]
1076  *
1077  * Get a value from the registry, expanding environment variable strings.
1078  *
1079  * PARAMS
1080  *   hKey       [I] Handle to registry key
1081  *   lpszValue  [I] Name of value to delete
1082  *   lpReserved [O] Reserved for future use; must be NULL
1083  *   pwType     [O] Optional pointer updated with the values type
1084  *   pvData     [O] Optional pointer updated with the values data
1085  *   pcbData    [O] Optional pointer updated with the values size
1086  *
1087  * RETURNS
1088  *   Success: ERROR_SUCCESS. Any non-NULL output parameters are updated with
1089  *            information about the value.
1090  *   Failure: ERROR_OUTOFMEMORY if memory allocation fails, or the type of the
1091  *            data is REG_EXPAND_SZ and pcbData is NULL. Otherwise an error
1092  *            code from RegQueryValueExA or ExpandEnvironmentStringsA.
1093  *
1094  * NOTES
1095  *   Either pwType, pvData or pcbData may be NULL if the caller doesn't want
1096  *   the type, data or size information for the value.
1097  *
1098  *   If the type of the data is REG_EXPAND_SZ, it is expanded to REG_SZ. The
1099  *   value returned will be truncated if it is of type REG_SZ and bigger than
1100  *   the buffer given to store it.
1101  */
1102 DWORD WINAPI SHQueryValueExA(HKEY hKey, LPCSTR lpszValue,
1103                              LPDWORD lpReserved, LPDWORD pwType,
1104                              LPVOID pvData, LPDWORD pcbData)
1105 {
1106   TRACE("(hkey=0x%08x,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_a(lpszValue),
1107         lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1108
1109   return SHQueryValueExAW((RegQueryFn)RegQueryValueExA, hKey, lpszValue,
1110                           lpReserved, pwType, pvData, pcbData);
1111 }
1112
1113 /*************************************************************************
1114  * SHQueryValueExW   [SHLWAPI.@]
1115  *
1116  * See SHQueryValueExA.
1117  */
1118 DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue,
1119                              LPDWORD lpReserved, LPDWORD pwType,
1120                              LPVOID pvData, LPDWORD pcbData)
1121 {
1122   TRACE("(hkey=0x%08x,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_w(lpszValue),
1123         lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1124
1125   return SHQueryValueExAW((RegQueryFn)RegQueryValueExW, hKey, lpszValue,
1126                           lpReserved, pwType, pvData, pcbData);
1127 }
1128
1129 /*************************************************************************
1130  * SHDeleteKeyA   [SHLWAPI.@]
1131  *
1132  * Delete a registry key and any sub keys/values present
1133  *
1134  * PARAMS
1135  *   hKey       [I] Handle to registry key
1136  *   lpszSubKey [I] Name of sub key to delete
1137  *
1138  * RETURNS
1139  *   Success: ERROR_SUCCESS. The key is deleted.
1140  *   Failure: An error code from RegOpenKeyExA, RegQueryInfoKeyA,
1141  *          RegEnumKeyExA or RegDeleteKeyA.
1142  */
1143 DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey)
1144 {
1145   DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1146   CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1147   HKEY hSubKey = 0;
1148
1149   TRACE("(hkey=0x%08x,%s)\n", hKey, debugstr_a(lpszSubKey));
1150
1151   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1152   if(!dwRet)
1153   {
1154     /* Find how many subkeys there are */
1155     dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1156                              &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1157     if(!dwRet)
1158     {
1159       dwMaxSubkeyLen++;
1160       if (dwMaxSubkeyLen > sizeof(szNameBuf))
1161         /* Name too big: alloc a buffer for it */
1162         lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(CHAR));
1163
1164       if(!lpszName)
1165         dwRet = ERROR_NOT_ENOUGH_MEMORY;
1166       else
1167       {
1168         /* Recursively delete all the subkeys */
1169         for(i = 0; i < dwKeyCount && !dwRet; i++)
1170         {
1171           dwSize = dwMaxSubkeyLen;
1172           dwRet = RegEnumKeyExA(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1173           if(!dwRet)
1174             dwRet = SHDeleteKeyA(hSubKey, lpszName);
1175         }
1176         if (lpszName != szNameBuf)
1177           HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1178       }
1179     }
1180
1181     RegCloseKey(hSubKey);
1182     if(!dwRet)
1183       dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1184   }
1185   return dwRet;
1186 }
1187
1188 /*************************************************************************
1189  * SHDeleteKeyW   [SHLWAPI.@]
1190  *
1191  * See SHDeleteKeyA.
1192  */
1193 DWORD WINAPI SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1194 {
1195   DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1196   WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1197   HKEY hSubKey = 0;
1198
1199   TRACE("(hkey=0x%08x,%s)\n", hKey, debugstr_w(lpszSubKey));
1200
1201   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1202   if(!dwRet)
1203   {
1204     /* Find how many subkeys there are */
1205     dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1206                              &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1207     if(!dwRet)
1208     {
1209       dwMaxSubkeyLen++;
1210       if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1211         /* Name too big: alloc a buffer for it */
1212         lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1213
1214       if(!lpszName)
1215         dwRet = ERROR_NOT_ENOUGH_MEMORY;
1216       else
1217       {
1218         /* Recursively delete all the subkeys */
1219         for(i = 0; i < dwKeyCount && !dwRet; i++)
1220         {
1221           dwSize = dwMaxSubkeyLen;
1222           dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1223           if(!dwRet)
1224             dwRet = SHDeleteKeyW(hSubKey, lpszName);
1225         }
1226
1227         if (lpszName != szNameBuf)
1228           HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1229       }
1230     }
1231
1232     RegCloseKey(hSubKey);
1233     if(!dwRet)
1234       dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1235   }
1236   return dwRet;
1237 }
1238
1239 /*************************************************************************
1240  * SHDeleteEmptyKeyA   [SHLWAPI.@]
1241  *
1242  * Delete a registry key with no sub keys.
1243  *
1244  * PARAMS
1245  *   hKey       [I] Handle to registry key
1246  *   lpszSubKey [I] Name of sub key to delete
1247  *
1248  * RETURNS
1249  *   Success: ERROR_SUCCESS. The key is deleted.
1250  *   Failure: If the key is not empty, returns ERROR_KEY_HAS_CHILDREN. Otherwise
1251  *          returns an error code from RegOpenKeyExA, RegQueryInfoKeyA or
1252  *          RegDeleteKeyA.
1253  */
1254 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hKey, LPCSTR lpszSubKey)
1255 {
1256   DWORD dwRet, dwKeyCount = 0;
1257   HKEY hSubKey = 0;
1258
1259   TRACE("(hkey=0x%08x,%s)\n", hKey, debugstr_a(lpszSubKey));
1260
1261   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1262   if(!dwRet)
1263   {
1264     dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1265                              NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1266     RegCloseKey(hSubKey);
1267     if(!dwRet)
1268     {
1269       if (!dwKeyCount)
1270         dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1271       else
1272         dwRet = ERROR_KEY_HAS_CHILDREN;
1273     }
1274   }
1275   return dwRet;
1276 }
1277
1278 /*************************************************************************
1279  * SHDeleteEmptyKeyW   [SHLWAPI.@]
1280  *
1281  * See SHDeleteEmptyKeyA.
1282  */
1283 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1284 {
1285   DWORD dwRet, dwKeyCount = 0;
1286   HKEY hSubKey = 0;
1287
1288   TRACE("(hkey=0x%08x, %s)\n", hKey, debugstr_w(lpszSubKey));
1289
1290   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1291   if(!dwRet)
1292   {
1293     dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1294                              NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1295     RegCloseKey(hSubKey);
1296     if(!dwRet)
1297     {
1298       if (!dwKeyCount)
1299         dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1300       else
1301         dwRet = ERROR_KEY_HAS_CHILDREN;
1302     }
1303   }
1304   return dwRet;
1305 }
1306
1307 /*************************************************************************
1308  * SHDeleteOrphanKeyA   [SHLWAPI.@]
1309  *
1310  * Delete a registry key with no sub keys or values.
1311  *
1312  * PARAMS
1313  *   hKey       [I] Handle to registry key
1314  *   lpszSubKey [I] Name of sub key to possibly delete
1315  *
1316  * RETURNS
1317  *   Success: ERROR_SUCCESS. The key has been deleted if it was an orphan.
1318  *   Failure: An error from RegOpenKeyExA, RegQueryValueExA, or RegDeleteKeyA.
1319  */
1320 DWORD WINAPI SHDeleteOrphanKeyA(HKEY hKey, LPCSTR lpszSubKey)
1321 {
1322   HKEY hSubKey;
1323   DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
1324
1325   TRACE("(hkey=0x%08x,%s)", hKey, debugstr_a(lpszSubKey));
1326
1327   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1328
1329   if(!dwRet)
1330   {
1331     /* Get subkey and value count */
1332     dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1333                              NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
1334
1335     if(!dwRet && !dwKeyCount && !dwValueCount)
1336     {
1337       dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1338     }
1339     RegCloseKey(hSubKey);
1340   }
1341   return dwRet;
1342 }
1343
1344 /*************************************************************************
1345  * SHDeleteOrphanKeyW   [SHLWAPI.@]
1346  *
1347  * See SHDeleteOrphanKeyA.
1348  */
1349 DWORD WINAPI SHDeleteOrphanKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1350 {
1351   HKEY hSubKey;
1352   DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
1353
1354   TRACE("(hkey=0x%08x,%s)", hKey, debugstr_w(lpszSubKey));
1355
1356   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1357
1358   if(!dwRet)
1359   {
1360     /* Get subkey and value count */
1361     dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1362                              NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
1363
1364     if(!dwRet && !dwKeyCount && !dwValueCount)
1365     {
1366       dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1367     }
1368     RegCloseKey(hSubKey);
1369   }
1370   return dwRet;
1371 }
1372
1373 /*************************************************************************
1374  * SHDeleteValueA   [SHLWAPI.@]
1375  *
1376  * Delete a value from the registry.
1377  *
1378  * PARAMS
1379  *   hKey       [I] Handle to registry key
1380  *   lpszSubKey [I] Name of sub key containing value to delete
1381  *   lpszValue  [I] Name of value to delete
1382  *
1383  * RETURNS
1384  *   Success: ERROR_SUCCESS. The value is deleted.
1385  *   Failure: An error code from RegOpenKeyExA or RegDeleteValueA.
1386  */
1387 DWORD WINAPI SHDeleteValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue)
1388 {
1389   DWORD dwRet;
1390   HKEY hSubKey;
1391
1392   TRACE("(hkey=0x%08x,%s,%s)\n", hKey, debugstr_a(lpszSubKey), debugstr_a(lpszValue));
1393
1394   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey);
1395   if (!dwRet)
1396   {
1397     dwRet = RegDeleteValueA(hSubKey, lpszValue);
1398     RegCloseKey(hSubKey);
1399   }
1400   return dwRet;
1401 }
1402
1403 /*************************************************************************
1404  * SHDeleteValueW   [SHLWAPI.@]
1405  *
1406  * See SHDeleteValueA.
1407  */
1408 DWORD WINAPI SHDeleteValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue)
1409 {
1410   DWORD dwRet;
1411   HKEY hSubKey;
1412
1413   TRACE("(hkey=0x%08x,%s,%s)\n", hKey, debugstr_w(lpszSubKey), debugstr_w(lpszValue));
1414
1415   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey);
1416   if (!dwRet)
1417   {
1418     dwRet = RegDeleteValueW(hSubKey, lpszValue);
1419     RegCloseKey(hSubKey);
1420   }
1421   return dwRet;
1422 }
1423
1424 /*************************************************************************
1425  * SHEnumKeyExA   [SHLWAPI.@]
1426  *
1427  * Enumerate sub keys in a registry key.
1428  *
1429  * PARAMS
1430  *   hKey       [I] Handle to registry key
1431  *   dwIndex    [I] Index of key to enumerate
1432  *   lpszSubKey [O] Pointer updated with the subkey name
1433  *   pwLen      [O] Pointer updated with the subkey length
1434  *
1435  * RETURN
1436  *   Success: ERROR_SUCCESS. lpszSubKey and pwLen are updated.
1437  *   Failure: An error code from RegEnumKeyExA.
1438  */
1439 LONG WINAPI SHEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpszSubKey,
1440                          LPDWORD pwLen)
1441 {
1442   TRACE("(hkey=0x%08x,%ld,%s,%p)\n", hKey, dwIndex, debugstr_a(lpszSubKey), pwLen);
1443
1444   return RegEnumKeyExA(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL);
1445 }
1446
1447 /*************************************************************************
1448  * SHEnumKeyExW   [SHLWAPI.@]
1449  *
1450  * See SHEnumKeyExA.
1451  */
1452 LONG WINAPI SHEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpszSubKey,
1453                          LPDWORD pwLen)
1454 {
1455   TRACE("(hkey=0x%08x,%ld,%s,%p)\n", hKey, dwIndex, debugstr_w(lpszSubKey), pwLen);
1456
1457   return RegEnumKeyExW(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL);
1458 }
1459
1460 /*************************************************************************
1461  * SHEnumValueA   [SHLWAPI.@]
1462  *
1463  * Enumerate values in a registry key.
1464  *
1465  * PARAMS
1466  *   hKey      [I] Handle to registry key
1467  *   dwIndex   [I] Index of key to enumerate
1468  *   lpszValue [O] Pointer updated with the values name
1469  *   pwLen     [O] Pointer updated with the values length
1470  *   pwType    [O] Pointer updated with the values type
1471  *   pvData    [O] Pointer updated with the values data
1472  *   pcbData   [O] Pointer updated with the values size
1473  *
1474  * RETURNS
1475  *   Success: ERROR_SUCCESS. Output parameters are updated.
1476  *   Failure: An error code from RegEnumValueExA.
1477  */
1478 LONG WINAPI SHEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpszValue,
1479                          LPDWORD pwLen, LPDWORD pwType,
1480                          LPVOID pvData, LPDWORD pcbData)
1481 {
1482   TRACE("(hkey=0x%08x,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
1483         debugstr_a(lpszValue), pwLen, pwType, pvData, pcbData);
1484
1485  return RegEnumValueA(hKey, dwIndex, lpszValue, pwLen, NULL,
1486                       pwType, pvData, pcbData);
1487 }
1488
1489 /*************************************************************************
1490  * SHEnumValueW   [SHLWAPI.@]
1491  *
1492  * See SHEnumValueA.
1493  */
1494 LONG WINAPI SHEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpszValue,
1495                          LPDWORD pwLen, LPDWORD pwType,
1496                          LPVOID pvData, LPDWORD pcbData)
1497 {
1498   TRACE("(hkey=0x%08x,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
1499         debugstr_w(lpszValue), pwLen, pwType, pvData, pcbData);
1500
1501   return RegEnumValueW(hKey, dwIndex, lpszValue, pwLen, NULL,
1502                        pwType, pvData, pcbData);
1503 }
1504
1505 /*************************************************************************
1506  * @   [SHLWAPI.205]
1507  *
1508  * Wrapper for SHGetValueA in case machine is in safe mode.
1509  */
1510 DWORD WINAPI SHLWAPI_205(HKEY hkey, LPCSTR pSubKey, LPCSTR pValue,
1511                          LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
1512 {
1513   if (GetSystemMetrics(SM_CLEANBOOT))
1514     return ERROR_INVALID_FUNCTION;
1515   return SHGetValueA(hkey, pSubKey, pValue, pwType, pvData, pbData);
1516 }
1517
1518 /*************************************************************************
1519  * @   [SHLWAPI.206]
1520  *
1521  * Unicode version of SHLWAPI_205.
1522  */
1523 DWORD WINAPI SHLWAPI_206(HKEY hkey, LPCWSTR pSubKey, LPCWSTR pValue,
1524                          LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
1525 {
1526   if (GetSystemMetrics(SM_CLEANBOOT))
1527     return ERROR_INVALID_FUNCTION;
1528   return SHGetValueW(hkey, pSubKey, pValue, pwType, pvData, pbData);
1529 }
1530
1531 /*************************************************************************
1532  * @   [SHLWAPI.320]
1533  *
1534  * Set a content type in the registry.
1535  *
1536  * PARAMS
1537  *   hKey       [I] Handle to registry key
1538  *   lpszSubKey [I] Name of sub key under hKey
1539  *   lpszValue  [I] Value to set
1540  *
1541  * RETURNS
1542  *   Success: TRUE
1543  *   Failure: FALSE
1544  */
1545 BOOL WINAPI SHLWAPI_320(LPCSTR lpszSubKey, LPCSTR lpszValue)
1546 {
1547   DWORD dwRet;
1548
1549   if (!lpszValue)
1550   {
1551     WARN("Invalid lpszValue would crash under Win32!");
1552     return FALSE;
1553   }
1554
1555   dwRet = SHSetValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA,
1556                       REG_SZ, lpszValue, strlen(lpszValue));
1557   return dwRet ? FALSE : TRUE;
1558 }
1559
1560 /*************************************************************************
1561  * @   [SHLWAPI.321]
1562  *
1563  * Unicode version of SHLWAPI_320.
1564  */
1565 BOOL WINAPI SHLWAPI_321(LPCWSTR lpszSubKey, LPCWSTR lpszValue)
1566 {
1567   DWORD dwRet;
1568
1569   if (!lpszValue)
1570   {
1571     WARN("Invalid lpszValue would crash under Win32!");
1572     return FALSE;
1573   }
1574
1575   dwRet = SHSetValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW,
1576                       REG_SZ, lpszValue, strlenW(lpszValue));
1577   return dwRet ? FALSE : TRUE;
1578 }
1579
1580 /*************************************************************************
1581  * @   [SHLWAPI.322]
1582  *
1583  * Delete a content type from the registry.
1584  *
1585  * PARAMS
1586  *   lpszSubKey [I] Name of sub key
1587  *
1588  * RETURNS
1589  *   Success: TRUE
1590  *   Failure: FALSE
1591  */
1592 BOOL WINAPI SHLWAPI_322(LPCSTR lpszSubKey)
1593 {
1594   HRESULT ret = SHDeleteValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA);
1595   return ret ? FALSE : TRUE;
1596 }
1597
1598 /*************************************************************************
1599  * @   [SHLWAPI.323]
1600  *
1601  * Unicode version of SHLWAPI_322.
1602  */
1603 BOOL WINAPI SHLWAPI_323(LPCWSTR lpszSubKey)
1604 {
1605   HRESULT ret = SHDeleteValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW);
1606   return ret ? FALSE : TRUE;
1607 }
1608
1609
1610 /*************************************************************************
1611  * SHRegDuplicateHKey   [SHLWAPI.@]
1612  */
1613 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1614 {
1615     HKEY newKey = 0;
1616
1617     RegOpenKeyExA(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1618     TRACE("new key is %08x\n", newKey);
1619     return newKey;
1620 }