Don't prefix %p with 0x.
[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 #include "shlwapi.h"
15 #include "wine/unicode.h"
16
17 DEFAULT_DEBUG_CHANNEL(shell);
18
19 static const char *lpszContentTypeA = "Content Type";
20 static const WCHAR lpszContentTypeW[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
21
22 /* internal structure of what the HUSKEY points to */
23 typedef struct {
24     HKEY     HKCUkey;                  /* HKEY of opened HKCU key      */
25     HKEY     HKLMkey;                  /* HKEY of opened HKLM key      */
26     HKEY     start;                    /* HKEY of where to start       */
27     WCHAR    key_string[MAX_PATH];     /* additional path from 'start' */
28 } Internal_HUSKEY, *LPInternal_HUSKEY;
29
30
31 #define REG_HKCU  TRUE
32 #define REG_HKLM  FALSE
33 /*************************************************************************
34  * REG_GetHKEYFromHUSKEY
35  *
36  * Function:  Return the proper registry key from the HUSKEY structure
37  *            also allow special predefined values.
38  */
39 HKEY REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which)
40 {
41         HKEY test = (HKEY) hUSKey;
42         LPInternal_HUSKEY mihk = (LPInternal_HUSKEY) hUSKey;
43
44         if ((test == HKEY_CLASSES_ROOT)        ||
45             (test == HKEY_CURRENT_CONFIG)      ||
46             (test == HKEY_CURRENT_USER)        ||
47             (test == HKEY_DYN_DATA)            ||
48             (test == HKEY_LOCAL_MACHINE)       ||
49             (test == HKEY_PERFORMANCE_DATA)    ||
50 /* FIXME:  need to define for Win2k, ME, XP
51  *          (test == HKEY_PERFORMANCE_TEXT)    ||
52  *          (test == HKEY_PERFORMANCE_NLSTEXT) ||
53  */
54             (test == HKEY_USERS)) return test;
55         if (which == REG_HKCU) return mihk->HKCUkey;
56         return mihk->HKLMkey;
57 }
58
59
60 /*************************************************************************
61  * SHRegOpenUSKeyA      [SHLWAPI.@]
62  *
63  * Opens a user-specific registry key
64  */
65 LONG WINAPI SHRegOpenUSKeyA(
66         LPCSTR Path,
67         REGSAM AccessType,
68         HUSKEY hRelativeUSKey,
69         PHUSKEY phNewUSKey,
70         BOOL fIgnoreHKCU)
71 {
72     HKEY openHKCUkey=0;
73     HKEY openHKLMkey=0;
74     LONG ret2, ret1 = ~ERROR_SUCCESS;
75     LPInternal_HUSKEY ihky;
76
77     TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_a(Path), 
78           (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey, 
79           (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
80
81     /* now create the internal version of HUSKEY */
82     ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 , 
83                                         sizeof(Internal_HUSKEY));
84     MultiByteToWideChar(0, 0, Path, -1, ihky->key_string,
85                         sizeof(ihky->key_string)-1);
86
87     if (hRelativeUSKey) {
88         openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
89         openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
90     }
91     else {
92         openHKCUkey = HKEY_CURRENT_USER;
93         openHKLMkey = HKEY_LOCAL_MACHINE;
94     }
95
96     ihky->HKCUkey = 0;
97     ihky->HKLMkey = 0;
98     if (!fIgnoreHKCU) {
99         ret1 = RegOpenKeyExA(HKEY_CURRENT_USER, Path, 
100                              0, AccessType, &ihky->HKCUkey);
101         /* if successful, then save real starting point */
102         if (ret1 != ERROR_SUCCESS)
103             ihky->HKCUkey = 0;
104     }
105     ret2 = RegOpenKeyExA(HKEY_LOCAL_MACHINE, Path, 
106                          0, AccessType, &ihky->HKLMkey);
107     if (ret2 != ERROR_SUCCESS)
108         ihky->HKLMkey = 0;
109
110     if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
111         TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
112
113     /* if all attempts have failed then bail */
114     if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
115         HeapFree(GetProcessHeap(), 0, ihky);
116         if (phNewUSKey)
117             *phNewUSKey = (HUSKEY)0;
118         return ret2;
119     }
120
121     TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
122     if (phNewUSKey)
123         *phNewUSKey = (HUSKEY)ihky;
124     return ERROR_SUCCESS;
125 }
126
127 /*************************************************************************
128  * SHRegOpenUSKeyW      [SHLWAPI.@]
129  *
130  * Opens a user-specific registry key
131  */
132 LONG WINAPI SHRegOpenUSKeyW(
133         LPCWSTR Path,
134         REGSAM AccessType,
135         HUSKEY hRelativeUSKey,
136         PHUSKEY phNewUSKey,
137         BOOL fIgnoreHKCU)
138 {
139     HKEY openHKCUkey=0;
140     HKEY openHKLMkey=0;
141     LONG ret2, ret1 = ~ERROR_SUCCESS;
142     LPInternal_HUSKEY ihky;
143
144     TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_w(Path), 
145           (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey, 
146           (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
147
148     /* now create the internal version of HUSKEY */
149     ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 , 
150                                         sizeof(Internal_HUSKEY));
151     lstrcpynW(ihky->key_string, Path, sizeof(ihky->key_string));
152
153     if (hRelativeUSKey) {
154         openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
155         openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
156     }
157     else {
158         openHKCUkey = HKEY_CURRENT_USER;
159         openHKLMkey = HKEY_LOCAL_MACHINE;
160     }
161
162     ihky->HKCUkey = 0;
163     ihky->HKLMkey = 0;
164     if (!fIgnoreHKCU) {
165         ret1 = RegOpenKeyExW(HKEY_CURRENT_USER, Path, 
166                             0, AccessType, &ihky->HKCUkey);
167         /* if successful, then save real starting point */
168         if (ret1 != ERROR_SUCCESS)
169             ihky->HKCUkey = 0;
170     }
171     ret2 = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Path, 
172                         0, AccessType, &ihky->HKLMkey);
173     if (ret2 != ERROR_SUCCESS)
174         ihky->HKLMkey = 0;
175
176     if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
177         TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
178
179     /* if all attempts have failed then bail */
180     if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
181         HeapFree(GetProcessHeap(), 0, ihky);
182         if (phNewUSKey)
183             *phNewUSKey = (HUSKEY)0;
184         return ret2;
185     }
186
187     TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
188     if (phNewUSKey)
189         *phNewUSKey = (HUSKEY)ihky;
190     return ERROR_SUCCESS;
191 }
192
193 /*************************************************************************
194  * SHRegCloseUSKey      [SHLWAPI.@]
195  *
196  * Closes a user-specific registry key
197  */
198 LONG WINAPI SHRegCloseUSKey(
199         HUSKEY hUSKey)
200 {
201     LPInternal_HUSKEY mihk = (LPInternal_HUSKEY)hUSKey;
202     LONG ret = ERROR_SUCCESS;
203
204     if (mihk->HKCUkey)
205         ret = RegCloseKey(mihk->HKCUkey);
206     if (mihk->HKLMkey)
207         ret = RegCloseKey(mihk->HKLMkey);
208     HeapFree(GetProcessHeap(), 0, mihk);
209     return ret;
210 }
211
212 /*************************************************************************
213  *      SHRegQueryUSValueA      [SHLWAPI.@]
214  */
215 LONG WINAPI SHRegQueryUSValueA(
216         HUSKEY hUSKey,             /* [in]  */
217         LPCSTR pszValue,
218         LPDWORD pdwType,
219         LPVOID pvData,
220         LPDWORD pcbData,
221         BOOL fIgnoreHKCU,
222         LPVOID pvDefaultData,
223         DWORD dwDefaultDataSize)
224 {
225         LONG ret = ~ERROR_SUCCESS;
226         LONG i, maxmove;
227         HKEY dokey;
228         CHAR *src, *dst;
229
230         /* if user wants HKCU, and it exists, then try it */
231         if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU)))
232             ret = RegQueryValueExA(dokey, 
233                                    pszValue, 0, pdwType, pvData, pcbData);
234
235         /* if HKCU did not work and HKLM exists, then try it */
236         if ((ret != ERROR_SUCCESS) &&
237             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU)))
238             ret = RegQueryValueExA(dokey,
239                                    pszValue, 0, pdwType, pvData, pcbData);
240
241         /* if neither worked, and default data exists, then use it */
242         if (ret != ERROR_SUCCESS) {
243             if (pvDefaultData && (dwDefaultDataSize != 0)) {
244                 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
245                 src = (CHAR*)pvDefaultData;
246                 dst = (CHAR*)pvData;
247                 for(i=0; i<maxmove; i++) *dst++ = *src++;
248                 *pcbData = maxmove;
249                 TRACE("setting default data\n");
250                 ret = ERROR_SUCCESS;
251             }
252         }
253         return ret;
254 }
255
256
257 /*************************************************************************
258  *      SHRegQueryUSValueW      [SHLWAPI.@]
259  */
260 LONG WINAPI SHRegQueryUSValueW(
261         HUSKEY hUSKey,             /* [in]  */
262         LPCWSTR pszValue,
263         LPDWORD pdwType,
264         LPVOID pvData,
265         LPDWORD pcbData,
266         BOOL fIgnoreHKCU,
267         LPVOID pvDefaultData,
268         DWORD dwDefaultDataSize)
269 {
270         LONG ret = ~ERROR_SUCCESS;
271         LONG i, maxmove;
272         HKEY dokey;
273         CHAR *src, *dst;
274
275         /* if user wants HKCU, and it exists, then try it */
276         if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU)))
277             ret = RegQueryValueExW(dokey, 
278                                    pszValue, 0, pdwType, pvData, pcbData);
279
280         /* if HKCU did not work and HKLM exists, then try it */
281         if ((ret != ERROR_SUCCESS) &&
282             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU)))
283             ret = RegQueryValueExW(dokey,
284                                    pszValue, 0, pdwType, pvData, pcbData);
285
286         /* if neither worked, and default data exists, then use it */
287         if (ret != ERROR_SUCCESS) {
288             if (pvDefaultData && (dwDefaultDataSize != 0)) {
289                 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
290                 src = (CHAR*)pvDefaultData;
291                 dst = (CHAR*)pvData;
292                 for(i=0; i<maxmove; i++) *dst++ = *src++;
293                 *pcbData = maxmove;
294                 TRACE("setting default data\n");
295                 ret = ERROR_SUCCESS;
296             }
297         }
298         return ret;
299 }
300
301 /*************************************************************************
302  * SHRegGetUSValueA     [SHLWAPI.@]
303  *
304  * Gets a user-specific registry value
305  *   Will open the key, query the value, and close the key
306  */
307 LONG WINAPI SHRegGetUSValueA(
308         LPCSTR   pSubKey,
309         LPCSTR   pValue,
310         LPDWORD  pwType,
311         LPVOID   pvData,
312         LPDWORD  pcbData,
313         BOOL     flagIgnoreHKCU,
314         LPVOID   pDefaultData,
315         DWORD    wDefaultDataSize)
316 {
317         HUSKEY myhuskey;
318         LONG ret;
319
320         if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
321         TRACE("key '%s', value '%s', datalen %ld,  %s\n",
322               debugstr_a(pSubKey), debugstr_a(pValue), *pcbData,
323               (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
324
325         ret = SHRegOpenUSKeyA(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
326         if (ret == ERROR_SUCCESS) {
327             ret = SHRegQueryUSValueA(myhuskey, pValue, pwType, pvData,
328                                      pcbData, flagIgnoreHKCU, pDefaultData,
329                                      wDefaultDataSize);
330             SHRegCloseUSKey(myhuskey);
331         }
332         return ret;
333 }
334
335 /*************************************************************************
336  * SHRegGetUSValueW     [SHLWAPI.@]
337  *
338  * Gets a user-specific registry value
339  *   Will open the key, query the value, and close the key
340  */
341 LONG WINAPI SHRegGetUSValueW(
342         LPCWSTR  pSubKey,
343         LPCWSTR  pValue,
344         LPDWORD  pwType,
345         LPVOID   pvData,
346         LPDWORD  pcbData,
347         BOOL     flagIgnoreHKCU,
348         LPVOID   pDefaultData,
349         DWORD    wDefaultDataSize)
350 {
351         HUSKEY myhuskey;
352         LONG ret;
353
354         if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
355         TRACE("key '%s', value '%s', datalen %ld,  %s\n",
356               debugstr_w(pSubKey), debugstr_w(pValue), *pcbData,
357               (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
358
359         ret = SHRegOpenUSKeyW(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
360         if (ret == ERROR_SUCCESS) {
361             ret = SHRegQueryUSValueW(myhuskey, pValue, pwType, pvData,
362                                      pcbData, flagIgnoreHKCU, pDefaultData,
363                                      wDefaultDataSize);
364             SHRegCloseUSKey(myhuskey);
365         }
366         return ret;
367 }
368
369 /*************************************************************************
370  * SHRegGetBoolUSValueA   [SHLWAPI.@]
371  */
372 BOOL WINAPI SHRegGetBoolUSValueA(
373         LPCSTR pszSubKey,
374         LPCSTR pszValue,
375         BOOL fIgnoreHKCU,
376         BOOL fDefault)
377 {
378         LONG retvalue;
379         DWORD type, datalen, work;
380         BOOL ret = fDefault;
381         CHAR data[10];
382
383         TRACE("key '%s', value '%s', %s\n",
384               debugstr_a(pszSubKey), debugstr_a(pszValue),
385               (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
386
387         datalen = sizeof(data)-1;
388         if (!(retvalue = SHRegGetUSValueA( pszSubKey, pszValue, &type, 
389                                            data, &datalen,
390                                            fIgnoreHKCU, 0, 0))) {
391             /* process returned data via type into bool */
392             switch (type) {
393             case REG_SZ:
394                 data[9] = '\0';     /* set end of string */
395                 if (lstrcmpiA(data, "YES") == 0) ret = TRUE;
396                 if (lstrcmpiA(data, "TRUE") == 0) ret = TRUE;
397                 if (lstrcmpiA(data, "NO") == 0) ret = FALSE;
398                 if (lstrcmpiA(data, "FALSE") == 0) ret = FALSE;
399                 break;
400             case REG_DWORD:
401                 work = *(LPDWORD)data;
402                 ret = (work != 0);
403                 break;
404             case REG_BINARY:
405                 if (datalen == 1) {
406                     ret = (data[0] != '\0');
407                     break;
408                 }
409             default:
410                 FIXME("Unsupported registry data type %ld\n", type);
411                 ret = FALSE;
412             }
413             TRACE("got value (type=%ld), returing <%s>\n", type,
414                   (ret) ? "TRUE" : "FALSE");
415         }
416         else {
417             ret = fDefault;
418             TRACE("returning default data <%s>\n",
419                   (ret) ? "TRUE" : "FALSE");
420         }
421         return ret;
422 }
423
424 /*************************************************************************
425  * SHRegGetBoolUSValueW   [SHLWAPI.@]
426  */
427 BOOL WINAPI SHRegGetBoolUSValueW(
428         LPCWSTR pszSubKey,
429         LPCWSTR pszValue,
430         BOOL fIgnoreHKCU,
431         BOOL fDefault)
432 {
433         static const WCHAR wYES[]=  {'Y','E','S','\0'};
434         static const WCHAR wTRUE[]= {'T','R','U','E','\0'};
435         static const WCHAR wNO[]=   {'N','O','\0'};
436         static const WCHAR wFALSE[]={'F','A','L','S','E','\0'};
437         LONG retvalue;
438         DWORD type, datalen, work;
439         BOOL ret = fDefault;
440         WCHAR data[10];
441
442         TRACE("key '%s', value '%s', %s\n",
443               debugstr_w(pszSubKey), debugstr_w(pszValue),
444               (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
445
446         datalen = (sizeof(data)-1) * sizeof(WCHAR);
447         if (!(retvalue = SHRegGetUSValueW( pszSubKey, pszValue, &type, 
448                                            data, &datalen,
449                                            fIgnoreHKCU, 0, 0))) {
450             /* process returned data via type into bool */
451             switch (type) {
452             case REG_SZ:
453                 data[9] = L'\0';     /* set end of string */
454                 if (lstrcmpiW(data, wYES)==0 || lstrcmpiW(data, wTRUE)==0)
455                     ret = TRUE;
456                 else if (lstrcmpiW(data, wNO)==0 || lstrcmpiW(data, wFALSE)==0)
457                     ret = FALSE;
458                 break;
459             case REG_DWORD:
460                 work = *(LPDWORD)data;
461                 ret = (work != 0);
462                 break;
463             case REG_BINARY:
464                 if (datalen == 1) {
465                     ret = (data[0] != L'\0');
466                     break;
467                 }
468             default:
469                 FIXME("Unsupported registry data type %ld\n", type);
470                 ret = FALSE;
471             }
472             TRACE("got value (type=%ld), returing <%s>\n", type,
473                   (ret) ? "TRUE" : "FALSE");
474         }
475         else {
476             ret = fDefault;
477             TRACE("returning default data <%s>\n",
478                   (ret) ? "TRUE" : "FALSE");
479         }
480         return ret;
481 }
482
483 /*************************************************************************
484  *      SHRegQueryInfoUSKeyA    [SHLWAPI.@]
485  */
486 DWORD WINAPI SHRegQueryInfoUSKeyA(
487         HUSKEY hUSKey,             /* [in]  */
488         LPDWORD pcSubKeys,
489         LPDWORD pcchMaxSubKeyLen,
490         LPDWORD pcValues,
491         LPDWORD pcchMaxValueNameLen,
492         SHREGENUM_FLAGS enumRegFlags)
493 {
494         HKEY dokey;
495         LONG ret;
496
497         TRACE("(0x%lx,%p,%p,%p,%p,%d)\n",
498               (LONG)hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
499               pcchMaxValueNameLen,enumRegFlags);
500
501         /* if user wants HKCU, and it exists, then try it */
502         if (((enumRegFlags == SHREGENUM_HKCU) ||
503              (enumRegFlags == SHREGENUM_DEFAULT)) && 
504             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
505             ret = RegQueryInfoKeyA(dokey, 0, 0, 0,
506                                    pcSubKeys, pcchMaxSubKeyLen, 0,
507                                    pcValues, pcchMaxValueNameLen, 0, 0, 0);
508             if ((ret == ERROR_SUCCESS) ||
509                 (enumRegFlags == SHREGENUM_HKCU)) 
510                 return ret;
511         }
512         if (((enumRegFlags == SHREGENUM_HKLM) ||
513              (enumRegFlags == SHREGENUM_DEFAULT)) && 
514             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
515             return RegQueryInfoKeyA(dokey, 0, 0, 0,
516                                     pcSubKeys, pcchMaxSubKeyLen, 0,
517                                     pcValues, pcchMaxValueNameLen, 0, 0, 0);
518         }
519         return ERROR_INVALID_FUNCTION;
520 }
521
522 /*************************************************************************
523  *      SHRegQueryInfoUSKeyW    [SHLWAPI.@]
524  */
525 DWORD WINAPI SHRegQueryInfoUSKeyW(
526         HUSKEY hUSKey,             /* [in]  */
527         LPDWORD pcSubKeys,
528         LPDWORD pcchMaxSubKeyLen,
529         LPDWORD pcValues,
530         LPDWORD pcchMaxValueNameLen,
531         SHREGENUM_FLAGS enumRegFlags)
532 {
533         HKEY dokey;
534         LONG ret;
535
536         TRACE("(0x%lx,%p,%p,%p,%p,%d)\n",
537               (LONG)hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
538               pcchMaxValueNameLen,enumRegFlags);
539
540         /* if user wants HKCU, and it exists, then try it */
541         if (((enumRegFlags == SHREGENUM_HKCU) ||
542              (enumRegFlags == SHREGENUM_DEFAULT)) && 
543             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
544             ret = RegQueryInfoKeyW(dokey, 0, 0, 0,
545                                    pcSubKeys, pcchMaxSubKeyLen, 0,
546                                    pcValues, pcchMaxValueNameLen, 0, 0, 0);
547             if ((ret == ERROR_SUCCESS) ||
548                 (enumRegFlags == SHREGENUM_HKCU)) 
549                 return ret;
550         }
551         if (((enumRegFlags == SHREGENUM_HKLM) ||
552              (enumRegFlags == SHREGENUM_DEFAULT)) && 
553             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
554             return RegQueryInfoKeyW(dokey, 0, 0, 0,
555                                     pcSubKeys, pcchMaxSubKeyLen, 0,
556                                     pcValues, pcchMaxValueNameLen, 0, 0, 0);
557         }
558         return ERROR_INVALID_FUNCTION;
559 }
560
561 /*************************************************************************
562  *      SHRegEnumUSKeyA         [SHLWAPI.@]
563  */
564 LONG WINAPI SHRegEnumUSKeyA(
565         HUSKEY hUSKey,                 /* [in]  */
566         DWORD dwIndex,
567         LPSTR pszName,
568         LPDWORD pcchValueNameLen,
569         SHREGENUM_FLAGS enumRegFlags)  /* [in]  */
570 {
571         FIXME("%s stub\n",debugstr_a(pszName));
572         return ERROR_NO_MORE_ITEMS;
573 }
574
575 /*************************************************************************
576  *      SHRegEnumUSKeyW         [SHLWAPI.@]
577  */
578 LONG WINAPI SHRegEnumUSKeyW(
579         HUSKEY hUSKey,                 /* [in]  */
580         DWORD dwIndex,
581         LPWSTR pszName,
582         LPDWORD pcchValueNameLen,
583         SHREGENUM_FLAGS enumRegFlags)  /* [in]  */
584 {
585         FIXME("%s stub\n",debugstr_w(pszName));
586         return ERROR_NO_MORE_ITEMS;
587 }
588
589 /*************************************************************************
590  * SHRegGetPathA   [SHLWAPI.@]
591  */
592 DWORD WINAPI SHRegGetPathA(
593         HKEY hKey,
594         LPCSTR pcszSubKey,
595         LPCSTR pcszValue,
596         LPSTR pszPath,
597         DWORD dwFlags)
598 {
599         FIXME("%s %s\n", pcszSubKey, pcszValue);
600         return 0;
601 }
602
603 /*************************************************************************
604  * SHRegGetPathW   [SHLWAPI.@]
605  */
606 DWORD WINAPI SHRegGetPathW(
607         HKEY hKey,
608         LPCWSTR pcszSubKey,
609         LPCWSTR pcszValue,
610         LPWSTR pszPath,
611         DWORD dwFlags)
612 {
613         FIXME("%s %s\n", debugstr_w(pcszSubKey), debugstr_w(pcszValue));
614         return 0;
615 }
616
617 /*************************************************************************
618  * SHGetValueA   [SHLWAPI.@]
619  *
620  * Gets a value from the registry
621  */
622 DWORD WINAPI SHGetValueA(
623         HKEY     hkey,
624         LPCSTR   pSubKey,
625         LPCSTR   pValue,
626         LPDWORD  pwType,
627         LPVOID   pvData,
628         LPDWORD  pbData)
629 {
630         HKEY hSubKey;
631         DWORD res;
632
633         TRACE("(%s %s)\n", pSubKey, pValue);
634
635         if((res = RegOpenKeyA(hkey, pSubKey, &hSubKey))) return res;
636         res = RegQueryValueExA(hSubKey, pValue, 0, pwType, pvData, pbData);
637         RegCloseKey( hSubKey );
638
639         return res;
640 }
641
642 /*************************************************************************
643  * SHGetValueW   [SHLWAPI.@]
644  *
645  * Gets a value from the registry
646  */
647 DWORD WINAPI SHGetValueW(
648         HKEY     hkey,
649         LPCWSTR  pSubKey,
650         LPCWSTR  pValue,
651         LPDWORD  pwType,
652         LPVOID   pvData,
653         LPDWORD  pbData)
654 {
655         HKEY hSubKey;
656         DWORD res;
657
658         TRACE("(%s %s)\n", debugstr_w(pSubKey), debugstr_w(pValue));
659
660         if((res = RegOpenKeyW(hkey, pSubKey, &hSubKey))) return res;
661         res = RegQueryValueExW(hSubKey, pValue, 0, pwType, pvData, pbData);
662         RegCloseKey( hSubKey );
663
664         return res;
665 }
666
667 /*************************************************************************
668  *      SHSetValueA   [SHLWAPI.@]
669  */
670 HRESULT WINAPI SHSetValueA(
671         HKEY hkey,
672         LPCSTR pszSubKey,
673         LPCSTR pszValue,
674         DWORD dwType,
675         LPCVOID pvData,
676         DWORD cbData)
677 {
678     HKEY        subkey;
679     HRESULT     hres;
680
681     hres = RegCreateKeyA(hkey,pszSubKey,&subkey);
682     if (!hres)
683         return hres;
684     hres = RegSetValueExA(subkey,pszValue,0,dwType,pvData,cbData);
685     RegCloseKey(subkey);
686     return hres;
687 }
688
689 /*************************************************************************
690  *      SHSetValueW   [SHLWAPI.@]
691  */
692 HRESULT WINAPI SHSetValueW(
693         HKEY hkey,
694         LPCWSTR pszSubKey,
695         LPCWSTR pszValue,
696         DWORD dwType,
697         LPCVOID pvData,
698         DWORD cbData)
699 {
700     HKEY        subkey;
701     HRESULT     hres;
702
703     hres = RegCreateKeyW(hkey,pszSubKey,&subkey);
704     if (!hres)
705         return hres;
706     hres = RegSetValueExW(subkey,pszValue,0,dwType,pvData,cbData);
707     RegCloseKey(subkey);
708     return hres;
709 }
710
711 /*************************************************************************
712  * SHQueryValueExA              [SHLWAPI.@]
713  *
714  */
715 HRESULT WINAPI SHQueryValueExA(
716         HKEY hkey,
717         LPSTR lpValueName,
718         LPDWORD lpReserved,
719         LPDWORD lpType,
720         LPBYTE lpData,
721         LPDWORD lpcbData)
722 {
723         TRACE("0x%04x %s %p %p %p %p\n", hkey, lpValueName, lpReserved, lpType, lpData, lpcbData);
724         return RegQueryValueExA (hkey, lpValueName, lpReserved, lpType, lpData, lpcbData);
725 }
726
727
728 /*************************************************************************
729  * SHQueryValueExW   [SHLWAPI.@]
730  *
731  * FIXME 
732  *  if the datatype REG_EXPAND_SZ then expand the string and change
733  *  *pdwType to REG_SZ.
734  */
735 HRESULT WINAPI SHQueryValueExW (
736         HKEY hkey,
737         LPWSTR pszValue,
738         LPDWORD pdwReserved,
739         LPDWORD pdwType,
740         LPVOID pvData,
741         LPDWORD pcbData)
742 {
743         WARN("0x%04x %s %p %p %p %p semi-stub\n",
744              hkey, debugstr_w(pszValue), pdwReserved, pdwType, pvData, pcbData);
745         return RegQueryValueExW ( hkey, pszValue, pdwReserved, pdwType, pvData, pcbData);
746 }
747
748 /*************************************************************************
749  * SHDeleteKeyA   [SHLWAPI.@]
750  *
751  * It appears this function is made available to account for the differences
752  * between the Win9x and WinNT/2k RegDeleteKeyA functions.
753  *
754  * According to docs, Win9x RegDeleteKeyA will delete all subkeys, whereas
755  * WinNt/2k will only delete the key if empty.
756  */
757 HRESULT WINAPI SHDeleteKeyA(
758         HKEY hKey,
759         LPCSTR lpszSubKey)
760 {
761     DWORD r, dwKeyCount, dwSize, i, dwMaxSubkeyLen;
762     HKEY hSubKey;
763     LPSTR lpszName;
764
765     TRACE("hkey=0x%08x, %s\n", hKey, debugstr_a(lpszSubKey));
766
767     hSubKey = 0;
768     r = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
769     if(r != ERROR_SUCCESS)
770         return r;
771
772     /* find how many subkeys there are */
773     dwKeyCount = 0;
774     dwMaxSubkeyLen = 0;
775     r = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
776                     &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
777     if(r != ERROR_SUCCESS)
778     {
779         RegCloseKey(hSubKey);
780         return r;
781     }
782
783     /* alloc memory for the longest string terminating 0 */
784     dwMaxSubkeyLen++;
785     lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(CHAR));
786     if(!lpszName)
787     {
788         RegCloseKey(hSubKey);
789         return ERROR_NOT_ENOUGH_MEMORY;
790     }
791
792     /* recursively delete all the subkeys */
793     for(i=0; i<dwKeyCount; i++)
794     {
795         dwSize = dwMaxSubkeyLen;
796         r = RegEnumKeyExA(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
797         if(r != ERROR_SUCCESS)
798             break;
799         r = SHDeleteKeyA(hSubKey, lpszName);
800         if(r != ERROR_SUCCESS)
801             break;
802     }
803
804     HeapFree(GetProcessHeap(), 0, lpszName);
805
806     RegCloseKey(hSubKey);
807
808     if(r == ERROR_SUCCESS)
809         r = RegDeleteKeyA(hKey, lpszSubKey);
810
811     return r;
812 }
813
814 /*************************************************************************
815  * SHDeleteKeyW   [SHLWAPI.@]
816  *
817  * It appears this function is made available to account for the differences
818  * between the Win9x and WinNT/2k RegDeleteKeyA functions.
819  *
820  * According to docs, Win9x RegDeleteKeyA will delete all subkeys, whereas
821  * WinNt/2k will only delete the key if empty.
822  */
823 HRESULT WINAPI SHDeleteKeyW(
824         HKEY hkey,
825         LPCWSTR pszSubKey)
826 {
827         FIXME("hkey=0x%08x, %s\n", hkey, debugstr_w(pszSubKey));
828         return 0;
829 }
830
831 /*************************************************************************
832  * SHDeleteValueA   [SHLWAPI.@]
833  *
834  * Function opens the key, get/set/delete the value, then close the key.
835  */
836 HRESULT WINAPI SHDeleteValueA(HKEY hkey, LPCSTR pszSubKey, LPCSTR pszValue) {
837     HKEY        subkey;
838     HRESULT     hres;
839
840     hres = RegOpenKeyA(hkey,pszSubKey,&subkey);
841     if (hres)
842         return hres;
843     hres = RegDeleteValueA(subkey,pszValue);
844     RegCloseKey(subkey);
845     return hres;
846 }
847
848 /*************************************************************************
849  * SHDeleteValueW   [SHLWAPI.@]
850  *
851  * Function opens the key, get/set/delete the value, then close the key.
852  */
853 HRESULT WINAPI SHDeleteValueW(HKEY hkey, LPCWSTR pszSubKey, LPCWSTR pszValue) {
854     HKEY        subkey;
855     HRESULT     hres;
856
857     hres = RegOpenKeyW(hkey,pszSubKey,&subkey);
858     if (hres)
859         return hres;
860     hres = RegDeleteValueW(subkey,pszValue);
861     RegCloseKey(subkey);
862     return hres;
863 }
864
865 /*************************************************************************
866  * SHDeleteEmptyKeyA   [SHLWAPI.@]
867  *
868  * It appears this function is made available to account for the differences
869  * between the Win9x and WinNT/2k RegDeleteKeyA functions.
870  *
871  * According to docs, Win9x RegDeleteKeyA will delete all subkeys, whereas
872  * WinNt/2k will only delete the key if empty.
873  */
874 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hKey, LPCSTR lpszSubKey)
875 {
876     DWORD r, dwKeyCount;
877     HKEY hSubKey;
878
879     TRACE("hkey=0x%08x, %s\n", hKey, debugstr_a(lpszSubKey));
880
881     hSubKey = 0;
882     r = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
883     if(r != ERROR_SUCCESS)
884         return r;
885
886     dwKeyCount = 0;
887     r = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
888                     NULL, NULL, NULL, NULL, NULL, NULL, NULL);
889     if(r != ERROR_SUCCESS)
890         return r;
891
892     RegCloseKey(hSubKey);
893
894     if(dwKeyCount)
895         return ERROR_KEY_HAS_CHILDREN;
896
897     r = RegDeleteKeyA(hKey, lpszSubKey);
898
899     return r;
900 }
901
902 /*************************************************************************
903  * SHDeleteEmptyKeyW   [SHLWAPI.@]
904  *
905  * It appears this function is made available to account for the differences
906  * between the Win9x and WinNT/2k RegDeleteKeyA functions.
907  *
908  * According to docs, Win9x RegDeleteKeyA will delete all subkeys, whereas
909  * WinNt/2k will only delete the key if empty.
910  */
911 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hKey, LPCWSTR lpszSubKey)
912 {
913     FIXME("hkey=0x%08x, %s\n", hKey, debugstr_w(lpszSubKey));
914     return 0;
915 }
916
917 /*************************************************************************
918  * @   [SHLWAPI.205]
919  *
920  * Wrapper for SHGetValueA in case machine is in safe mode.
921  */
922 DWORD WINAPI SHLWAPI_205(HKEY hkey, LPCSTR pSubKey, LPCSTR pValue,
923                          LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
924 {
925   if (GetSystemMetrics(SM_CLEANBOOT))
926     return ERROR_INVALID_FUNCTION;
927   return SHGetValueA(hkey, pSubKey, pValue, pwType, pvData, pbData);
928 }
929
930 /*************************************************************************
931  * @   [SHLWAPI.206]
932  *
933  * Unicode version of SHLWAPI_205.
934  */
935 DWORD WINAPI SHLWAPI_206(HKEY hkey, LPCWSTR pSubKey, LPCWSTR pValue,
936                          LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
937 {
938   if (GetSystemMetrics(SM_CLEANBOOT))
939     return ERROR_INVALID_FUNCTION;
940   return SHGetValueW(hkey, pSubKey, pValue, pwType, pvData, pbData);
941 }
942
943 /*************************************************************************
944  * @   [SHLWAPI.320]
945  *
946  */
947 BOOL WINAPI SHLWAPI_320(LPCSTR lpszSubKey, LPCSTR lpszValue)
948 {
949   DWORD dwLen = strlen(lpszValue);
950   HRESULT ret = SHSetValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA,
951                             REG_SZ, lpszValue, dwLen);
952   return ret ? FALSE : TRUE;
953 }
954
955 /*************************************************************************
956  * @   [SHLWAPI.321]
957  *
958  * Unicode version of SHLWAPI_320.
959  */
960 BOOL WINAPI SHLWAPI_321(LPCWSTR lpszSubKey, LPCWSTR lpszValue)
961 {
962   DWORD dwLen = strlenW(lpszValue);
963   HRESULT ret = SHSetValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW,
964                             REG_SZ, lpszValue, dwLen);
965   return ret ? FALSE : TRUE;
966 }
967
968 /*************************************************************************
969  * @   [SHLWAPI.322]
970  *
971  */
972 BOOL WINAPI SHLWAPI_322(LPCSTR lpszSubKey)
973 {
974   HRESULT ret = SHDeleteValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA);
975   return ret ? FALSE : TRUE;
976 }
977
978 /*************************************************************************
979  * @   [SHLWAPI.323]
980  *
981  * Unicode version of SHLWAPI_322.
982  */
983 BOOL WINAPI SHLWAPI_323(LPCWSTR lpszSubKey)
984 {
985   HRESULT ret = SHDeleteValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW);
986   return ret ? FALSE : TRUE;
987 }
988