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