- fix broadcast address for name lookups after iphlpapi change
[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     HKCUkey;                  /* HKEY of opened HKCU key      */
51     HKEY     HKLMkey;                  /* HKEY of opened HKLM key      */
52     HKEY     start;                    /* HKEY of where to start       */
53     WCHAR    key_string[MAX_PATH];     /* additional path from 'start' */
54 } Internal_HUSKEY, *LPInternal_HUSKEY;
55
56 DWORD   WINAPI SHStringFromGUIDW(REFGUID,LPWSTR,INT);
57 HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID,LPCWSTR,BOOL,BOOL,PHKEY);
58
59
60 #define REG_HKCU  TRUE
61 #define REG_HKLM  FALSE
62 /*************************************************************************
63  * REG_GetHKEYFromHUSKEY
64  *
65  * Function:  Return the proper registry key from the HUSKEY structure
66  *            also allow special predefined values.
67  */
68 static HKEY WINAPI REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which)
69 {
70         HKEY test = (HKEY) hUSKey;
71         LPInternal_HUSKEY mihk = (LPInternal_HUSKEY) hUSKey;
72
73         if ((test == HKEY_CLASSES_ROOT)        ||
74             (test == HKEY_CURRENT_CONFIG)      ||
75             (test == HKEY_CURRENT_USER)        ||
76             (test == HKEY_DYN_DATA)            ||
77             (test == HKEY_LOCAL_MACHINE)       ||
78             (test == HKEY_PERFORMANCE_DATA)    ||
79 /* FIXME:  need to define for Win2k, ME, XP
80  *          (test == HKEY_PERFORMANCE_TEXT)    ||
81  *          (test == HKEY_PERFORMANCE_NLSTEXT) ||
82  */
83             (test == HKEY_USERS)) return test;
84         if (which == REG_HKCU) return mihk->HKCUkey;
85         return mihk->HKLMkey;
86 }
87
88
89 /*************************************************************************
90  * SHRegOpenUSKeyA      [SHLWAPI.@]
91  *
92  * Opens a user-specific registry key
93  *
94  * RETURNS
95  *  Success: ERROR_SUCCESS
96  *  Failure: An error code from RegOpenKeyExA().
97  */
98 LONG WINAPI SHRegOpenUSKeyA(
99         LPCSTR Path, /* [I] Key name to open */
100         REGSAM AccessType, /* [I] Access type */
101         HUSKEY hRelativeUSKey, /* [I] Relative user key */
102         PHUSKEY phNewUSKey, /* [O] Destination for created key */
103         BOOL fIgnoreHKCU)  /* [I] TRUE=Don't check HKEY_CURRENT_USER */
104 {
105     HKEY openHKCUkey=0;
106     HKEY openHKLMkey=0;
107     LONG ret2, ret1 = ~ERROR_SUCCESS;
108     LPInternal_HUSKEY ihky;
109
110     TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_a(Path),
111           (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey,
112           (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
113
114     /* now create the internal version of HUSKEY */
115     ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 ,
116                                         sizeof(Internal_HUSKEY));
117     MultiByteToWideChar(0, 0, Path, -1, ihky->key_string,
118                         sizeof(ihky->key_string)-1);
119
120     if (hRelativeUSKey) {
121         openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
122         openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
123     }
124     else {
125         openHKCUkey = HKEY_CURRENT_USER;
126         openHKLMkey = HKEY_LOCAL_MACHINE;
127     }
128
129     ihky->HKCUkey = 0;
130     ihky->HKLMkey = 0;
131     if (!fIgnoreHKCU) {
132         ret1 = RegOpenKeyExA(openHKCUkey, Path,
133                              0, AccessType, &ihky->HKCUkey);
134         /* if successful, then save real starting point */
135         if (ret1 != ERROR_SUCCESS)
136             ihky->HKCUkey = 0;
137     }
138     ret2 = RegOpenKeyExA(openHKLMkey, Path,
139                          0, AccessType, &ihky->HKLMkey);
140     if (ret2 != ERROR_SUCCESS)
141         ihky->HKLMkey = 0;
142
143     if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
144         TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
145
146     /* if all attempts have failed then bail */
147     if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
148         HeapFree(GetProcessHeap(), 0, ihky);
149         if (phNewUSKey)
150             *phNewUSKey = NULL;
151         return ret2;
152     }
153
154     TRACE("HUSKEY=%p\n", ihky);
155     if (phNewUSKey)
156         *phNewUSKey = (HUSKEY)ihky;
157     return ERROR_SUCCESS;
158 }
159
160 /*************************************************************************
161  * SHRegOpenUSKeyW      [SHLWAPI.@]
162  *
163  * See SHRegOpenUSKeyA.
164  */
165 LONG WINAPI SHRegOpenUSKeyW(
166         LPCWSTR Path,
167         REGSAM AccessType,
168         HUSKEY hRelativeUSKey,
169         PHUSKEY phNewUSKey,
170         BOOL fIgnoreHKCU)
171 {
172     HKEY openHKCUkey=0;
173     HKEY openHKLMkey=0;
174     LONG ret2, ret1 = ~ERROR_SUCCESS;
175     LPInternal_HUSKEY ihky;
176
177     TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_w(Path),
178           (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey,
179           (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
180
181     /* now create the internal version of HUSKEY */
182     ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 ,
183                                         sizeof(Internal_HUSKEY));
184     lstrcpynW(ihky->key_string, Path, sizeof(ihky->key_string));
185
186     if (hRelativeUSKey) {
187         openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
188         openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
189     }
190     else {
191         openHKCUkey = HKEY_CURRENT_USER;
192         openHKLMkey = HKEY_LOCAL_MACHINE;
193     }
194
195     ihky->HKCUkey = 0;
196     ihky->HKLMkey = 0;
197     if (!fIgnoreHKCU) {
198         ret1 = RegOpenKeyExW(openHKCUkey, Path,
199                             0, AccessType, &ihky->HKCUkey);
200         /* if successful, then save real starting point */
201         if (ret1 != ERROR_SUCCESS)
202             ihky->HKCUkey = 0;
203     }
204     ret2 = RegOpenKeyExW(openHKLMkey, Path,
205                         0, AccessType, &ihky->HKLMkey);
206     if (ret2 != ERROR_SUCCESS)
207         ihky->HKLMkey = 0;
208
209     if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
210         TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
211
212     /* if all attempts have failed then bail */
213     if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
214         HeapFree(GetProcessHeap(), 0, ihky);
215         if (phNewUSKey)
216             *phNewUSKey = NULL;
217         return ret2;
218     }
219
220     TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
221     if (phNewUSKey)
222         *phNewUSKey = (HUSKEY)ihky;
223     return ERROR_SUCCESS;
224 }
225
226 /*************************************************************************
227  * SHRegCloseUSKey      [SHLWAPI.@]
228  *
229  * Close a user-specific registry key
230  *
231  * RETURNS
232  *  Success: ERROR_SUCCESS
233  *  Failure: An error code from RegCloseKey().
234  */
235 LONG WINAPI SHRegCloseUSKey(
236         HUSKEY hUSKey) /* [I] Key to close */
237 {
238     LPInternal_HUSKEY mihk = (LPInternal_HUSKEY)hUSKey;
239     LONG ret = ERROR_SUCCESS;
240
241     if (mihk->HKCUkey)
242         ret = RegCloseKey(mihk->HKCUkey);
243     if (mihk->HKLMkey)
244         ret = RegCloseKey(mihk->HKLMkey);
245     HeapFree(GetProcessHeap(), 0, mihk);
246     return ret;
247 }
248
249 /*************************************************************************
250  *      SHRegQueryUSValueA      [SHLWAPI.@]
251  *
252  * Query a user-specific registry value.
253  *
254  * RETURNS
255  *  Success: ERROR_SUCCESS
256  *  Failure: An error code from RegQueryValueExA().
257  */
258 LONG WINAPI SHRegQueryUSValueA(
259         HUSKEY hUSKey, /* [I] Key to query */
260         LPCSTR pszValue, /* [I] Value name under hUSKey */
261         LPDWORD pdwType, /* [O] Destination for value type */
262         LPVOID pvData, /* [O] Destination for value data */
263         LPDWORD pcbData, /* [O] Destination for value length */
264         BOOL fIgnoreHKCU,  /* [I] TRUE=Don't check HKEY_CURRENT_USER */
265         LPVOID pvDefaultData, /* [I] Default data if pszValue does not exist */
266         DWORD dwDefaultDataSize) /* [I] Length of pvDefaultData */
267 {
268         LONG ret = ~ERROR_SUCCESS;
269         LONG i, maxmove;
270         HKEY dokey;
271         CHAR *src, *dst;
272
273         /* if user wants HKCU, and it exists, then try it */
274         if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
275             ret = RegQueryValueExA(dokey,
276                                    pszValue, 0, pdwType, pvData, pcbData);
277             TRACE("HKCU RegQueryValue returned %08lx\n", ret);
278         }
279
280         /* if HKCU did not work and HKLM exists, then try it */
281         if ((ret != ERROR_SUCCESS) &&
282             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
283             ret = RegQueryValueExA(dokey,
284                                    pszValue, 0, pdwType, pvData, pcbData);
285             TRACE("HKLM RegQueryValue returned %08lx\n", ret);
286         }
287
288         /* if neither worked, and default data exists, then use it */
289         if (ret != ERROR_SUCCESS) {
290             if (pvDefaultData && (dwDefaultDataSize != 0)) {
291                 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
292                 src = (CHAR*)pvDefaultData;
293                 dst = (CHAR*)pvData;
294                 for(i=0; i<maxmove; i++) *dst++ = *src++;
295                 *pcbData = maxmove;
296                 TRACE("setting default data\n");
297                 ret = ERROR_SUCCESS;
298             }
299         }
300         return ret;
301 }
302
303
304 /*************************************************************************
305  *      SHRegQueryUSValueW      [SHLWAPI.@]
306  *
307  * See SHRegQueryUSValueA.
308  */
309 LONG WINAPI SHRegQueryUSValueW(
310         HUSKEY hUSKey,
311         LPCWSTR pszValue,
312         LPDWORD pdwType,
313         LPVOID pvData,
314         LPDWORD pcbData,
315         BOOL fIgnoreHKCU,
316         LPVOID pvDefaultData,
317         DWORD dwDefaultDataSize)
318 {
319         LONG ret = ~ERROR_SUCCESS;
320         LONG i, maxmove;
321         HKEY dokey;
322         CHAR *src, *dst;
323
324         /* if user wants HKCU, and it exists, then try it */
325         if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
326             ret = RegQueryValueExW(dokey,
327                                    pszValue, 0, pdwType, pvData, pcbData);
328             TRACE("HKCU RegQueryValue returned %08lx\n", ret);
329         }
330
331         /* if HKCU did not work and HKLM exists, then try it */
332         if ((ret != ERROR_SUCCESS) &&
333             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
334             ret = RegQueryValueExW(dokey,
335                                    pszValue, 0, pdwType, pvData, pcbData);
336             TRACE("HKLM RegQueryValue returned %08lx\n", ret);
337         }
338
339         /* if neither worked, and default data exists, then use it */
340         if (ret != ERROR_SUCCESS) {
341             if (pvDefaultData && (dwDefaultDataSize != 0)) {
342                 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
343                 src = (CHAR*)pvDefaultData;
344                 dst = (CHAR*)pvData;
345                 for(i=0; i<maxmove; i++) *dst++ = *src++;
346                 *pcbData = maxmove;
347                 TRACE("setting default data\n");
348                 ret = ERROR_SUCCESS;
349             }
350         }
351         return ret;
352 }
353
354 /*************************************************************************
355  * SHRegGetUSValueA     [SHLWAPI.@]
356  *
357  * Get a user-specific registry value.
358  *
359  * RETURNS
360  *  Success: ERROR_SUCCESS
361  *  Failure: An error code from SHRegOpenUSKeyA() or SHRegQueryUSValueA().
362  *
363  * NOTES
364  *   This function opens pSubKey, queries the value, and then closes the key.
365  */
366 LONG WINAPI SHRegGetUSValueA(
367         LPCSTR   pSubKey, /* [I] Key name to open */
368         LPCSTR   pValue, /* [I] Value name to open */
369         LPDWORD  pwType, /* [O] Destination for the type of the value */
370         LPVOID   pvData, /* [O] Destination for the value */
371         LPDWORD  pcbData, /* [I] Destination for the length of the value **/
372         BOOL     flagIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */
373         LPVOID   pDefaultData, /* [I] Default value if it doesn't exist */
374         DWORD    wDefaultDataSize) /* [I] Length of pDefaultData */
375 {
376         HUSKEY myhuskey;
377         LONG ret;
378
379         if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
380         TRACE("key '%s', value '%s', datalen %ld,  %s\n",
381               debugstr_a(pSubKey), debugstr_a(pValue), *pcbData,
382               (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
383
384         ret = SHRegOpenUSKeyA(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
385         if (ret == ERROR_SUCCESS) {
386             ret = SHRegQueryUSValueA(myhuskey, pValue, pwType, pvData,
387                                      pcbData, flagIgnoreHKCU, pDefaultData,
388                                      wDefaultDataSize);
389             SHRegCloseUSKey(myhuskey);
390         }
391         return ret;
392 }
393
394 /*************************************************************************
395  * SHRegGetUSValueW     [SHLWAPI.@]
396  *
397  * See SHRegGetUSValueA.
398  */
399 LONG WINAPI SHRegGetUSValueW(
400         LPCWSTR  pSubKey,
401         LPCWSTR  pValue,
402         LPDWORD  pwType,
403         LPVOID   pvData,
404         LPDWORD  pcbData,
405         BOOL     flagIgnoreHKCU,
406         LPVOID   pDefaultData,
407         DWORD    wDefaultDataSize)
408 {
409         HUSKEY myhuskey;
410         LONG ret;
411
412         if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
413         TRACE("key '%s', value '%s', datalen %ld,  %s\n",
414               debugstr_w(pSubKey), debugstr_w(pValue), *pcbData,
415               (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
416
417         ret = SHRegOpenUSKeyW(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
418         if (ret == ERROR_SUCCESS) {
419             ret = SHRegQueryUSValueW(myhuskey, pValue, pwType, pvData,
420                                      pcbData, flagIgnoreHKCU, pDefaultData,
421                                      wDefaultDataSize);
422             SHRegCloseUSKey(myhuskey);
423         }
424         return ret;
425 }
426
427 /*************************************************************************
428  * SHRegSetUSValueA   [SHLWAPI.@]
429  *
430  * Set a user-specific registry value.
431  *
432  * RETURNS
433  *  Success: ERROR_SUCCESS
434  *  Failure: An error code from SHRegOpenUSKeyA() or SHRegWriteUSValueA(), or
435  *           ERROR_INVALID_FUNCTION if pvData is NULL.
436  *
437  * NOTES
438  *   This function opens pszSubKey, sets the value, and then closes the key.
439  */
440 LONG WINAPI SHRegSetUSValueA(
441         LPCSTR pszSubKey, /* [I] Name of key to set the value in */
442         LPCSTR pszValue, /* [I] Name of value under pszSubKey to set the value in */
443         DWORD  dwType, /* [I] Type of the value */
444         LPVOID pvData, /* [I] Data to set as the value */
445         DWORD  cbData, /* [I] length of pvData */
446         DWORD  dwFlags) /* [I] SHREGSET_ flags from "shlwapi.h" */
447 {
448         HUSKEY myhuskey;
449         LONG   ret;
450         BOOL   ignoreHKCU;
451
452         if (!pvData) return ERROR_INVALID_FUNCTION;
453         TRACE("key '%s', value '%s', datalen %ld\n",
454               debugstr_a(pszSubKey), debugstr_a(pszValue), cbData);
455
456         ignoreHKCU = ((dwFlags == SHREGSET_HKLM) || (dwFlags == SHREGSET_FORCE_HKLM));
457
458         ret = SHRegOpenUSKeyA(pszSubKey, 0x1, 0, &myhuskey, ignoreHKCU);
459         if (ret == ERROR_SUCCESS) {
460           ret = SHRegWriteUSValueA(myhuskey, pszValue, dwType, pvData,
461                                    cbData, dwFlags);
462             SHRegCloseUSKey(myhuskey);
463         }
464         return ret;
465 }
466
467 /*************************************************************************
468  * SHRegSetUSValueW   [SHLWAPI.@]
469  *
470  * See SHRegSetUSValueA.
471  */
472 LONG WINAPI SHRegSetUSValueW(
473         LPCWSTR pszSubKey,
474         LPCWSTR pszValue,
475         DWORD   dwType,
476         LPVOID  pvData,
477         DWORD   cbData,
478         DWORD   dwFlags)
479 {
480         HUSKEY myhuskey;
481         LONG   ret;
482         BOOL   ignoreHKCU;
483
484         if (!pvData) return ERROR_INVALID_FUNCTION;
485         TRACE("key '%s', value '%s', datalen %ld\n",
486               debugstr_w(pszSubKey), debugstr_w(pszValue), cbData);
487
488         ignoreHKCU = ((dwFlags == SHREGSET_HKLM) || (dwFlags == SHREGSET_FORCE_HKLM));
489
490         ret = SHRegOpenUSKeyW(pszSubKey, 0x1, 0, &myhuskey, ignoreHKCU);
491         if (ret == ERROR_SUCCESS) {
492           ret = SHRegWriteUSValueW(myhuskey, pszValue, dwType, pvData,
493                                    cbData, dwFlags);
494             SHRegCloseUSKey(myhuskey);
495         }
496         return ret;
497 }
498
499 /*************************************************************************
500  * SHRegGetBoolUSValueA   [SHLWAPI.@]
501  *
502  * Get a user-specific registry boolean value.
503  *
504  * RETURNS
505  *  Success: ERROR_SUCCESS
506  *  Failure: An error code from SHRegOpenUSKeyA() or SHRegQueryUSValueA().
507  *
508  * NOTES
509  *   This function opens pszSubKey, queries the value, and then closes the key.
510  *
511  *   Boolean values are one of the following:
512  *   True: YES,TRUE,non-zero
513  *   False: NO,FALSE,0
514  */
515 BOOL WINAPI SHRegGetBoolUSValueA(
516         LPCSTR pszSubKey, /* [I] Key name to open */
517         LPCSTR pszValue, /* [I] Value name to open */
518         BOOL fIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */
519         BOOL fDefault) /* [I] Default value to use if pszValue is not present */
520 {
521         LONG retvalue;
522         DWORD type, datalen, work;
523         BOOL ret = fDefault;
524         CHAR data[10];
525
526         TRACE("key '%s', value '%s', %s\n",
527               debugstr_a(pszSubKey), debugstr_a(pszValue),
528               (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
529
530         datalen = sizeof(data)-1;
531         if (!(retvalue = SHRegGetUSValueA( pszSubKey, pszValue, &type,
532                                            data, &datalen,
533                                            fIgnoreHKCU, 0, 0))) {
534             /* process returned data via type into bool */
535             switch (type) {
536             case REG_SZ:
537                 data[9] = '\0';     /* set end of string */
538                 if (lstrcmpiA(data, "YES") == 0) ret = TRUE;
539                 if (lstrcmpiA(data, "TRUE") == 0) ret = TRUE;
540                 if (lstrcmpiA(data, "NO") == 0) ret = FALSE;
541                 if (lstrcmpiA(data, "FALSE") == 0) ret = FALSE;
542                 break;
543             case REG_DWORD:
544                 work = *(LPDWORD)data;
545                 ret = (work != 0);
546                 break;
547             case REG_BINARY:
548                 if (datalen == 1) {
549                     ret = (data[0] != '\0');
550                     break;
551                 }
552             default:
553                 FIXME("Unsupported registry data type %ld\n", type);
554                 ret = FALSE;
555             }
556             TRACE("got value (type=%ld), returing <%s>\n", type,
557                   (ret) ? "TRUE" : "FALSE");
558         }
559         else {
560             ret = fDefault;
561             TRACE("returning default data <%s>\n",
562                   (ret) ? "TRUE" : "FALSE");
563         }
564         return ret;
565 }
566
567 /*************************************************************************
568  * SHRegGetBoolUSValueW   [SHLWAPI.@]
569  *
570  * See SHRegGetBoolUSValueA.
571  */
572 BOOL WINAPI SHRegGetBoolUSValueW(
573         LPCWSTR pszSubKey,
574         LPCWSTR pszValue,
575         BOOL fIgnoreHKCU,
576         BOOL fDefault)
577 {
578         static const WCHAR wYES[]=  {'Y','E','S','\0'};
579         static const WCHAR wTRUE[]= {'T','R','U','E','\0'};
580         static const WCHAR wNO[]=   {'N','O','\0'};
581         static const WCHAR wFALSE[]={'F','A','L','S','E','\0'};
582         LONG retvalue;
583         DWORD type, datalen, work;
584         BOOL ret = fDefault;
585         WCHAR data[10];
586
587         TRACE("key '%s', value '%s', %s\n",
588               debugstr_w(pszSubKey), debugstr_w(pszValue),
589               (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
590
591         datalen = (sizeof(data)-1) * sizeof(WCHAR);
592         if (!(retvalue = SHRegGetUSValueW( pszSubKey, pszValue, &type,
593                                            data, &datalen,
594                                            fIgnoreHKCU, 0, 0))) {
595             /* process returned data via type into bool */
596             switch (type) {
597             case REG_SZ:
598                 data[9] = L'\0';     /* set end of string */
599                 if (lstrcmpiW(data, wYES)==0 || lstrcmpiW(data, wTRUE)==0)
600                     ret = TRUE;
601                 else if (lstrcmpiW(data, wNO)==0 || lstrcmpiW(data, wFALSE)==0)
602                     ret = FALSE;
603                 break;
604             case REG_DWORD:
605                 work = *(LPDWORD)data;
606                 ret = (work != 0);
607                 break;
608             case REG_BINARY:
609                 if (datalen == 1) {
610                     ret = (data[0] != L'\0');
611                     break;
612                 }
613             default:
614                 FIXME("Unsupported registry data type %ld\n", type);
615                 ret = FALSE;
616             }
617             TRACE("got value (type=%ld), returing <%s>\n", type,
618                   (ret) ? "TRUE" : "FALSE");
619         }
620         else {
621             ret = fDefault;
622             TRACE("returning default data <%s>\n",
623                   (ret) ? "TRUE" : "FALSE");
624         }
625         return ret;
626 }
627
628 /*************************************************************************
629  *      SHRegQueryInfoUSKeyA    [SHLWAPI.@]
630  *
631  * Get information about a user-specific registry key.
632  *
633  * RETURNS
634  *  Success: ERROR_SUCCESS
635  *  Failure: An error code from RegQueryInfoKeyA().
636  */
637 LONG WINAPI SHRegQueryInfoUSKeyA(
638         HUSKEY hUSKey, /* [I] Key to query */
639         LPDWORD pcSubKeys, /* [O] Destination for number of sub keys */
640         LPDWORD pcchMaxSubKeyLen, /* [O] Destination for the length of the biggest sub key name */
641         LPDWORD pcValues, /* [O] Destination for number of values */
642         LPDWORD pcchMaxValueNameLen,/* [O] Destination for the length of the biggest value */
643         SHREGENUM_FLAGS enumRegFlags)  /* [in] SHREGENUM_ flags from "shlwapi.h" */
644 {
645         HKEY dokey;
646         LONG ret;
647
648         TRACE("(%p,%p,%p,%p,%p,%d)\n",
649               hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
650               pcchMaxValueNameLen,enumRegFlags);
651
652         /* if user wants HKCU, and it exists, then try it */
653         if (((enumRegFlags == SHREGENUM_HKCU) ||
654              (enumRegFlags == SHREGENUM_DEFAULT)) &&
655             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
656             ret = RegQueryInfoKeyA(dokey, 0, 0, 0,
657                                    pcSubKeys, pcchMaxSubKeyLen, 0,
658                                    pcValues, pcchMaxValueNameLen, 0, 0, 0);
659             if ((ret == ERROR_SUCCESS) ||
660                 (enumRegFlags == SHREGENUM_HKCU))
661                 return ret;
662         }
663         if (((enumRegFlags == SHREGENUM_HKLM) ||
664              (enumRegFlags == SHREGENUM_DEFAULT)) &&
665             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
666             return RegQueryInfoKeyA(dokey, 0, 0, 0,
667                                     pcSubKeys, pcchMaxSubKeyLen, 0,
668                                     pcValues, pcchMaxValueNameLen, 0, 0, 0);
669         }
670         return ERROR_INVALID_FUNCTION;
671 }
672
673 /*************************************************************************
674  *      SHRegQueryInfoUSKeyW    [SHLWAPI.@]
675  *
676  * See SHRegQueryInfoUSKeyA.
677  */
678 LONG WINAPI SHRegQueryInfoUSKeyW(
679         HUSKEY hUSKey,
680         LPDWORD pcSubKeys,
681         LPDWORD pcchMaxSubKeyLen,
682         LPDWORD pcValues,
683         LPDWORD pcchMaxValueNameLen,
684         SHREGENUM_FLAGS enumRegFlags)
685 {
686         HKEY dokey;
687         LONG ret;
688
689         TRACE("(%p,%p,%p,%p,%p,%d)\n",
690               hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
691               pcchMaxValueNameLen,enumRegFlags);
692
693         /* if user wants HKCU, and it exists, then try it */
694         if (((enumRegFlags == SHREGENUM_HKCU) ||
695              (enumRegFlags == SHREGENUM_DEFAULT)) &&
696             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
697             ret = RegQueryInfoKeyW(dokey, 0, 0, 0,
698                                    pcSubKeys, pcchMaxSubKeyLen, 0,
699                                    pcValues, pcchMaxValueNameLen, 0, 0, 0);
700             if ((ret == ERROR_SUCCESS) ||
701                 (enumRegFlags == SHREGENUM_HKCU))
702                 return ret;
703         }
704         if (((enumRegFlags == SHREGENUM_HKLM) ||
705              (enumRegFlags == SHREGENUM_DEFAULT)) &&
706             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
707             return RegQueryInfoKeyW(dokey, 0, 0, 0,
708                                     pcSubKeys, pcchMaxSubKeyLen, 0,
709                                     pcValues, pcchMaxValueNameLen, 0, 0, 0);
710         }
711         return ERROR_INVALID_FUNCTION;
712 }
713
714 /*************************************************************************
715  *      SHRegEnumUSKeyA         [SHLWAPI.@]
716  *
717  * Enumerate a user-specific registry key.
718  *
719  * RETURNS
720  *  Success: ERROR_SUCCESS
721  *  Failure: An error code from RegEnumKeyExA().
722  */
723 LONG WINAPI SHRegEnumUSKeyA(
724         HUSKEY hUSKey,                 /* [in] Key to enumerate */
725         DWORD dwIndex,                 /* [in] Index within hUSKey */
726         LPSTR pszName,                 /* [out] Name of the enumerated value */
727         LPDWORD pcchValueNameLen,      /* [in/out] Length of pszName */
728         SHREGENUM_FLAGS enumRegFlags)  /* [in] SHREGENUM_ flags from "shlwapi.h" */
729 {
730         HKEY dokey;
731
732         TRACE("(%p,%ld,%p,%p(%ld),%d)\n",
733               hUSKey, dwIndex, pszName, pcchValueNameLen,
734               *pcchValueNameLen, enumRegFlags);
735
736         if (((enumRegFlags == SHREGENUM_HKCU) ||
737              (enumRegFlags == SHREGENUM_DEFAULT)) &&
738             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
739             return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
740                                 0, 0, 0, 0);
741         }
742
743         if (((enumRegFlags == SHREGENUM_HKLM) ||
744              (enumRegFlags == SHREGENUM_DEFAULT)) &&
745             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
746             return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
747                                 0, 0, 0, 0);
748         }
749         FIXME("no support for SHREGENUM_BOTH\n");
750         return ERROR_INVALID_FUNCTION;
751 }
752
753 /*************************************************************************
754  *      SHRegEnumUSKeyW         [SHLWAPI.@]
755  *
756  * See SHRegEnumUSKeyA.
757  */
758 LONG WINAPI SHRegEnumUSKeyW(
759         HUSKEY hUSKey,
760         DWORD dwIndex,
761         LPWSTR pszName,
762         LPDWORD pcchValueNameLen,
763         SHREGENUM_FLAGS enumRegFlags)
764 {
765         HKEY dokey;
766
767         TRACE("(%p,%ld,%p,%p(%ld),%d)\n",
768               hUSKey, dwIndex, pszName, pcchValueNameLen,
769               *pcchValueNameLen, enumRegFlags);
770
771         if (((enumRegFlags == SHREGENUM_HKCU) ||
772              (enumRegFlags == SHREGENUM_DEFAULT)) &&
773             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
774             return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
775                                 0, 0, 0, 0);
776         }
777
778         if (((enumRegFlags == SHREGENUM_HKLM) ||
779              (enumRegFlags == SHREGENUM_DEFAULT)) &&
780             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
781             return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
782                                 0, 0, 0, 0);
783         }
784         FIXME("no support for SHREGENUM_BOTH\n");
785         return ERROR_INVALID_FUNCTION;
786 }
787
788
789 /*************************************************************************
790  *      SHRegWriteUSValueA      [SHLWAPI.@]
791  *
792  * Write a user-specific registry value.
793  *
794  * PARAMS
795  *  hUSKey   [I] Key to write the value to
796  *  pszValue [I] Name of value under hUSKey to write the value as
797  *  dwType   [I] Type of the value
798  *  pvData   [I] Data to set as the value
799  *  cbData   [I] length of pvData
800  *  dwFlags  [I] SHREGSET_ flags from "shlwapi.h"
801  *
802  * RETURNS
803  *  Success: ERROR_SUCCESS.
804  *  Failure: An error code from RegSetValueExA().
805  */
806 LONG  WINAPI SHRegWriteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, DWORD dwType,
807                                 LPVOID pvData, DWORD cbData, DWORD dwFlags)
808 {
809     HKEY dokey;
810
811     TRACE("(%p,%s,%ld,%p,%ld,%ld)\n",
812               hUSKey, debugstr_a(pszValue), dwType, pvData, cbData, dwFlags);
813
814     if ((dwFlags & SHREGSET_FORCE_HKCU) &&
815             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
816         RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
817     }
818
819     if ((dwFlags & SHREGSET_FORCE_HKLM) &&
820             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
821         RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
822     }
823
824     if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM))
825         return ERROR_SUCCESS;
826
827     FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
828     return ERROR_SUCCESS;
829 }
830
831 /*************************************************************************
832  *      SHRegWriteUSValueW      [SHLWAPI.@]
833  *
834  * See SHRegWriteUSValueA.
835  */
836 LONG  WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, DWORD dwType,
837                                 LPVOID pvData, DWORD cbData, DWORD dwFlags)
838 {
839     HKEY dokey;
840
841     TRACE("(%p,%s,%ld,%p,%ld,%ld)\n",
842               hUSKey, debugstr_w(pszValue), dwType, pvData, cbData, dwFlags);
843
844     if ((dwFlags & SHREGSET_FORCE_HKCU) &&
845             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
846         RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
847     }
848
849     if ((dwFlags & SHREGSET_FORCE_HKLM) &&
850             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
851         RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
852     }
853
854     if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM))
855         return ERROR_SUCCESS;
856
857     FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
858     return ERROR_SUCCESS;
859 }
860
861 /*************************************************************************
862  * SHRegGetPathA   [SHLWAPI.@]
863  *
864  * Get a path from the registry.
865  *
866  * PARAMS
867  *   hKey       [I] Handle to registry key
868  *   lpszSubKey [I] Name of sub key containing path to get
869  *   lpszValue  [I] Name of value containing path to get
870  *   lpszPath   [O] Buffer for returned path
871  *   dwFlags    [I] Reserved
872  *
873  * RETURNS
874  *   Success: ERROR_SUCCESS. lpszPath contains the path.
875  *   Failure: An error code from RegOpenKeyExA() or SHQueryValueExA().
876  */
877 DWORD WINAPI SHRegGetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
878                            LPSTR lpszPath, DWORD dwFlags)
879 {
880   DWORD dwSize = MAX_PATH;
881
882   TRACE("(hkey=%p,%s,%s,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
883         debugstr_a(lpszValue), lpszPath, dwFlags);
884
885   return SHGetValueA(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize);
886 }
887
888 /*************************************************************************
889  * SHRegGetPathW   [SHLWAPI.@]
890  *
891  * See SHRegGetPathA.
892  */
893 DWORD WINAPI SHRegGetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
894                            LPWSTR lpszPath, DWORD dwFlags)
895 {
896   DWORD dwSize = MAX_PATH;
897
898   TRACE("(hkey=%p,%s,%s,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
899         debugstr_w(lpszValue), lpszPath, dwFlags);
900
901   return SHGetValueW(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize);
902 }
903
904
905 /*************************************************************************
906  * SHRegSetPathA   [SHLWAPI.@]
907  *
908  * Write a path to the registry.
909  *
910  * PARAMS
911  *   hKey       [I] Handle to registry key
912  *   lpszSubKey [I] Name of sub key containing path to set
913  *   lpszValue  [I] Name of value containing path to set
914  *   lpszPath   [O] Path to write
915  *   dwFlags    [I] Reserved, must be 0.
916  *
917  * RETURNS
918  *   Success: ERROR_SUCCESS.
919  *   Failure: An error code from SHSetValueA().
920  */
921 DWORD WINAPI SHRegSetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
922                            LPCSTR lpszPath, DWORD dwFlags)
923 {
924   char szBuff[MAX_PATH];
925
926   FIXME("(hkey=%p,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_a(lpszSubKey),
927         debugstr_a(lpszValue), lpszPath, dwFlags);
928
929   lstrcpyA(szBuff, lpszPath);
930
931   /* FIXME: PathUnExpandEnvStringsA(szBuff); */
932
933   return SHSetValueA(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
934                      lstrlenA(szBuff));
935 }
936
937 /*************************************************************************
938  * SHRegSetPathW   [SHLWAPI.@]
939  *
940  * See SHRegSetPathA.
941  */
942 DWORD WINAPI SHRegSetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
943                            LPCWSTR lpszPath, DWORD dwFlags)
944 {
945   WCHAR szBuff[MAX_PATH];
946
947   FIXME("(hkey=%p,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_w(lpszSubKey),
948         debugstr_w(lpszValue), lpszPath, dwFlags);
949
950   lstrcpyW(szBuff, lpszPath);
951
952   /* FIXME: PathUnExpandEnvStringsW(szBuff); */
953
954   return SHSetValueW(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
955                      lstrlenW(szBuff));
956 }
957
958 /*************************************************************************
959  * SHGetValueA   [SHLWAPI.@]
960  *
961  * Get a value from the registry.
962  *
963  * PARAMS
964  *   hKey       [I] Handle to registry key
965  *   lpszSubKey [I] Name of sub key containing value to get
966  *   lpszValue  [I] Name of value to get
967  *   pwType     [O] Pointer to the values type
968  *   pvData     [O] Pointer to the values data
969  *   pcbData    [O] Pointer to the values size
970  *
971  * RETURNS
972  *   Success: ERROR_SUCCESS. Output parameters contain the details read.
973  *   Failure: An error code from RegOpenKeyExA() or SHQueryValueExA().
974  */
975 DWORD WINAPI SHGetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
976                          LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
977 {
978   DWORD dwRet = 0;
979   HKEY hSubKey = 0;
980
981   TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_a(lpszSubKey),
982         debugstr_a(lpszValue), pwType, pvData, pcbData);
983
984   /*   lpszSubKey can be 0. In this case the value is taken from the
985    *   current key.
986    */
987   if(lpszSubKey)
988     dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
989
990   if (! dwRet)
991   {
992     /* SHQueryValueEx expands Environment strings */
993     dwRet = SHQueryValueExA(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData);
994     if (hSubKey) RegCloseKey(hSubKey);
995   }
996   return dwRet;
997 }
998
999 /*************************************************************************
1000  * SHGetValueW   [SHLWAPI.@]
1001  *
1002  * See SHGetValueA.
1003  */
1004 DWORD WINAPI SHGetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
1005                          LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
1006 {
1007   DWORD dwRet = 0;
1008   HKEY hSubKey = 0;
1009
1010   TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_w(lpszSubKey),
1011         debugstr_w(lpszValue), pwType, pvData, pcbData);
1012
1013   if(lpszSubKey)
1014     dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
1015
1016   if (! dwRet)
1017   {
1018     dwRet = SHQueryValueExW(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData);
1019     if (hSubKey) RegCloseKey(hSubKey);
1020   }
1021   return dwRet;
1022 }
1023
1024 /*************************************************************************
1025  * SHSetValueA   [SHLWAPI.@]
1026  *
1027  * Set a value in the registry.
1028  *
1029  * PARAMS
1030  *   hKey       [I] Handle to registry key
1031  *   lpszSubKey [I] Name of sub key under hKey
1032  *   lpszValue  [I] Name of value to set
1033  *   dwType     [I] Type of the value
1034  *   pvData     [I] Data of the value
1035  *   cbData     [I] Size of the value
1036  *
1037  * RETURNS
1038  *   Success: ERROR_SUCCESS. The value is set with the data given.
1039  *   Failure: An error code from RegCreateKeyExA() or RegSetValueExA()
1040  *
1041  * NOTES
1042  *   If lpszSubKey does not exist, it is created before the value is set. If
1043  *   lpszSubKey is NULL or an empty string, then the value is added directly
1044  *   to hKey instead.
1045  */
1046 DWORD WINAPI SHSetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
1047                          DWORD dwType, LPCVOID pvData, DWORD cbData)
1048 {
1049   DWORD dwRet = ERROR_SUCCESS, dwDummy;
1050   HKEY  hSubKey;
1051   char  szEmpty[] = "";
1052
1053   TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
1054           debugstr_a(lpszValue), dwType, pvData, cbData);
1055
1056   if (lpszSubKey && *lpszSubKey)
1057     dwRet = RegCreateKeyExA(hKey, lpszSubKey, 0, szEmpty,
1058                             0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
1059   else
1060     hSubKey = hKey;
1061   if (!dwRet)
1062   {
1063     dwRet = RegSetValueExA(hSubKey, lpszValue, 0, dwType, pvData, cbData);
1064     if (hSubKey != hKey)
1065       RegCloseKey(hSubKey);
1066   }
1067   return dwRet;
1068 }
1069
1070 /*************************************************************************
1071  * SHSetValueW   [SHLWAPI.@]
1072  *
1073  * See SHSetValueA.
1074  */
1075 DWORD WINAPI SHSetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
1076                          DWORD dwType, LPCVOID pvData, DWORD cbData)
1077 {
1078   DWORD dwRet = ERROR_SUCCESS, dwDummy;
1079   HKEY  hSubKey;
1080   WCHAR szEmpty[] = { '\0' };
1081
1082   TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
1083         debugstr_w(lpszValue), dwType, pvData, cbData);
1084
1085   if (lpszSubKey && *lpszSubKey)
1086     dwRet = RegCreateKeyExW(hKey, lpszSubKey, 0, szEmpty,
1087                             0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
1088   else
1089     hSubKey = hKey;
1090   if (!dwRet)
1091   {
1092     dwRet = RegSetValueExW(hSubKey, lpszValue, 0, dwType, pvData, cbData);
1093     if (hSubKey != hKey)
1094       RegCloseKey(hSubKey);
1095   }
1096   return dwRet;
1097 }
1098
1099 /*************************************************************************
1100  * SHQueryInfoKeyA   [SHLWAPI.@]
1101  *
1102  * Get information about a registry key. See RegQueryInfoKeyA().
1103  *
1104  * RETURNS
1105  *  The result of calling RegQueryInfoKeyA().
1106  */
1107 LONG WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
1108                             LPDWORD pwValues, LPDWORD pwValueMax)
1109 {
1110   TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
1111         pwValues, pwValueMax);
1112   return RegQueryInfoKeyA(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
1113                           NULL, pwValues, pwValueMax, NULL, NULL, NULL);
1114 }
1115
1116 /*************************************************************************
1117  * SHQueryInfoKeyW   [SHLWAPI.@]
1118  *
1119  * See SHQueryInfoKeyA.
1120  */
1121 LONG WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
1122                             LPDWORD pwValues, LPDWORD pwValueMax)
1123 {
1124   TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
1125         pwValues, pwValueMax);
1126   return RegQueryInfoKeyW(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
1127                           NULL, pwValues, pwValueMax, NULL, NULL, NULL);
1128 }
1129
1130 /*************************************************************************
1131  * SHQueryValueExA   [SHLWAPI.@]
1132  *
1133  * Get a value from the registry, expanding environment variable strings.
1134  *
1135  * PARAMS
1136  *   hKey       [I] Handle to registry key
1137  *   lpszValue  [I] Name of value to query
1138  *   lpReserved [O] Reserved for future use; must be NULL
1139  *   pwType     [O] Optional pointer updated with the values type
1140  *   pvData     [O] Optional pointer updated with the values data
1141  *   pcbData    [O] Optional pointer updated with the values size
1142  *
1143  * RETURNS
1144  *   Success: ERROR_SUCCESS. Any non NULL output parameters are updated with
1145  *            information about the value.
1146  *   Failure: ERROR_OUTOFMEMORY if memory allocation fails, or the type of the
1147  *            data is REG_EXPAND_SZ and pcbData is NULL. Otherwise an error
1148  *            code from RegQueryValueExA() or ExpandEnvironmentStringsA().
1149  *
1150  * NOTES
1151  *   Either pwType, pvData or pcbData may be NULL if the caller doesn't want
1152  *   the type, data or size information for the value.
1153  *
1154  *   If the type of the data is REG_EXPAND_SZ, it is expanded to REG_SZ. The
1155  *   value returned will be truncated if it is of type REG_SZ and bigger than
1156  *   the buffer given to store it.
1157  *
1158  *   REG_EXPAND_SZ:
1159  *     case-1: the unexpanded string is smaller than the expanded one
1160  *       subcase-1: the buffer is to small to hold the unexpanded string:
1161  *          function fails and returns the size of the unexpanded string.
1162  *
1163  *       subcase-2: buffer is to small to hold the expanded string:
1164  *          the function return success (!!) and the result is truncated
1165  *          *** This is clearly a error in the native implementation. ***
1166  *
1167  *     case-2: the unexpanded string is bigger than the expanded one
1168  *       The buffer must have enough space to hold the unexpanded
1169  *       string even if the result is smaller.
1170  *
1171  */
1172 DWORD WINAPI SHQueryValueExA( HKEY hKey, LPCSTR lpszValue,
1173                               LPDWORD lpReserved, LPDWORD pwType,
1174                               LPVOID pvData, LPDWORD pcbData)
1175 {
1176   DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen;
1177
1178   TRACE("(hkey=%p,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_a(lpszValue),
1179         lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1180
1181   if (pcbData) dwUnExpDataLen = *pcbData;
1182
1183   dwRet = RegQueryValueExA(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen);
1184
1185   if (pcbData && (dwType == REG_EXPAND_SZ))
1186   {
1187     DWORD nBytesToAlloc;
1188
1189     /* Expand type REG_EXPAND_SZ into REG_SZ */
1190     LPSTR szData;
1191
1192     /* If the caller didn't supply a buffer or the buffer is to small we have
1193      * to allocate our own
1194      */
1195     if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
1196     {
1197       char cNull = '\0';
1198       nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData;
1199
1200       szData = (LPSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc);
1201       RegQueryValueExA (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
1202       dwExpDataLen = ExpandEnvironmentStringsA(szData, &cNull, 1);
1203       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1204       LocalFree((HLOCAL) szData);
1205     }
1206     else
1207     {
1208       nBytesToAlloc = lstrlenA(pvData) * sizeof (CHAR);
1209       szData = (LPSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc + 1);
1210       lstrcpyA(szData, pvData);
1211       dwExpDataLen = ExpandEnvironmentStringsA(szData, pvData, *pcbData / sizeof(CHAR));
1212       if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
1213       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1214       LocalFree((HLOCAL) szData);
1215     }
1216   }
1217
1218   /* Update the type and data size if the caller wanted them */
1219   if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ;
1220   if ( pwType ) *pwType = dwType;
1221   if ( pcbData ) *pcbData = dwUnExpDataLen;
1222   return dwRet;
1223 }
1224
1225
1226 /*************************************************************************
1227  * SHQueryValueExW   [SHLWAPI.@]
1228  *
1229  * See SHQueryValueExA.
1230  */
1231 DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue,
1232                              LPDWORD lpReserved, LPDWORD pwType,
1233                              LPVOID pvData, LPDWORD pcbData)
1234 {
1235   DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen;
1236
1237   TRACE("(hkey=%p,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_w(lpszValue),
1238         lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1239
1240   if (pcbData) dwUnExpDataLen = *pcbData;
1241
1242   dwRet = RegQueryValueExW(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen);
1243   if (dwRet!=ERROR_SUCCESS && dwRet!=ERROR_MORE_DATA)
1244       return dwRet;
1245
1246   if (pcbData && (dwType == REG_EXPAND_SZ))
1247   {
1248     DWORD nBytesToAlloc;
1249
1250     /* Expand type REG_EXPAND_SZ into REG_SZ */
1251     LPWSTR szData;
1252
1253     /* If the caller didn't supply a buffer or the buffer is too small we have
1254      * to allocate our own
1255      */
1256     if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
1257     {
1258       WCHAR cNull = '\0';
1259       nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData;
1260
1261       szData = (LPWSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc);
1262       RegQueryValueExW (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
1263       dwExpDataLen = ExpandEnvironmentStringsW(szData, &cNull, 1);
1264       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1265       LocalFree((HLOCAL) szData);
1266     }
1267     else
1268     {
1269       nBytesToAlloc = lstrlenW(pvData) * sizeof(WCHAR);
1270       szData = (LPWSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc + 1);
1271       lstrcpyW(szData, pvData);
1272       dwExpDataLen = ExpandEnvironmentStringsW(szData, pvData, *pcbData/sizeof(WCHAR) );
1273       if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
1274       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1275       LocalFree((HLOCAL) szData);
1276     }
1277   }
1278
1279   /* Update the type and data size if the caller wanted them */
1280   if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ;
1281   if ( pwType ) *pwType = dwType;
1282   if ( pcbData ) *pcbData = dwUnExpDataLen;
1283   return dwRet;
1284 }
1285
1286 /*************************************************************************
1287  * SHDeleteKeyA   [SHLWAPI.@]
1288  *
1289  * Delete a registry key and any sub keys/values present
1290  *
1291  * PARAMS
1292  *   hKey       [I] Handle to registry key
1293  *   lpszSubKey [I] Name of sub key to delete
1294  *
1295  * RETURNS
1296  *   Success: ERROR_SUCCESS. The key is deleted.
1297  *   Failure: An error code from RegOpenKeyExA(), RegQueryInfoKeyA(),
1298  *            RegEnumKeyExA() or RegDeleteKeyA().
1299  */
1300 DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey)
1301 {
1302   DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1303   CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1304   HKEY hSubKey = 0;
1305
1306   TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey));
1307
1308   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1309   if(!dwRet)
1310   {
1311     /* Find how many subkeys there are */
1312     dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1313                              &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1314     if(!dwRet)
1315     {
1316       dwMaxSubkeyLen++;
1317       if (dwMaxSubkeyLen > sizeof(szNameBuf))
1318         /* Name too big: alloc a buffer for it */
1319         lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(CHAR));
1320
1321       if(!lpszName)
1322         dwRet = ERROR_NOT_ENOUGH_MEMORY;
1323       else
1324       {
1325         /* Recursively delete all the subkeys */
1326         for(i = 0; i < dwKeyCount && !dwRet; i++)
1327         {
1328           dwSize = dwMaxSubkeyLen;
1329           dwRet = RegEnumKeyExA(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1330           if(!dwRet)
1331             dwRet = SHDeleteKeyA(hSubKey, lpszName);
1332         }
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.324]
1838  *
1839  * Set the file extension for a MIME content key.
1840  *
1841  * PARAMS
1842  *   lpszExt  [I] File extension to set
1843  *   lpszType [I] Content type to set the extension for
1844  *
1845  * RETURNS
1846  *   Success: TRUE. The file extension is set in the registry.
1847  *   Failure: FALSE.
1848  */
1849 BOOL WINAPI RegisterExtensionForMIMETypeA(LPCSTR lpszExt, LPCSTR lpszType)
1850 {
1851   DWORD dwLen;
1852   char szKey[MAX_PATH];
1853
1854   TRACE("(%s,%s)\n", debugstr_a(lpszExt), debugstr_a(lpszType));
1855
1856   if (!GetMIMETypeSubKeyA(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1857     return FALSE;
1858
1859   dwLen = strlen(lpszExt) + 1;
1860
1861   if (SHSetValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA, REG_SZ, lpszExt, dwLen))
1862     return FALSE;
1863   return TRUE;
1864 }
1865
1866 /*************************************************************************
1867  * @   [SHLWAPI.325]
1868  *
1869  * Unicode version of RegisterExtensionForMIMETypeA.
1870  */
1871 BOOL WINAPI RegisterExtensionForMIMETypeW(LPCWSTR lpszExt, LPCWSTR lpszType)
1872 {
1873   DWORD dwLen;
1874   WCHAR szKey[MAX_PATH];
1875
1876   TRACE("(%s,%s)\n", debugstr_w(lpszExt), debugstr_w(lpszType));
1877
1878   /* Get the full path to the key */
1879   if (!GetMIMETypeSubKeyW(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1880     return FALSE;
1881
1882   dwLen = (lstrlenW(lpszExt) + 1) * sizeof(WCHAR);
1883
1884   if (SHSetValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW, REG_SZ, lpszExt, dwLen))
1885     return FALSE;
1886   return TRUE;
1887 }
1888
1889 /*************************************************************************
1890  * @   [SHLWAPI.326]
1891  *
1892  * Delete a file extension from a MIME content type.
1893  *
1894  * PARAMS
1895  *   lpszType [I] Content type to delete the extension for
1896  *
1897  * RETURNS
1898  *   Success: TRUE. The file extension is deleted from the registry.
1899  *   Failure: FALSE. The extension may have been removed but the key remains.
1900  *
1901  * NOTES
1902  *   If deleting the extension leaves an orphan key, the key is removed also.
1903  */
1904 BOOL WINAPI UnregisterExtensionForMIMETypeA(LPCSTR lpszType)
1905 {
1906   char szKey[MAX_PATH];
1907
1908   TRACE("(%s)\n", debugstr_a(lpszType));
1909
1910   if (!GetMIMETypeSubKeyA(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1911     return FALSE;
1912
1913   if (!SHDeleteValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA))
1914     return FALSE;
1915
1916   if (!SHDeleteOrphanKeyA(HKEY_CLASSES_ROOT, szKey))
1917     return FALSE;
1918   return TRUE;
1919 }
1920
1921 /*************************************************************************
1922  * @   [SHLWAPI.327]
1923  *
1924  * Unicode version of UnregisterExtensionForMIMETypeA.
1925  */
1926 BOOL WINAPI UnregisterExtensionForMIMETypeW(LPCWSTR lpszType)
1927 {
1928   WCHAR szKey[MAX_PATH];
1929
1930   TRACE("(%s)\n", debugstr_w(lpszType));
1931
1932   if (!GetMIMETypeSubKeyW(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1933     return FALSE;
1934
1935   if (!SHDeleteValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW))
1936     return FALSE;
1937
1938   if (!SHDeleteOrphanKeyW(HKEY_CLASSES_ROOT, szKey))
1939     return FALSE;
1940   return TRUE;
1941 }
1942
1943 /*************************************************************************
1944  * SHRegDuplicateHKey   [SHLWAPI.@]
1945  *
1946  * Create a duplicate of a registry handle.
1947  *
1948  * PARAMS
1949  *  hKey [I] key to duplicate.
1950  *
1951  * RETURNS
1952  *  A new handle pointing to the same key as hKey.
1953  */
1954 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1955 {
1956     HKEY newKey = 0;
1957
1958     RegOpenKeyExA(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1959     TRACE("new key is %p\n", newKey);
1960     return newKey;
1961 }
1962
1963
1964 /*************************************************************************
1965  * SHCopyKeyA   [SHLWAPI.@]
1966  *
1967  * Copy a key and its values/sub keys to another location.
1968  *
1969  * PARAMS
1970  *  hKeyDst    [I] Destination key
1971  *  lpszSubKey [I] Sub key under hKeyDst, or NULL to use hKeyDst directly
1972  *  hKeySrc    [I] Source key to copy from
1973  *  dwReserved [I] Reserved, must be 0
1974  *
1975  * RETURNS
1976  *  Success: ERROR_SUCCESS. The key is copied to the destination key.
1977  *  Failure: A standard windows error code.
1978  *
1979  * NOTES
1980  *  If hKeyDst is a key under hKeySrc, this function will misbehave
1981  *  (It will loop until out of stack, or the registry is full). This
1982  *  bug is present in Win32 also.
1983  */
1984 DWORD WINAPI SHCopyKeyA(HKEY hKeyDst, LPCSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved)
1985 {
1986   WCHAR szSubKeyW[MAX_PATH];
1987
1988   TRACE("(hkey=%p,%s,%p08x,%ld)\n", hKeyDst, debugstr_a(lpszSubKey), hKeySrc, dwReserved);
1989
1990   if (lpszSubKey)
1991     MultiByteToWideChar(0, 0, lpszSubKey, -1, szSubKeyW, MAX_PATH);
1992
1993   return SHCopyKeyW(hKeyDst, lpszSubKey ? szSubKeyW : NULL, hKeySrc, dwReserved);
1994 }
1995
1996 /*************************************************************************
1997  * SHCopyKeyW   [SHLWAPI.@]
1998  *
1999  * See SHCopyKeyA.
2000  */
2001 DWORD WINAPI SHCopyKeyW(HKEY hKeyDst, LPCWSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved)
2002 {
2003   DWORD dwKeyCount = 0, dwValueCount = 0, dwMaxKeyLen = 0;
2004   DWORD  dwMaxValueLen = 0, dwMaxDataLen = 0, i;
2005   BYTE buff[1024];
2006   LPVOID lpBuff = (LPVOID)buff;
2007   WCHAR szName[MAX_PATH], *lpszName = szName;
2008   DWORD dwRet = S_OK;
2009
2010   TRACE("hkey=%p,%s,%p08x,%ld)\n", hKeyDst, debugstr_w(lpszSubKey), hKeySrc, dwReserved);
2011
2012   if(!hKeyDst || !hKeySrc)
2013     dwRet = ERROR_INVALID_PARAMETER;
2014   else
2015   {
2016     /* Open destination key */
2017     if(lpszSubKey)
2018       dwRet = RegOpenKeyExW(hKeyDst, lpszSubKey, 0, KEY_ALL_ACCESS, &hKeyDst);
2019
2020     if(dwRet)
2021       hKeyDst = 0; /* Don't close this key since we didn't open it */
2022     else
2023     {
2024       /* Get details about sub keys and values */
2025       dwRet = RegQueryInfoKeyW(hKeySrc, NULL, NULL, NULL, &dwKeyCount, &dwMaxKeyLen,
2026                                NULL, &dwValueCount, &dwMaxValueLen, &dwMaxDataLen,
2027                                NULL, NULL);
2028       if(!dwRet)
2029       {
2030         if (dwMaxValueLen > dwMaxKeyLen)
2031           dwMaxKeyLen = dwMaxValueLen; /* Get max size for key/value names */
2032
2033         if (dwMaxKeyLen++ > MAX_PATH - 1)
2034           lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxKeyLen * sizeof(WCHAR));
2035
2036         if (dwMaxDataLen > sizeof(buff))
2037           lpBuff = HeapAlloc(GetProcessHeap(), 0, dwMaxDataLen);
2038
2039         if (!lpszName || !lpBuff)
2040           dwRet = ERROR_NOT_ENOUGH_MEMORY;
2041       }
2042     }
2043   }
2044
2045   /* Copy all the sub keys */
2046   for(i = 0; i < dwKeyCount && !dwRet; i++)
2047   {
2048     HKEY hSubKeySrc, hSubKeyDst;
2049     DWORD dwSize = dwMaxKeyLen;
2050
2051     dwRet = RegEnumKeyExW(hKeySrc, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2052
2053     if(!dwRet)
2054     {
2055       /* Open source sub key */
2056       dwRet = RegOpenKeyExW(hKeySrc, lpszName, 0, KEY_READ, &hSubKeySrc);
2057
2058       if(!dwRet)
2059       {
2060         /* Create destination sub key */
2061         dwRet = RegCreateKeyW(hKeyDst, lpszName, &hSubKeyDst);
2062
2063         if(!dwRet)
2064         {
2065           /* Recursively copy keys and values from the sub key */
2066           dwRet = SHCopyKeyW(hSubKeyDst, NULL, hSubKeySrc, 0);
2067           RegCloseKey(hSubKeyDst);
2068         }
2069       }
2070       RegCloseKey(hSubKeySrc);
2071     }
2072   }
2073
2074   /* Copy all the values in this key */
2075   for (i = 0; i < dwValueCount && !dwRet; i++)
2076   {
2077     DWORD dwNameSize = dwMaxKeyLen, dwType, dwLen = dwMaxDataLen;
2078
2079     dwRet = RegEnumValueW(hKeySrc, i, lpszName, &dwNameSize, NULL, &dwType, buff, &dwLen);
2080
2081     if (!dwRet)
2082       dwRet = SHSetValueW(hKeyDst, NULL, lpszName, dwType, lpBuff, dwLen);
2083   }
2084
2085   /* Free buffers if allocated */
2086   if (lpszName != szName)
2087     HeapFree(GetProcessHeap(), 0, lpszName);
2088   if (lpBuff != buff)
2089     HeapFree(GetProcessHeap(), 0, lpBuff);
2090
2091   if (lpszSubKey && hKeyDst)
2092     RegCloseKey(hKeyDst);
2093   return dwRet;
2094 }
2095
2096 /*
2097  * The following functions are ORDINAL ONLY:
2098  */
2099
2100 /*************************************************************************
2101  *      @     [SHLWAPI.280]
2102  *
2103  * Read an integer value from the registry, falling back to a default.
2104  *
2105  * PARAMS
2106  *  hKey      [I] Registry key to read from
2107  *  lpszValue [I] Value name to read
2108  *  iDefault  [I] Default value to return
2109  *
2110  * RETURNS
2111  *  The value contained in the given registry value if present, otherwise
2112  *  iDefault.
2113  */
2114 int WINAPI SHRegGetIntW(HKEY hKey, LPCWSTR lpszValue, int iDefault)
2115 {
2116   TRACE("(%p,%s,%d)\n", hKey, debugstr_w(lpszValue), iDefault);
2117
2118   if (hKey)
2119   {
2120     WCHAR szBuff[32];
2121     DWORD dwSize = sizeof(szBuff);
2122     szBuff[0] = '\0';
2123     SHQueryValueExW(hKey, lpszValue, 0, 0, szBuff, &dwSize);
2124
2125     if(*szBuff >= '0' && *szBuff <= '9')
2126       return StrToIntW(szBuff);
2127   }
2128   return iDefault;
2129 }
2130
2131 /*************************************************************************
2132  *      @       [SHLWAPI.343]
2133  *
2134  * Create or open an explorer ClassId Key.
2135  *
2136  * PARAMS
2137  *  guid      [I] Explorer ClassId key to open
2138  *  lpszValue [I] Value name under the ClassId Key
2139  *  bUseHKCU  [I] TRUE=Use HKEY_CURRENT_USER, FALSE=Use HKEY_CLASSES_ROOT
2140  *  bCreate   [I] TRUE=Create the key if it doesn't exist, FALSE=Don't
2141  *  phKey     [O] Destination for the resulting key handle
2142  *
2143  * RETURNS
2144  *  Success: S_OK. phKey contains the resulting registry handle.
2145  *  Failure: An HRESULT error code indicating the problem.
2146  */
2147 HRESULT WINAPI SHRegGetCLSIDKeyA(REFGUID guid, LPCSTR lpszValue, BOOL bUseHKCU, BOOL bCreate, PHKEY phKey)
2148 {
2149   WCHAR szValue[MAX_PATH];
2150
2151   if (lpszValue)
2152     MultiByteToWideChar(CP_ACP, 0, lpszValue, -1, szValue, sizeof(szValue)/sizeof(WCHAR));
2153
2154   return SHRegGetCLSIDKeyW(guid, lpszValue ? szValue : NULL, bUseHKCU, bCreate, phKey);
2155 }
2156
2157 /*************************************************************************
2158  *      @       [SHLWAPI.344]
2159  *
2160  * Unicode version of SHRegGetCLSIDKeyA.
2161  */
2162 HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID guid, LPCWSTR lpszValue, BOOL bUseHKCU,
2163                            BOOL bCreate, PHKEY phKey)
2164 {
2165   static const WCHAR szClassIdKey[] = { 'S','o','f','t','w','a','r','e','\\',
2166     'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2167     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2168     'E','x','p','l','o','r','e','r','\\','C','L','S','I','D','\\' };
2169 #define szClassIdKeyLen (sizeof(szClassIdKey)/sizeof(WCHAR))
2170   WCHAR szKey[MAX_PATH];
2171   DWORD dwRet;
2172   HKEY hkey;
2173
2174   /* Create the key string */
2175   memcpy(szKey, szClassIdKey, sizeof(szClassIdKey));
2176   SHStringFromGUIDW(guid, szKey + szClassIdKeyLen, 39); /* Append guid */
2177
2178   if(lpszValue)
2179   {
2180     szKey[szClassIdKeyLen + 39] = '\\';
2181     strcpyW(szKey + szClassIdKeyLen + 40, lpszValue); /* Append value name */
2182   }
2183
2184   hkey = bUseHKCU ? HKEY_CURRENT_USER : HKEY_CLASSES_ROOT;
2185
2186   if(bCreate)
2187     dwRet = RegCreateKeyW(hkey, szKey, phKey);
2188   else
2189     dwRet = RegOpenKeyExW(hkey, szKey, 0, KEY_READ, phKey);
2190
2191   return dwRet ? HRESULT_FROM_WIN32(dwRet) : S_OK;
2192 }
2193
2194 /*************************************************************************
2195  * SHRegisterValidateTemplate   [SHLWAPI.@]
2196  *
2197  * observed from the ie 5.5 installer:
2198  *  - allocates a buffer with the size of the given file
2199  *  - read the file content into the buffer
2200  *  - creates the key szTemplateKey
2201  *  - sets "205523652929647911071668590831910975402"=dword:00002e37 at
2202  *    the key
2203  *
2204  * PARAMS
2205  *  filename [I] An existing file its content is read into an allocated
2206  *               buffer
2207  *  unknown  [I]
2208  *
2209  * RETURNS
2210  *  Success: ERROR_SUCCESS.
2211  */
2212 HRESULT WINAPI SHRegisterValidateTemplate(LPCWSTR filename, BOOL unknown)
2213 {
2214 /* static const WCHAR szTemplateKey[] = { 'S','o','f','t','w','a','r','e','\\',
2215  *  'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2216  *  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2217  *  'E','x','p','l','o','r','e','r','\\',
2218  *  'T','e','m','p','l','a','t','e','R','e','g','i','s','t','r','y',0 };
2219  */
2220   FIXME("stub: %s, %08x\n", debugstr_w(filename), unknown);
2221
2222   return S_OK;
2223 }