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