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