Keep track of per-column information inside the listview.
[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 <string.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winerror.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "wine/debug.h"
31 #define NO_SHLWAPI_STREAM
32 #include "shlwapi.h"
33 #include "wine/unicode.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(shell);
36
37 /* Key/Value names for MIME content types */
38 static const char *lpszContentTypeA = "Content Type";
39 static const WCHAR lpszContentTypeW[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
40
41 static const char *szMimeDbContentA = "MIME\\Database\\Content Type\\";
42 static const WCHAR szMimeDbContentW[] = { 'M', 'I', 'M','E','\\',
43   'D','a','t','a','b','a','s','e','\\','C','o','n','t','e','n','t',
44   ' ','T','y','p','e','\\', '0' };
45 static const DWORD dwLenMimeDbContent = 27; /* strlen of szMimeDbContentA/W */
46
47 static const char *szExtensionA = "Extension";
48 static const WCHAR szExtensionW[] = { 'E', 'x', 't','e','n','s','i','o','n','\0' };
49
50 /* internal structure of what the HUSKEY points to */
51 typedef struct {
52     HKEY     HKCUkey;                  /* HKEY of opened HKCU key      */
53     HKEY     HKLMkey;                  /* HKEY of opened HKLM key      */
54     HKEY     start;                    /* HKEY of where to start       */
55     WCHAR    key_string[MAX_PATH];     /* additional path from 'start' */
56 } Internal_HUSKEY, *LPInternal_HUSKEY;
57
58
59 #define REG_HKCU  TRUE
60 #define REG_HKLM  FALSE
61 /*************************************************************************
62  * REG_GetHKEYFromHUSKEY
63  *
64  * Function:  Return the proper registry key from the HUSKEY structure
65  *            also allow special predefined values.
66  */
67 HKEY REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which)
68 {
69         HKEY test = (HKEY) hUSKey;
70         LPInternal_HUSKEY mihk = (LPInternal_HUSKEY) hUSKey;
71
72         if ((test == HKEY_CLASSES_ROOT)        ||
73             (test == HKEY_CURRENT_CONFIG)      ||
74             (test == HKEY_CURRENT_USER)        ||
75             (test == HKEY_DYN_DATA)            ||
76             (test == HKEY_LOCAL_MACHINE)       ||
77             (test == HKEY_PERFORMANCE_DATA)    ||
78 /* FIXME:  need to define for Win2k, ME, XP
79  *          (test == HKEY_PERFORMANCE_TEXT)    ||
80  *          (test == HKEY_PERFORMANCE_NLSTEXT) ||
81  */
82             (test == HKEY_USERS)) return test;
83         if (which == REG_HKCU) return mihk->HKCUkey;
84         return mihk->HKLMkey;
85 }
86
87
88 /*************************************************************************
89  * SHRegOpenUSKeyA      [SHLWAPI.@]
90  *
91  * Opens a user-specific registry key
92  */
93 LONG WINAPI SHRegOpenUSKeyA(
94         LPCSTR Path,
95         REGSAM AccessType,
96         HUSKEY hRelativeUSKey,
97         PHUSKEY phNewUSKey,
98         BOOL fIgnoreHKCU)
99 {
100     HKEY openHKCUkey=0;
101     HKEY openHKLMkey=0;
102     LONG ret2, ret1 = ~ERROR_SUCCESS;
103     LPInternal_HUSKEY ihky;
104
105     TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_a(Path),
106           (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey,
107           (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
108
109     /* now create the internal version of HUSKEY */
110     ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 ,
111                                         sizeof(Internal_HUSKEY));
112     MultiByteToWideChar(0, 0, Path, -1, ihky->key_string,
113                         sizeof(ihky->key_string)-1);
114
115     if (hRelativeUSKey) {
116         openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
117         openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
118     }
119     else {
120         openHKCUkey = HKEY_CURRENT_USER;
121         openHKLMkey = HKEY_LOCAL_MACHINE;
122     }
123
124     ihky->HKCUkey = 0;
125     ihky->HKLMkey = 0;
126     if (!fIgnoreHKCU) {
127         ret1 = RegOpenKeyExA(openHKCUkey, Path,
128                              0, AccessType, &ihky->HKCUkey);
129         /* if successful, then save real starting point */
130         if (ret1 != ERROR_SUCCESS)
131             ihky->HKCUkey = 0;
132     }
133     ret2 = RegOpenKeyExA(openHKLMkey, Path,
134                          0, AccessType, &ihky->HKLMkey);
135     if (ret2 != ERROR_SUCCESS)
136         ihky->HKLMkey = 0;
137
138     if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
139         TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
140
141     /* if all attempts have failed then bail */
142     if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
143         HeapFree(GetProcessHeap(), 0, ihky);
144         if (phNewUSKey)
145             *phNewUSKey = (HUSKEY)0;
146         return ret2;
147     }
148
149     TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
150     if (phNewUSKey)
151         *phNewUSKey = (HUSKEY)ihky;
152     return ERROR_SUCCESS;
153 }
154
155 /*************************************************************************
156  * SHRegOpenUSKeyW      [SHLWAPI.@]
157  *
158  * Opens a user-specific registry key
159  */
160 LONG WINAPI SHRegOpenUSKeyW(
161         LPCWSTR Path,
162         REGSAM AccessType,
163         HUSKEY hRelativeUSKey,
164         PHUSKEY phNewUSKey,
165         BOOL fIgnoreHKCU)
166 {
167     HKEY openHKCUkey=0;
168     HKEY openHKLMkey=0;
169     LONG ret2, ret1 = ~ERROR_SUCCESS;
170     LPInternal_HUSKEY ihky;
171
172     TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_w(Path),
173           (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey,
174           (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
175
176     /* now create the internal version of HUSKEY */
177     ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 ,
178                                         sizeof(Internal_HUSKEY));
179     lstrcpynW(ihky->key_string, Path, sizeof(ihky->key_string));
180
181     if (hRelativeUSKey) {
182         openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
183         openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
184     }
185     else {
186         openHKCUkey = HKEY_CURRENT_USER;
187         openHKLMkey = HKEY_LOCAL_MACHINE;
188     }
189
190     ihky->HKCUkey = 0;
191     ihky->HKLMkey = 0;
192     if (!fIgnoreHKCU) {
193         ret1 = RegOpenKeyExW(openHKCUkey, Path,
194                             0, AccessType, &ihky->HKCUkey);
195         /* if successful, then save real starting point */
196         if (ret1 != ERROR_SUCCESS)
197             ihky->HKCUkey = 0;
198     }
199     ret2 = RegOpenKeyExW(openHKLMkey, Path,
200                         0, AccessType, &ihky->HKLMkey);
201     if (ret2 != ERROR_SUCCESS)
202         ihky->HKLMkey = 0;
203
204     if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
205         TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
206
207     /* if all attempts have failed then bail */
208     if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
209         HeapFree(GetProcessHeap(), 0, ihky);
210         if (phNewUSKey)
211             *phNewUSKey = (HUSKEY)0;
212         return ret2;
213     }
214
215     TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
216     if (phNewUSKey)
217         *phNewUSKey = (HUSKEY)ihky;
218     return ERROR_SUCCESS;
219 }
220
221 /*************************************************************************
222  * SHRegCloseUSKey      [SHLWAPI.@]
223  *
224  * Closes a user-specific registry key
225  */
226 LONG WINAPI SHRegCloseUSKey(
227         HUSKEY hUSKey)
228 {
229     LPInternal_HUSKEY mihk = (LPInternal_HUSKEY)hUSKey;
230     LONG ret = ERROR_SUCCESS;
231
232     if (mihk->HKCUkey)
233         ret = RegCloseKey(mihk->HKCUkey);
234     if (mihk->HKLMkey)
235         ret = RegCloseKey(mihk->HKLMkey);
236     HeapFree(GetProcessHeap(), 0, mihk);
237     return ret;
238 }
239
240 /*************************************************************************
241  *      SHRegQueryUSValueA      [SHLWAPI.@]
242  */
243 LONG WINAPI SHRegQueryUSValueA(
244         HUSKEY hUSKey,             /* [in]  */
245         LPCSTR pszValue,
246         LPDWORD pdwType,
247         LPVOID pvData,
248         LPDWORD pcbData,
249         BOOL fIgnoreHKCU,
250         LPVOID pvDefaultData,
251         DWORD dwDefaultDataSize)
252 {
253         LONG ret = ~ERROR_SUCCESS;
254         LONG i, maxmove;
255         HKEY dokey;
256         CHAR *src, *dst;
257
258         /* if user wants HKCU, and it exists, then try it */
259         if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
260             ret = RegQueryValueExA(dokey,
261                                    pszValue, 0, pdwType, pvData, pcbData);
262             TRACE("HKCU RegQueryValue returned %08lx\n", ret);
263         }
264
265         /* if HKCU did not work and HKLM exists, then try it */
266         if ((ret != ERROR_SUCCESS) &&
267             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
268             ret = RegQueryValueExA(dokey,
269                                    pszValue, 0, pdwType, pvData, pcbData);
270             TRACE("HKLM RegQueryValue returned %08lx\n", ret);
271         }
272
273         /* if neither worked, and default data exists, then use it */
274         if (ret != ERROR_SUCCESS) {
275             if (pvDefaultData && (dwDefaultDataSize != 0)) {
276                 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
277                 src = (CHAR*)pvDefaultData;
278                 dst = (CHAR*)pvData;
279                 for(i=0; i<maxmove; i++) *dst++ = *src++;
280                 *pcbData = maxmove;
281                 TRACE("setting default data\n");
282                 ret = ERROR_SUCCESS;
283             }
284         }
285         return ret;
286 }
287
288
289 /*************************************************************************
290  *      SHRegQueryUSValueW      [SHLWAPI.@]
291  */
292 LONG WINAPI SHRegQueryUSValueW(
293         HUSKEY hUSKey,             /* [in]  */
294         LPCWSTR pszValue,
295         LPDWORD pdwType,
296         LPVOID pvData,
297         LPDWORD pcbData,
298         BOOL fIgnoreHKCU,
299         LPVOID pvDefaultData,
300         DWORD dwDefaultDataSize)
301 {
302         LONG ret = ~ERROR_SUCCESS;
303         LONG i, maxmove;
304         HKEY dokey;
305         CHAR *src, *dst;
306
307         /* if user wants HKCU, and it exists, then try it */
308         if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
309             ret = RegQueryValueExW(dokey,
310                                    pszValue, 0, pdwType, pvData, pcbData);
311             TRACE("HKCU RegQueryValue returned %08lx\n", ret);
312         }
313
314         /* if HKCU did not work and HKLM exists, then try it */
315         if ((ret != ERROR_SUCCESS) &&
316             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
317             ret = RegQueryValueExW(dokey,
318                                    pszValue, 0, pdwType, pvData, pcbData);
319             TRACE("HKLM RegQueryValue returned %08lx\n", ret);
320         }
321
322         /* if neither worked, and default data exists, then use it */
323         if (ret != ERROR_SUCCESS) {
324             if (pvDefaultData && (dwDefaultDataSize != 0)) {
325                 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
326                 src = (CHAR*)pvDefaultData;
327                 dst = (CHAR*)pvData;
328                 for(i=0; i<maxmove; i++) *dst++ = *src++;
329                 *pcbData = maxmove;
330                 TRACE("setting default data\n");
331                 ret = ERROR_SUCCESS;
332             }
333         }
334         return ret;
335 }
336
337 /*************************************************************************
338  * SHRegGetUSValueA     [SHLWAPI.@]
339  *
340  * Gets a user-specific registry value
341  *   Will open the key, query the value, and close the key
342  */
343 LONG WINAPI SHRegGetUSValueA(
344         LPCSTR   pSubKey,
345         LPCSTR   pValue,
346         LPDWORD  pwType,
347         LPVOID   pvData,
348         LPDWORD  pcbData,
349         BOOL     flagIgnoreHKCU,
350         LPVOID   pDefaultData,
351         DWORD    wDefaultDataSize)
352 {
353         HUSKEY myhuskey;
354         LONG ret;
355
356         if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
357         TRACE("key '%s', value '%s', datalen %ld,  %s\n",
358               debugstr_a(pSubKey), debugstr_a(pValue), *pcbData,
359               (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
360
361         ret = SHRegOpenUSKeyA(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
362         if (ret == ERROR_SUCCESS) {
363             ret = SHRegQueryUSValueA(myhuskey, pValue, pwType, pvData,
364                                      pcbData, flagIgnoreHKCU, pDefaultData,
365                                      wDefaultDataSize);
366             SHRegCloseUSKey(myhuskey);
367         }
368         return ret;
369 }
370
371 /*************************************************************************
372  * SHRegGetUSValueW     [SHLWAPI.@]
373  *
374  * Gets a user-specific registry value
375  *   Will open the key, query the value, and close the key
376  */
377 LONG WINAPI SHRegGetUSValueW(
378         LPCWSTR  pSubKey,
379         LPCWSTR  pValue,
380         LPDWORD  pwType,
381         LPVOID   pvData,
382         LPDWORD  pcbData,
383         BOOL     flagIgnoreHKCU,
384         LPVOID   pDefaultData,
385         DWORD    wDefaultDataSize)
386 {
387         HUSKEY myhuskey;
388         LONG ret;
389
390         if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
391         TRACE("key '%s', value '%s', datalen %ld,  %s\n",
392               debugstr_w(pSubKey), debugstr_w(pValue), *pcbData,
393               (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
394
395         ret = SHRegOpenUSKeyW(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
396         if (ret == ERROR_SUCCESS) {
397             ret = SHRegQueryUSValueW(myhuskey, pValue, pwType, pvData,
398                                      pcbData, flagIgnoreHKCU, pDefaultData,
399                                      wDefaultDataSize);
400             SHRegCloseUSKey(myhuskey);
401         }
402         return ret;
403 }
404
405 /*************************************************************************
406  * SHRegGetBoolUSValueA   [SHLWAPI.@]
407  */
408 BOOL WINAPI SHRegGetBoolUSValueA(
409         LPCSTR pszSubKey,
410         LPCSTR pszValue,
411         BOOL fIgnoreHKCU,
412         BOOL fDefault)
413 {
414         LONG retvalue;
415         DWORD type, datalen, work;
416         BOOL ret = fDefault;
417         CHAR data[10];
418
419         TRACE("key '%s', value '%s', %s\n",
420               debugstr_a(pszSubKey), debugstr_a(pszValue),
421               (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
422
423         datalen = sizeof(data)-1;
424         if (!(retvalue = SHRegGetUSValueA( pszSubKey, pszValue, &type,
425                                            data, &datalen,
426                                            fIgnoreHKCU, 0, 0))) {
427             /* process returned data via type into bool */
428             switch (type) {
429             case REG_SZ:
430                 data[9] = '\0';     /* set end of string */
431                 if (lstrcmpiA(data, "YES") == 0) ret = TRUE;
432                 if (lstrcmpiA(data, "TRUE") == 0) ret = TRUE;
433                 if (lstrcmpiA(data, "NO") == 0) ret = FALSE;
434                 if (lstrcmpiA(data, "FALSE") == 0) ret = FALSE;
435                 break;
436             case REG_DWORD:
437                 work = *(LPDWORD)data;
438                 ret = (work != 0);
439                 break;
440             case REG_BINARY:
441                 if (datalen == 1) {
442                     ret = (data[0] != '\0');
443                     break;
444                 }
445             default:
446                 FIXME("Unsupported registry data type %ld\n", type);
447                 ret = FALSE;
448             }
449             TRACE("got value (type=%ld), returing <%s>\n", type,
450                   (ret) ? "TRUE" : "FALSE");
451         }
452         else {
453             ret = fDefault;
454             TRACE("returning default data <%s>\n",
455                   (ret) ? "TRUE" : "FALSE");
456         }
457         return ret;
458 }
459
460 /*************************************************************************
461  * SHRegGetBoolUSValueW   [SHLWAPI.@]
462  */
463 BOOL WINAPI SHRegGetBoolUSValueW(
464         LPCWSTR pszSubKey,
465         LPCWSTR pszValue,
466         BOOL fIgnoreHKCU,
467         BOOL fDefault)
468 {
469         static const WCHAR wYES[]=  {'Y','E','S','\0'};
470         static const WCHAR wTRUE[]= {'T','R','U','E','\0'};
471         static const WCHAR wNO[]=   {'N','O','\0'};
472         static const WCHAR wFALSE[]={'F','A','L','S','E','\0'};
473         LONG retvalue;
474         DWORD type, datalen, work;
475         BOOL ret = fDefault;
476         WCHAR data[10];
477
478         TRACE("key '%s', value '%s', %s\n",
479               debugstr_w(pszSubKey), debugstr_w(pszValue),
480               (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
481
482         datalen = (sizeof(data)-1) * sizeof(WCHAR);
483         if (!(retvalue = SHRegGetUSValueW( pszSubKey, pszValue, &type,
484                                            data, &datalen,
485                                            fIgnoreHKCU, 0, 0))) {
486             /* process returned data via type into bool */
487             switch (type) {
488             case REG_SZ:
489                 data[9] = L'\0';     /* set end of string */
490                 if (lstrcmpiW(data, wYES)==0 || lstrcmpiW(data, wTRUE)==0)
491                     ret = TRUE;
492                 else if (lstrcmpiW(data, wNO)==0 || lstrcmpiW(data, wFALSE)==0)
493                     ret = FALSE;
494                 break;
495             case REG_DWORD:
496                 work = *(LPDWORD)data;
497                 ret = (work != 0);
498                 break;
499             case REG_BINARY:
500                 if (datalen == 1) {
501                     ret = (data[0] != L'\0');
502                     break;
503                 }
504             default:
505                 FIXME("Unsupported registry data type %ld\n", type);
506                 ret = FALSE;
507             }
508             TRACE("got value (type=%ld), returing <%s>\n", type,
509                   (ret) ? "TRUE" : "FALSE");
510         }
511         else {
512             ret = fDefault;
513             TRACE("returning default data <%s>\n",
514                   (ret) ? "TRUE" : "FALSE");
515         }
516         return ret;
517 }
518
519 /*************************************************************************
520  *      SHRegQueryInfoUSKeyA    [SHLWAPI.@]
521  */
522 LONG WINAPI SHRegQueryInfoUSKeyA(
523         HUSKEY hUSKey,             /* [in]  */
524         LPDWORD pcSubKeys,
525         LPDWORD pcchMaxSubKeyLen,
526         LPDWORD pcValues,
527         LPDWORD pcchMaxValueNameLen,
528         SHREGENUM_FLAGS enumRegFlags)
529 {
530         HKEY dokey;
531         LONG ret;
532
533         TRACE("(0x%lx,%p,%p,%p,%p,%d)\n",
534               (LONG)hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
535               pcchMaxValueNameLen,enumRegFlags);
536
537         /* if user wants HKCU, and it exists, then try it */
538         if (((enumRegFlags == SHREGENUM_HKCU) ||
539              (enumRegFlags == SHREGENUM_DEFAULT)) &&
540             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
541             ret = RegQueryInfoKeyA(dokey, 0, 0, 0,
542                                    pcSubKeys, pcchMaxSubKeyLen, 0,
543                                    pcValues, pcchMaxValueNameLen, 0, 0, 0);
544             if ((ret == ERROR_SUCCESS) ||
545                 (enumRegFlags == SHREGENUM_HKCU))
546                 return ret;
547         }
548         if (((enumRegFlags == SHREGENUM_HKLM) ||
549              (enumRegFlags == SHREGENUM_DEFAULT)) &&
550             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
551             return RegQueryInfoKeyA(dokey, 0, 0, 0,
552                                     pcSubKeys, pcchMaxSubKeyLen, 0,
553                                     pcValues, pcchMaxValueNameLen, 0, 0, 0);
554         }
555         return ERROR_INVALID_FUNCTION;
556 }
557
558 /*************************************************************************
559  *      SHRegQueryInfoUSKeyW    [SHLWAPI.@]
560  */
561 LONG WINAPI SHRegQueryInfoUSKeyW(
562         HUSKEY hUSKey,             /* [in]  */
563         LPDWORD pcSubKeys,
564         LPDWORD pcchMaxSubKeyLen,
565         LPDWORD pcValues,
566         LPDWORD pcchMaxValueNameLen,
567         SHREGENUM_FLAGS enumRegFlags)
568 {
569         HKEY dokey;
570         LONG ret;
571
572         TRACE("(0x%lx,%p,%p,%p,%p,%d)\n",
573               (LONG)hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
574               pcchMaxValueNameLen,enumRegFlags);
575
576         /* if user wants HKCU, and it exists, then try it */
577         if (((enumRegFlags == SHREGENUM_HKCU) ||
578              (enumRegFlags == SHREGENUM_DEFAULT)) &&
579             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
580             ret = RegQueryInfoKeyW(dokey, 0, 0, 0,
581                                    pcSubKeys, pcchMaxSubKeyLen, 0,
582                                    pcValues, pcchMaxValueNameLen, 0, 0, 0);
583             if ((ret == ERROR_SUCCESS) ||
584                 (enumRegFlags == SHREGENUM_HKCU))
585                 return ret;
586         }
587         if (((enumRegFlags == SHREGENUM_HKLM) ||
588              (enumRegFlags == SHREGENUM_DEFAULT)) &&
589             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
590             return RegQueryInfoKeyW(dokey, 0, 0, 0,
591                                     pcSubKeys, pcchMaxSubKeyLen, 0,
592                                     pcValues, pcchMaxValueNameLen, 0, 0, 0);
593         }
594         return ERROR_INVALID_FUNCTION;
595 }
596
597 /*************************************************************************
598  *      SHRegEnumUSKeyA         [SHLWAPI.@]
599  */
600 LONG WINAPI SHRegEnumUSKeyA(
601         HUSKEY hUSKey,                 /* [in]  */
602         DWORD dwIndex,                 /* [in]  */
603         LPSTR pszName,                 /* [out] */
604         LPDWORD pcchValueNameLen,      /* [in/out] */
605         SHREGENUM_FLAGS enumRegFlags)  /* [in]  */
606 {
607         HKEY dokey;
608
609         TRACE("(0x%lx,%ld,%p,%p(%ld),%d)\n",
610               (LONG)hUSKey, dwIndex, pszName, pcchValueNameLen,
611               *pcchValueNameLen, enumRegFlags);
612
613         if (((enumRegFlags == SHREGENUM_HKCU) ||
614              (enumRegFlags == SHREGENUM_DEFAULT)) &&
615             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
616             return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
617                                 0, 0, 0, 0);
618         }
619
620         if (((enumRegFlags == SHREGENUM_HKLM) ||
621              (enumRegFlags == SHREGENUM_DEFAULT)) &&
622             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
623             return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
624                                 0, 0, 0, 0);
625         }
626         FIXME("no support for SHREGNUM_BOTH\n");
627         return ERROR_INVALID_FUNCTION;
628 }
629
630 /*************************************************************************
631  *      SHRegEnumUSKeyW         [SHLWAPI.@]
632  */
633 LONG WINAPI SHRegEnumUSKeyW(
634         HUSKEY hUSKey,                 /* [in]  */
635         DWORD dwIndex,                 /* [in]  */
636         LPWSTR pszName,                /* [out] */
637         LPDWORD pcchValueNameLen,      /* [in/out] */
638         SHREGENUM_FLAGS enumRegFlags)  /* [in]  */
639 {
640         HKEY dokey;
641
642         TRACE("(0x%lx,%ld,%p,%p(%ld),%d)\n",
643               (LONG)hUSKey, dwIndex, pszName, pcchValueNameLen,
644               *pcchValueNameLen, enumRegFlags);
645
646         if (((enumRegFlags == SHREGENUM_HKCU) ||
647              (enumRegFlags == SHREGENUM_DEFAULT)) &&
648             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
649             return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
650                                 0, 0, 0, 0);
651         }
652
653         if (((enumRegFlags == SHREGENUM_HKLM) ||
654              (enumRegFlags == SHREGENUM_DEFAULT)) &&
655             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
656             return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
657                                 0, 0, 0, 0);
658         }
659         FIXME("no support for SHREGNUM_BOTH\n");
660         return ERROR_INVALID_FUNCTION;
661 }
662
663 /*************************************************************************
664  *      SHRegWriteUSValueA      [SHLWAPI.@]
665  */
666 LONG  WINAPI SHRegWriteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, DWORD dwType,
667                                 LPVOID pvData, DWORD cbData, DWORD dwFlags)
668 {
669     HKEY dokey;
670
671     TRACE("(0x%lx,%s,%ld,%p,%ld,%ld)\n",
672           (LONG)hUSKey, debugstr_a(pszValue), dwType, pvData, cbData, dwFlags);
673
674     if ((dwFlags & SHREGSET_FORCE_HKCU) &&
675             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
676         RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
677     }
678
679     if ((dwFlags & SHREGSET_FORCE_HKLM) &&
680             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
681         RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
682     }
683
684     if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM))
685         return ERROR_SUCCESS;
686
687     FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
688     return ERROR_SUCCESS;
689 }
690
691 /*************************************************************************
692  *      SHRegWriteUSValueW      [SHLWAPI.@]
693  */
694 LONG  WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, DWORD dwType,
695                                 LPVOID pvData, DWORD cbData, DWORD dwFlags)
696 {
697     HKEY dokey;
698
699     TRACE("(0x%lx,%s,%ld,%p,%ld,%ld)\n",
700           (LONG)hUSKey, debugstr_w(pszValue), dwType, pvData, cbData, dwFlags);
701
702     if ((dwFlags & SHREGSET_FORCE_HKCU) &&
703             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
704         RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
705     }
706
707     if ((dwFlags & SHREGSET_FORCE_HKLM) &&
708             (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
709         RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
710     }
711
712     if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM))
713         return ERROR_SUCCESS;
714
715     FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
716     return ERROR_SUCCESS;
717 }
718
719 /*************************************************************************
720  * SHRegGetPathA   [SHLWAPI.@]
721  *
722  * Get a path from the registry.
723  *
724  * PARAMS
725  *   hKey       [I] Handle to registry key
726  *   lpszSubKey [I] Name of sub key containing path to get
727  *   lpszValue  [I] Name of value containing path to get
728  *   lpszPath   [O] Buffer for returned path
729  *   dwFlags    [I] Reserved
730  *
731  * RETURNS
732  *   Success: ERROR_SUCCESS. lpszPath contains the path.
733  *   Failure: An error code from RegOpenKeyExA or SHQueryValueExA.
734  */
735 DWORD WINAPI SHRegGetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
736                            LPSTR lpszPath, DWORD dwFlags)
737 {
738   DWORD dwSize = MAX_PATH;
739
740   TRACE("(hkey=0x%08x,%s,%s,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
741         debugstr_a(lpszValue), lpszPath, dwFlags);
742
743   return SHGetValueA(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize);
744 }
745
746 /*************************************************************************
747  * SHRegGetPathW   [SHLWAPI.@]
748  *
749  * See SHRegGetPathA.
750  */
751 DWORD WINAPI SHRegGetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
752                            LPWSTR lpszPath, DWORD dwFlags)
753 {
754   DWORD dwSize = MAX_PATH;
755
756   TRACE("(hkey=0x%08x,%s,%s,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
757         debugstr_w(lpszValue), lpszPath, dwFlags);
758
759   return SHGetValueW(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize);
760 }
761
762
763 /*************************************************************************
764  * SHRegSetPathA   [SHLWAPI.@]
765  *
766  * Write a path to the registry.
767  *
768  * PARAMS
769  *   hKey       [I] Handle to registry key
770  *   lpszSubKey [I] Name of sub key containing path to set
771  *   lpszValue  [I] Name of value containing path to set
772  *   lpszPath   [O] Path to write
773  *   dwFlags    [I] Reserved
774  *
775  * RETURNS
776  *   Success: ERROR_SUCCESS.
777  *   Failure: An error code from SHSetValueA.
778  */
779 DWORD WINAPI SHRegSetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
780                            LPCSTR lpszPath, DWORD dwFlags)
781 {
782   char szBuff[MAX_PATH];
783
784   FIXME("(hkey=0x%08x,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_a(lpszSubKey),
785         debugstr_a(lpszValue), lpszPath, dwFlags);
786
787   lstrcpyA(szBuff, lpszPath);
788
789   /* FIXME: PathUnExpandEnvStringsA(szBuff); */
790
791   return SHSetValueA(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
792                      lstrlenA(szBuff));
793 }
794
795 /*************************************************************************
796  * SHRegSetPathW   [SHLWAPI.@]
797  *
798  * See SHRegSetPathA.
799  */
800 DWORD WINAPI SHRegSetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
801                            LPCWSTR lpszPath, DWORD dwFlags)
802 {
803   WCHAR szBuff[MAX_PATH];
804
805   FIXME("(hkey=0x%08x,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_w(lpszSubKey),
806         debugstr_w(lpszValue), lpszPath, dwFlags);
807
808   lstrcpyW(szBuff, lpszPath);
809
810   /* FIXME: PathUnExpandEnvStringsW(szBuff); */
811
812   return SHSetValueW(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
813                      lstrlenW(szBuff));
814 }
815
816 /*************************************************************************
817  * SHGetValueA   [SHLWAPI.@]
818  *
819  * Get a value from the registry.
820  *
821  * PARAMS
822  *   hKey       [I] Handle to registry key
823  *   lpszSubKey [I] Name of sub key containing value to get
824  *   lpszValue  [I] Name of value to get
825  *   pwType     [O] Pointer to the values type
826  *   pvData     [O] Pointer to the values data
827  *   pcbData    [O] Pointer to the values size
828  *
829  * RETURNS
830  *   Success: ERROR_SUCCESS. Output parameters contain the details read.
831  *   Failure: An error code from RegOpenKeyExA or SHQueryValueExA.
832  */
833 DWORD WINAPI SHGetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
834                          LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
835 {
836   DWORD dwRet = 0;
837   HKEY hSubKey = 0;
838
839   TRACE("(hkey=0x%08x,%s,%s,%p,%p,%p)\n", hKey, debugstr_a(lpszSubKey),
840         debugstr_a(lpszValue), pwType, pvData, pcbData);
841
842   /*   lpszSubKey can be 0. In this case the value is taken from the
843    *   current key.
844    */
845   if(lpszSubKey)
846     dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
847
848   if (! dwRet)
849   {
850     /* SHQueryValueEx expands Environment strings */
851     dwRet = SHQueryValueExA(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData);
852     if (hSubKey) RegCloseKey(hSubKey);
853   }
854   return dwRet;
855 }
856
857 /*************************************************************************
858  * SHGetValueW   [SHLWAPI.@]
859  *
860  * See SHGetValueA.
861  */
862 DWORD WINAPI SHGetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
863                          LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
864 {
865   DWORD dwRet = 0;
866   HKEY hSubKey = 0;
867
868   TRACE("(hkey=0x%08x,%s,%s,%p,%p,%p)\n", hKey, debugstr_w(lpszSubKey),
869         debugstr_w(lpszValue), pwType, pvData, pcbData);
870
871   if(lpszSubKey)
872     dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
873
874   if (! dwRet)
875   {
876     dwRet = SHQueryValueExW(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData);
877     if (hSubKey) RegCloseKey(hSubKey);
878   }
879   return dwRet;
880 }
881
882 /*************************************************************************
883  * SHSetValueA   [SHLWAPI.@]
884  *
885  * Set a value in the registry.
886  *
887  * PARAMS
888  *   hKey       [I] Handle to registry key
889  *   lpszSubKey [I] Name of sub key under hKey
890  *   lpszValue  [I] Name of value to set
891  *   dwType     [I] Type of the value
892  *   pvData     [I] Data of the value
893  *   cbData     [I] Size of the value
894  *
895  * RETURNS
896  *   Success: ERROR_SUCCESS. The value is set with the data given.
897  *   Failure: An error code from RegCreateKeyExA or RegSetValueExA
898  *
899  * NOTES
900  *   If the sub key does not exist, it is created before the value is set. If
901  *   The sub key is NULL or an empty string, then the value is added directly
902  *   to hKey instead.
903  */
904 DWORD WINAPI SHSetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
905                          DWORD dwType, LPCVOID pvData, DWORD cbData)
906 {
907   DWORD dwRet = ERROR_SUCCESS, dwDummy;
908   HKEY  hSubKey;
909   LPSTR szEmpty = "";
910
911   TRACE("(hkey=0x%08x,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
912           debugstr_a(lpszValue), dwType, pvData, cbData);
913
914   if (lpszSubKey && *lpszSubKey)
915     dwRet = RegCreateKeyExA(hKey, lpszSubKey, 0, szEmpty,
916                             0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
917   else
918     hSubKey = hKey;
919   if (!dwRet)
920   {
921     dwRet = RegSetValueExA(hSubKey, lpszValue, 0, dwType, pvData, cbData);
922     if (hSubKey != hKey)
923       RegCloseKey(hSubKey);
924   }
925   return dwRet;
926 }
927
928 /*************************************************************************
929  * SHSetValueW   [SHLWAPI.@]
930  *
931  * See SHSetValueA.
932  */
933 DWORD WINAPI SHSetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
934                          DWORD dwType, LPCVOID pvData, DWORD cbData)
935 {
936   DWORD dwRet = ERROR_SUCCESS, dwDummy;
937   HKEY  hSubKey;
938   WCHAR szEmpty[] = { '\0' };
939
940   TRACE("(hkey=0x%08x,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
941         debugstr_w(lpszValue), dwType, pvData, cbData);
942
943   if (lpszSubKey && *lpszSubKey)
944     dwRet = RegCreateKeyExW(hKey, lpszSubKey, 0, szEmpty,
945                             0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
946   else
947     hSubKey = hKey;
948   if (!dwRet)
949   {
950     dwRet = RegSetValueExW(hSubKey, lpszValue, 0, dwType, pvData, cbData);
951     if (hSubKey != hKey)
952       RegCloseKey(hSubKey);
953   }
954   return dwRet;
955 }
956
957 /*************************************************************************
958  * SHQueryInfoKeyA   [SHLWAPI.@]
959  *
960  * Get information about a registry key. See RegQueryInfoKeyA.
961  */
962 LONG WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
963                             LPDWORD pwValues, LPDWORD pwValueMax)
964 {
965   TRACE("(hkey=0x%08x,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
966         pwValues, pwValueMax);
967   return RegQueryInfoKeyA(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
968                           NULL, pwValues, pwValueMax, NULL, NULL, NULL);
969 }
970
971 /*************************************************************************
972  * SHQueryInfoKeyW   [SHLWAPI.@]
973  *
974  * See SHQueryInfoKeyA
975  */
976 LONG WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
977                             LPDWORD pwValues, LPDWORD pwValueMax)
978 {
979   TRACE("(hkey=0x%08x,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
980         pwValues, pwValueMax);
981   return RegQueryInfoKeyW(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
982                           NULL, pwValues, pwValueMax, NULL, NULL, NULL);
983 }
984
985 /*************************************************************************
986  * SHQueryValueExA   [SHLWAPI.@]
987  *
988  * Get a value from the registry, expanding environment variable strings.
989  *
990  * PARAMS
991  *   hKey       [I] Handle to registry key
992  *   lpszValue  [I] Name of value to query
993  *   lpReserved [O] Reserved for future use; must be NULL
994  *   pwType     [O] Optional pointer updated with the values type
995  *   pvData     [O] Optional pointer updated with the values data
996  *   pcbData    [O] Optional pointer updated with the values size
997  *
998  * RETURNS
999  *   Success: ERROR_SUCCESS. Any non-NULL output parameters are updated with
1000  *            information about the value.
1001  *   Failure: ERROR_OUTOFMEMORY if memory allocation fails, or the type of the
1002  *            data is REG_EXPAND_SZ and pcbData is NULL. Otherwise an error
1003  *            code from RegQueryValueExA or ExpandEnvironmentStringsA.
1004  *
1005  * NOTES
1006  *   Either pwType, pvData or pcbData may be NULL if the caller doesn't want
1007  *   the type, data or size information for the value.
1008  *
1009  *   If the type of the data is REG_EXPAND_SZ, it is expanded to REG_SZ. The
1010  *   value returned will be truncated if it is of type REG_SZ and bigger than
1011  *   the buffer given to store it.
1012  *
1013  *   REG_EXPAND_SZ
1014  *     case 1: the unexpanded string is smaller than the expanded one
1015  *       subcase 1: the buffer is to small to hold the unexpanded string:
1016  *          function fails and returns the size of the unexpanded string.
1017  *
1018  *       subcase 2: buffer is to small to hold the expanded string:
1019  *          the function return success (!!) and the result is truncated
1020  *          *** This is clearly a error in the native implemantation. ***
1021  *
1022  *     case 2: the unexpanded string is bigger than the expanded one
1023  *       The buffer must have enough space to hold the unexpanded
1024  *       string even if the result is smaller.
1025  *
1026  */
1027 DWORD WINAPI SHQueryValueExA( HKEY hKey, LPCSTR lpszValue,
1028                               LPDWORD lpReserved, LPDWORD pwType,
1029                               LPVOID pvData, LPDWORD pcbData)
1030 {
1031   DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen;
1032
1033   TRACE("(hkey=0x%08x,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_a(lpszValue),
1034         lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1035
1036   if (pcbData) dwUnExpDataLen = *pcbData;
1037
1038   dwRet = RegQueryValueExA(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen);
1039
1040   if (pcbData && (dwType == REG_EXPAND_SZ))
1041   {
1042     DWORD nBytesToAlloc;
1043
1044     /* Expand type REG_EXPAND_SZ into REG_SZ */
1045     LPSTR szData;
1046
1047     /* If the caller didn't supply a buffer or the buffer is to small we have
1048      * to allocate our own
1049      */
1050     if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
1051     {
1052       char cNull = '\0';
1053       nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData;
1054
1055       szData = (LPSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc);
1056       RegQueryValueExA (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
1057       dwExpDataLen = ExpandEnvironmentStringsA(szData, &cNull, 1);
1058       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1059       LocalFree((HLOCAL) szData);
1060     }
1061     else
1062     {
1063       nBytesToAlloc = lstrlenA(pvData) * sizeof (CHAR);
1064       szData = (LPSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc + 1);
1065       lstrcpyA(szData, pvData);
1066       dwExpDataLen = ExpandEnvironmentStringsA(szData, pvData, *pcbData / sizeof(CHAR));
1067       if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
1068       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1069       LocalFree((HLOCAL) szData);
1070     }
1071   }
1072
1073   /* Update the type and data size if the caller wanted them */
1074   if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ;
1075   if ( pwType ) *pwType = dwType;
1076   if ( pcbData ) *pcbData = dwUnExpDataLen;
1077   return dwRet;
1078 }
1079
1080
1081 /*************************************************************************
1082  * SHQueryValueExW   [SHLWAPI.@]
1083  *
1084  * See SHQueryValueExA.
1085  */
1086 DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue,
1087                              LPDWORD lpReserved, LPDWORD pwType,
1088                              LPVOID pvData, LPDWORD pcbData)
1089 {
1090   DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen;
1091
1092   TRACE("(hkey=0x%08x,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_w(lpszValue),
1093         lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1094
1095   if (pcbData) dwUnExpDataLen = *pcbData;
1096
1097   dwRet = RegQueryValueExW(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen);
1098
1099   if (pcbData && (dwType == REG_EXPAND_SZ))
1100   {
1101     DWORD nBytesToAlloc;
1102
1103     /* Expand type REG_EXPAND_SZ into REG_SZ */
1104     LPWSTR szData;
1105
1106     /* If the caller didn't supply a buffer or the buffer is to small we have
1107      * to allocate our own
1108      */
1109     if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
1110     {
1111       WCHAR cNull = '\0';
1112       nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData;
1113
1114       szData = (LPWSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc);
1115       RegQueryValueExW (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
1116       dwExpDataLen = ExpandEnvironmentStringsW(szData, &cNull, 1);
1117       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1118       LocalFree((HLOCAL) szData);
1119     }
1120     else
1121     {
1122       nBytesToAlloc = lstrlenW(pvData) * sizeof(WCHAR);
1123       szData = (LPWSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc + 1);
1124       lstrcpyW(szData, pvData);
1125       dwExpDataLen = ExpandEnvironmentStringsW(szData, pvData, *pcbData/sizeof(WCHAR) );
1126       if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
1127       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1128       LocalFree((HLOCAL) szData);
1129     }
1130   }
1131
1132   /* Update the type and data size if the caller wanted them */
1133   if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ;
1134   if ( pwType ) *pwType = dwType;
1135   if ( pcbData ) *pcbData = dwUnExpDataLen;
1136   return dwRet;
1137 }
1138
1139 /*************************************************************************
1140  * SHDeleteKeyA   [SHLWAPI.@]
1141  *
1142  * Delete a registry key and any sub keys/values present
1143  *
1144  * PARAMS
1145  *   hKey       [I] Handle to registry key
1146  *   lpszSubKey [I] Name of sub key to delete
1147  *
1148  * RETURNS
1149  *   Success: ERROR_SUCCESS. The key is deleted.
1150  *   Failure: An error code from RegOpenKeyExA, RegQueryInfoKeyA,
1151  *          RegEnumKeyExA or RegDeleteKeyA.
1152  */
1153 DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey)
1154 {
1155   DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1156   CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1157   HKEY hSubKey = 0;
1158
1159   TRACE("(hkey=0x%08x,%s)\n", hKey, debugstr_a(lpszSubKey));
1160
1161   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1162   if(!dwRet)
1163   {
1164     /* Find how many subkeys there are */
1165     dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1166                              &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1167     if(!dwRet)
1168     {
1169       dwMaxSubkeyLen++;
1170       if (dwMaxSubkeyLen > sizeof(szNameBuf))
1171         /* Name too big: alloc a buffer for it */
1172         lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(CHAR));
1173
1174       if(!lpszName)
1175         dwRet = ERROR_NOT_ENOUGH_MEMORY;
1176       else
1177       {
1178         /* Recursively delete all the subkeys */
1179         for(i = 0; i < dwKeyCount && !dwRet; i++)
1180         {
1181           dwSize = dwMaxSubkeyLen;
1182           dwRet = RegEnumKeyExA(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1183           if(!dwRet)
1184             dwRet = SHDeleteKeyA(hSubKey, lpszName);
1185         }
1186         if (lpszName != szNameBuf)
1187           HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1188       }
1189     }
1190
1191     RegCloseKey(hSubKey);
1192     if(!dwRet)
1193       dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1194   }
1195   return dwRet;
1196 }
1197
1198 /*************************************************************************
1199  * SHDeleteKeyW   [SHLWAPI.@]
1200  *
1201  * See SHDeleteKeyA.
1202  */
1203 DWORD WINAPI SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1204 {
1205   DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1206   WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1207   HKEY hSubKey = 0;
1208
1209   TRACE("(hkey=0x%08x,%s)\n", hKey, debugstr_w(lpszSubKey));
1210
1211   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1212   if(!dwRet)
1213   {
1214     /* Find how many subkeys there are */
1215     dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1216                              &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1217     if(!dwRet)
1218     {
1219       dwMaxSubkeyLen++;
1220       if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1221         /* Name too big: alloc a buffer for it */
1222         lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1223
1224       if(!lpszName)
1225         dwRet = ERROR_NOT_ENOUGH_MEMORY;
1226       else
1227       {
1228         /* Recursively delete all the subkeys */
1229         for(i = 0; i < dwKeyCount && !dwRet; i++)
1230         {
1231           dwSize = dwMaxSubkeyLen;
1232           dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1233           if(!dwRet)
1234             dwRet = SHDeleteKeyW(hSubKey, lpszName);
1235         }
1236
1237         if (lpszName != szNameBuf)
1238           HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1239       }
1240     }
1241
1242     RegCloseKey(hSubKey);
1243     if(!dwRet)
1244       dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1245   }
1246   return dwRet;
1247 }
1248
1249 /*************************************************************************
1250  * SHDeleteEmptyKeyA   [SHLWAPI.@]
1251  *
1252  * Delete a registry key with no sub keys.
1253  *
1254  * PARAMS
1255  *   hKey       [I] Handle to registry key
1256  *   lpszSubKey [I] Name of sub key to delete
1257  *
1258  * RETURNS
1259  *   Success: ERROR_SUCCESS. The key is deleted.
1260  *   Failure: If the key is not empty, returns ERROR_KEY_HAS_CHILDREN. Otherwise
1261  *          returns an error code from RegOpenKeyExA, RegQueryInfoKeyA or
1262  *          RegDeleteKeyA.
1263  */
1264 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hKey, LPCSTR lpszSubKey)
1265 {
1266   DWORD dwRet, dwKeyCount = 0;
1267   HKEY hSubKey = 0;
1268
1269   TRACE("(hkey=0x%08x,%s)\n", hKey, debugstr_a(lpszSubKey));
1270
1271   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1272   if(!dwRet)
1273   {
1274     dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1275                              NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1276     RegCloseKey(hSubKey);
1277     if(!dwRet)
1278     {
1279       if (!dwKeyCount)
1280         dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1281       else
1282         dwRet = ERROR_KEY_HAS_CHILDREN;
1283     }
1284   }
1285   return dwRet;
1286 }
1287
1288 /*************************************************************************
1289  * SHDeleteEmptyKeyW   [SHLWAPI.@]
1290  *
1291  * See SHDeleteEmptyKeyA.
1292  */
1293 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1294 {
1295   DWORD dwRet, dwKeyCount = 0;
1296   HKEY hSubKey = 0;
1297
1298   TRACE("(hkey=0x%08x, %s)\n", hKey, debugstr_w(lpszSubKey));
1299
1300   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1301   if(!dwRet)
1302   {
1303     dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1304                              NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1305     RegCloseKey(hSubKey);
1306     if(!dwRet)
1307     {
1308       if (!dwKeyCount)
1309         dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1310       else
1311         dwRet = ERROR_KEY_HAS_CHILDREN;
1312     }
1313   }
1314   return dwRet;
1315 }
1316
1317 /*************************************************************************
1318  * SHDeleteOrphanKeyA   [SHLWAPI.@]
1319  *
1320  * Delete a registry key with no sub keys or values.
1321  *
1322  * PARAMS
1323  *   hKey       [I] Handle to registry key
1324  *   lpszSubKey [I] Name of sub key to possibly delete
1325  *
1326  * RETURNS
1327  *   Success: ERROR_SUCCESS. The key has been deleted if it was an orphan.
1328  *   Failure: An error from RegOpenKeyExA, RegQueryValueExA, or RegDeleteKeyA.
1329  */
1330 DWORD WINAPI SHDeleteOrphanKeyA(HKEY hKey, LPCSTR lpszSubKey)
1331 {
1332   HKEY hSubKey;
1333   DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
1334
1335   TRACE("(hkey=0x%08x,%s)\n", hKey, debugstr_a(lpszSubKey));
1336
1337   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1338
1339   if(!dwRet)
1340   {
1341     /* Get subkey and value count */
1342     dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1343                              NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
1344
1345     if(!dwRet && !dwKeyCount && !dwValueCount)
1346     {
1347       dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1348     }
1349     RegCloseKey(hSubKey);
1350   }
1351   return dwRet;
1352 }
1353
1354 /*************************************************************************
1355  * SHDeleteOrphanKeyW   [SHLWAPI.@]
1356  *
1357  * See SHDeleteOrphanKeyA.
1358  */
1359 DWORD WINAPI SHDeleteOrphanKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1360 {
1361   HKEY hSubKey;
1362   DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
1363
1364   TRACE("(hkey=0x%08x,%s)\n", hKey, debugstr_w(lpszSubKey));
1365
1366   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1367
1368   if(!dwRet)
1369   {
1370     /* Get subkey and value count */
1371     dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1372                              NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
1373
1374     if(!dwRet && !dwKeyCount && !dwValueCount)
1375     {
1376       dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1377     }
1378     RegCloseKey(hSubKey);
1379   }
1380   return dwRet;
1381 }
1382
1383 /*************************************************************************
1384  * SHDeleteValueA   [SHLWAPI.@]
1385  *
1386  * Delete a value from the registry.
1387  *
1388  * PARAMS
1389  *   hKey       [I] Handle to registry key
1390  *   lpszSubKey [I] Name of sub key containing value to delete
1391  *   lpszValue  [I] Name of value to delete
1392  *
1393  * RETURNS
1394  *   Success: ERROR_SUCCESS. The value is deleted.
1395  *   Failure: An error code from RegOpenKeyExA or RegDeleteValueA.
1396  */
1397 DWORD WINAPI SHDeleteValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue)
1398 {
1399   DWORD dwRet;
1400   HKEY hSubKey;
1401
1402   TRACE("(hkey=0x%08x,%s,%s)\n", hKey, debugstr_a(lpszSubKey), debugstr_a(lpszValue));
1403
1404   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey);
1405   if (!dwRet)
1406   {
1407     dwRet = RegDeleteValueA(hSubKey, lpszValue);
1408     RegCloseKey(hSubKey);
1409   }
1410   return dwRet;
1411 }
1412
1413 /*************************************************************************
1414  * SHDeleteValueW   [SHLWAPI.@]
1415  *
1416  * See SHDeleteValueA.
1417  */
1418 DWORD WINAPI SHDeleteValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue)
1419 {
1420   DWORD dwRet;
1421   HKEY hSubKey;
1422
1423   TRACE("(hkey=0x%08x,%s,%s)\n", hKey, debugstr_w(lpszSubKey), debugstr_w(lpszValue));
1424
1425   dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey);
1426   if (!dwRet)
1427   {
1428     dwRet = RegDeleteValueW(hSubKey, lpszValue);
1429     RegCloseKey(hSubKey);
1430   }
1431   return dwRet;
1432 }
1433
1434 /*************************************************************************
1435  * SHEnumKeyExA   [SHLWAPI.@]
1436  *
1437  * Enumerate sub keys in a registry key.
1438  *
1439  * PARAMS
1440  *   hKey       [I] Handle to registry key
1441  *   dwIndex    [I] Index of key to enumerate
1442  *   lpszSubKey [O] Pointer updated with the subkey name
1443  *   pwLen      [O] Pointer updated with the subkey length
1444  *
1445  * RETURN
1446  *   Success: ERROR_SUCCESS. lpszSubKey and pwLen are updated.
1447  *   Failure: An error code from RegEnumKeyExA.
1448  */
1449 LONG WINAPI SHEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpszSubKey,
1450                          LPDWORD pwLen)
1451 {
1452   TRACE("(hkey=0x%08x,%ld,%s,%p)\n", hKey, dwIndex, debugstr_a(lpszSubKey), pwLen);
1453
1454   return RegEnumKeyExA(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL);
1455 }
1456
1457 /*************************************************************************
1458  * SHEnumKeyExW   [SHLWAPI.@]
1459  *
1460  * See SHEnumKeyExA.
1461  */
1462 LONG WINAPI SHEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpszSubKey,
1463                          LPDWORD pwLen)
1464 {
1465   TRACE("(hkey=0x%08x,%ld,%s,%p)\n", hKey, dwIndex, debugstr_w(lpszSubKey), pwLen);
1466
1467   return RegEnumKeyExW(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL);
1468 }
1469
1470 /*************************************************************************
1471  * SHEnumValueA   [SHLWAPI.@]
1472  *
1473  * Enumerate values in a registry key.
1474  *
1475  * PARAMS
1476  *   hKey      [I] Handle to registry key
1477  *   dwIndex   [I] Index of key to enumerate
1478  *   lpszValue [O] Pointer updated with the values name
1479  *   pwLen     [O] Pointer updated with the values length
1480  *   pwType    [O] Pointer updated with the values type
1481  *   pvData    [O] Pointer updated with the values data
1482  *   pcbData   [O] Pointer updated with the values size
1483  *
1484  * RETURNS
1485  *   Success: ERROR_SUCCESS. Output parameters are updated.
1486  *   Failure: An error code from RegEnumValueExA.
1487  */
1488 LONG WINAPI SHEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpszValue,
1489                          LPDWORD pwLen, LPDWORD pwType,
1490                          LPVOID pvData, LPDWORD pcbData)
1491 {
1492   TRACE("(hkey=0x%08x,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
1493         debugstr_a(lpszValue), pwLen, pwType, pvData, pcbData);
1494
1495   return RegEnumValueA(hKey, dwIndex, lpszValue, pwLen, NULL,
1496                        pwType, pvData, pcbData);
1497 }
1498
1499 /*************************************************************************
1500  * SHEnumValueW   [SHLWAPI.@]
1501  *
1502  * See SHEnumValueA.
1503  */
1504 LONG WINAPI SHEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpszValue,
1505                          LPDWORD pwLen, LPDWORD pwType,
1506                          LPVOID pvData, LPDWORD pcbData)
1507 {
1508   TRACE("(hkey=0x%08x,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
1509         debugstr_w(lpszValue), pwLen, pwType, pvData, pcbData);
1510
1511   return RegEnumValueW(hKey, dwIndex, lpszValue, pwLen, NULL,
1512                        pwType, pvData, pcbData);
1513 }
1514
1515 /*************************************************************************
1516  * @   [SHLWAPI.205]
1517  *
1518  * Wrapper for SHGetValueA in case machine is in safe mode.
1519  */
1520 DWORD WINAPI SHLWAPI_205(HKEY hkey, LPCSTR pSubKey, LPCSTR pValue,
1521                          LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
1522 {
1523   if (GetSystemMetrics(SM_CLEANBOOT))
1524     return ERROR_INVALID_FUNCTION;
1525   return SHGetValueA(hkey, pSubKey, pValue, pwType, pvData, pbData);
1526 }
1527
1528 /*************************************************************************
1529  * @   [SHLWAPI.206]
1530  *
1531  * Unicode version of SHLWAPI_205.
1532  */
1533 DWORD WINAPI SHLWAPI_206(HKEY hkey, LPCWSTR pSubKey, LPCWSTR pValue,
1534                          LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
1535 {
1536   if (GetSystemMetrics(SM_CLEANBOOT))
1537     return ERROR_INVALID_FUNCTION;
1538   return SHGetValueW(hkey, pSubKey, pValue, pwType, pvData, pbData);
1539 }
1540
1541 /*************************************************************************
1542  * @   [SHLWAPI.320]
1543  *
1544  * Set a MIME content type in the registry.
1545  *
1546  * PARAMS
1547  *   hKey       [I] Handle to registry key
1548  *   lpszSubKey [I] Name of sub key under hKey
1549  *   lpszValue  [I] Value to set
1550  *
1551  * RETURNS
1552  *   Success: TRUE
1553  *   Failure: FALSE
1554  */
1555 BOOL WINAPI SHLWAPI_320(LPCSTR lpszSubKey, LPCSTR lpszValue)
1556 {
1557   DWORD dwRet;
1558
1559   if (!lpszValue)
1560   {
1561     WARN("Invalid lpszValue would crash under Win32!\n");
1562     return FALSE;
1563   }
1564
1565   dwRet = SHSetValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA,
1566                       REG_SZ, lpszValue, strlen(lpszValue));
1567   return dwRet ? FALSE : TRUE;
1568 }
1569
1570 /*************************************************************************
1571  * @   [SHLWAPI.321]
1572  *
1573  * Unicode version of SHLWAPI_320.
1574  */
1575 BOOL WINAPI SHLWAPI_321(LPCWSTR lpszSubKey, LPCWSTR lpszValue)
1576 {
1577   DWORD dwRet;
1578
1579   if (!lpszValue)
1580   {
1581     WARN("Invalid lpszValue would crash under Win32!\n");
1582     return FALSE;
1583   }
1584
1585   dwRet = SHSetValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW,
1586                       REG_SZ, lpszValue, strlenW(lpszValue));
1587   return dwRet ? FALSE : TRUE;
1588 }
1589
1590 /*************************************************************************
1591  * @   [SHLWAPI.322]
1592  *
1593  * Delete a MIME content type from the registry.
1594  *
1595  * PARAMS
1596  *   lpszSubKey [I] Name of sub key
1597  *
1598  * RETURNS
1599  *   Success: TRUE
1600  *   Failure: FALSE
1601  */
1602 BOOL WINAPI SHLWAPI_322(LPCSTR lpszSubKey)
1603 {
1604   HRESULT ret = SHDeleteValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA);
1605   return ret ? FALSE : TRUE;
1606 }
1607
1608 /*************************************************************************
1609  * @   [SHLWAPI.323]
1610  *
1611  * Unicode version of SHLWAPI_322.
1612  */
1613 BOOL WINAPI SHLWAPI_323(LPCWSTR lpszSubKey)
1614 {
1615   HRESULT ret = SHDeleteValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW);
1616   return ret ? FALSE : TRUE;
1617 }
1618
1619 /*************************************************************************
1620  * @   [SHLWAPI.328]
1621  *
1622  * Get the registry path to a MIME content key.
1623  *
1624  * PARAMS
1625  *   lpszType   [I] Content type to get the path for
1626  *   lpszBuffer [O] Destination for path
1627  *   dwLen      [I] Length of lpszBuffer
1628  *
1629  * RETURNS
1630  *   Success: TRUE. lpszBuffer contains the full path.
1631  *   Failure: FALSE.
1632  *
1633  * NOTES
1634  *   The base path for the key is "MIME\Database\Content Type\"
1635  */
1636 BOOL WINAPI SHLWAPI_328(LPCSTR lpszType, LPSTR lpszBuffer, DWORD dwLen)
1637 {
1638   TRACE("(%s,%p,%ld)\n", debugstr_a(lpszType), lpszBuffer, dwLen);
1639
1640   if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer)
1641   {
1642     DWORD dwStrLen = strlen(lpszType);
1643
1644     if (dwStrLen < dwLen - dwLenMimeDbContent)
1645     {
1646       memcpy(lpszBuffer, szMimeDbContentA, dwLenMimeDbContent);
1647       memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, dwStrLen + 1);
1648       return TRUE;
1649     }
1650   }
1651   return FALSE;
1652 }
1653
1654 /*************************************************************************
1655  * @   [SHLWAPI.329]
1656  *
1657  * Unicode version of SHLWAPI_328.
1658  */
1659 BOOL WINAPI SHLWAPI_329(LPCWSTR lpszType, LPWSTR lpszBuffer, DWORD dwLen)
1660 {
1661   TRACE("(%s,%p,%ld)\n", debugstr_w(lpszType), lpszBuffer, dwLen);
1662
1663   if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer)
1664   {
1665     DWORD dwStrLen = strlenW(lpszType);
1666
1667     if (dwStrLen < dwLen - dwLenMimeDbContent)
1668     {
1669       memcpy(lpszBuffer, szMimeDbContentA, dwLenMimeDbContent * sizeof(WCHAR));
1670       memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, (dwStrLen + 1) * sizeof(WCHAR));
1671       return TRUE;
1672     }
1673   }
1674   return FALSE;
1675 }
1676
1677 /*************************************************************************
1678  * @   [SHLWAPI.324]
1679  *
1680  * Set the file extension for a MIME content key.
1681  *
1682  * PARAMS
1683  *   lpszExt  [I] File extension to set
1684  *   lpszType [I] Content type to set the extension for
1685  *
1686  * RETURNS
1687  *   Success: TRUE. The file extension is set in the registry.
1688  *   Failure: FALSE.
1689  */
1690 BOOL WINAPI SHLWAPI_324(LPCSTR lpszExt, LPCSTR lpszType)
1691 {
1692   DWORD dwLen;
1693   char szKey[MAX_PATH];
1694
1695   TRACE("(%s,%s)\n", debugstr_a(lpszExt), debugstr_a(lpszType));
1696
1697   if (!SHLWAPI_328(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1698     return FALSE;
1699
1700   dwLen = strlen(lpszExt) + 1;
1701
1702   if (SHSetValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA, REG_SZ, lpszExt, dwLen))
1703     return FALSE;
1704   return TRUE;
1705 }
1706
1707 /*************************************************************************
1708  * @   [SHLWAPI.325]
1709  *
1710  * Unicode version of SHLWAPI_324.
1711  */
1712 BOOL WINAPI SHLWAPI_325(LPCWSTR lpszExt, LPCWSTR lpszType)
1713 {
1714   DWORD dwLen;
1715   WCHAR szKey[MAX_PATH];
1716
1717   TRACE("(%s,%s)\n", debugstr_w(lpszExt), debugstr_w(lpszType));
1718
1719   /* Get the full path to the key */
1720   if (!SHLWAPI_329(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1721     return FALSE;
1722
1723   dwLen = (lstrlenW(lpszExt) + 1) * sizeof(WCHAR);
1724
1725   if (SHSetValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW, REG_SZ, lpszExt, dwLen))
1726     return FALSE;
1727   return TRUE;
1728 }
1729
1730 /*************************************************************************
1731  * @   [SHLWAPI.326]
1732  *
1733  * Delete a file extension from a MIME content type.
1734  *
1735  * PARAMS
1736  *   lpszType [I] Content type to delete the extension for
1737  *
1738  * RETURNS
1739  *   Success: TRUE. The file extension is deleted from the registry.
1740  *   Failure: FALSE. The extension may have been removed but the key remains.
1741  *
1742  * NOTES
1743  *   If deleting the extension leaves an orphan key, the key is removed also.
1744  */
1745 BOOL WINAPI SHLWAPI_326(LPCSTR lpszType)
1746 {
1747   char szKey[MAX_PATH];
1748
1749   TRACE("(%s)\n", debugstr_a(lpszType));
1750
1751   if (!SHLWAPI_328(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1752     return FALSE;
1753
1754   if (!SHDeleteValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA))
1755     return FALSE;
1756
1757   if (!SHDeleteOrphanKeyA(HKEY_CLASSES_ROOT, szKey))
1758     return FALSE;
1759   return TRUE;
1760 }
1761
1762 /*************************************************************************
1763  * @   [SHLWAPI.327]
1764  *
1765  * Unicode version of SHLWAPI_326.
1766  */
1767 BOOL WINAPI SHLWAPI_327(LPCWSTR lpszType)
1768 {
1769   WCHAR szKey[MAX_PATH];
1770
1771   TRACE("(%s)\n", debugstr_w(lpszType));
1772
1773   if (!SHLWAPI_329(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1774     return FALSE;
1775
1776   if (!SHDeleteValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW))
1777     return FALSE;
1778
1779   if (!SHDeleteOrphanKeyW(HKEY_CLASSES_ROOT, szKey))
1780     return FALSE;
1781   return TRUE;
1782 }
1783
1784 /*************************************************************************
1785  * SHRegDuplicateHKey   [SHLWAPI.@]
1786  */
1787 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1788 {
1789     HKEY newKey = 0;
1790
1791     RegOpenKeyExA(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1792     TRACE("new key is %08x\n", newKey);
1793     return newKey;
1794 }
1795
1796
1797 /*************************************************************************
1798  * SHCopyKeyA   [SHLWAPI.@]
1799  *
1800  * Copy a key and its values/sub keys to another location.
1801  *
1802  * PARAMS
1803  *  hKeyDst    [I] Destination key
1804  *  lpszSubKey [I] Sub key under hKeyDst, or NULL to use hKeyDst directly
1805  *  hKeySrc    [I] Source key to copy from
1806  *  dwReserved [I] Reserved, must be 0
1807  *
1808  * RETURNS
1809  *  Success: ERROR_SUCCESS. The key is copied to the destination key.
1810  *  Failure: A standard windows error code.
1811  *
1812  * NOTES
1813  *  If hKeyDst is a key under hKeySrc, this function will misbehave
1814  *  (It will loop until out of stack, or the registry is full).
1815  */
1816 DWORD WINAPI SHCopyKeyA(HKEY hKeyDst, LPCSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved)
1817 {
1818   WCHAR szSubKeyW[MAX_PATH];
1819
1820   TRACE("(hkey=0x%08x,%s,%0x08x,%ld)\n", hKeyDst, debugstr_a(lpszSubKey), hKeySrc, dwReserved);
1821
1822   if (lpszSubKey)
1823     MultiByteToWideChar(0, 0, lpszSubKey, -1, szSubKeyW, MAX_PATH);
1824
1825   return SHCopyKeyW(hKeyDst, lpszSubKey ? szSubKeyW : NULL, hKeySrc, dwReserved);
1826 }
1827
1828 /*************************************************************************
1829  * SHCopyKeyW   [SHLWAPI.@]
1830  *
1831  * See SHCopyKeyA.
1832  */
1833 DWORD WINAPI SHCopyKeyW(HKEY hKeyDst, LPCWSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved)
1834 {
1835   DWORD dwKeyCount = 0, dwValueCount = 0, dwMaxKeyLen = 0;
1836   DWORD  dwMaxValueLen = 0, dwMaxDataLen = 0, i;
1837   BYTE buff[1024];
1838   LPVOID lpBuff = (LPVOID)buff;
1839   WCHAR szName[MAX_PATH], *lpszName = szName;
1840   DWORD dwRet = S_OK;
1841
1842   TRACE("hkey=0x%08x,%s,%0x08x,%ld)\n", hKeyDst, debugstr_w(lpszSubKey), hKeySrc, dwReserved);
1843
1844   if(!hKeyDst || !hKeySrc)
1845     dwRet = ERROR_INVALID_PARAMETER;
1846   else
1847   {
1848     /* Open destination key */
1849     if(lpszSubKey)
1850       dwRet = RegOpenKeyExW(hKeyDst, lpszSubKey, 0, KEY_ALL_ACCESS, &hKeyDst);
1851
1852     if(dwRet)
1853       hKeyDst = 0; /* Don't close this key since we didn't open it */
1854     else
1855     {
1856       /* Get details about sub keys and values */
1857       dwRet = RegQueryInfoKeyW(hKeySrc, NULL, NULL, NULL, &dwKeyCount, &dwMaxKeyLen,
1858                                NULL, &dwValueCount, &dwMaxValueLen, &dwMaxDataLen,
1859                                NULL, NULL);
1860       if(!dwRet)
1861       {
1862         if (dwMaxValueLen > dwMaxKeyLen)
1863           dwMaxKeyLen = dwMaxValueLen; /* Get max size for key/value names */
1864
1865         if (dwMaxKeyLen++ > MAX_PATH - 1)
1866           lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxKeyLen * sizeof(WCHAR));
1867
1868         if (dwMaxDataLen > sizeof(buff))
1869           lpBuff = HeapAlloc(GetProcessHeap(), 0, dwMaxDataLen);
1870
1871         if (!lpszName || !lpBuff)
1872           dwRet = ERROR_NOT_ENOUGH_MEMORY;
1873       }
1874     }
1875   }
1876
1877   /* Copy all the sub keys */
1878   for(i = 0; i < dwKeyCount && !dwRet; i++)
1879   {
1880     HKEY hSubKeySrc, hSubKeyDst;
1881     DWORD dwSize = dwMaxKeyLen;
1882
1883     dwRet = RegEnumKeyExW(hKeySrc, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1884
1885     if(!dwRet)
1886     {
1887       /* Open source sub key */
1888       dwRet = RegOpenKeyExW(hKeySrc, lpszName, 0, KEY_READ, &hSubKeySrc);
1889
1890       if(!dwRet)
1891       {
1892         /* Create destination sub key */
1893         dwRet = RegCreateKeyW(hKeyDst, lpszName, &hSubKeyDst);
1894
1895         if(!dwRet)
1896         {
1897           /* Recursively copy keys and values from the sub key */
1898           dwRet = SHCopyKeyW(hSubKeyDst, NULL, hSubKeySrc, 0);
1899           RegCloseKey(hSubKeyDst);
1900         }
1901       }
1902       RegCloseKey(hSubKeySrc);
1903     }
1904   }
1905
1906   /* Copy all the values in this key */
1907   for (i = 0; i < dwValueCount && !dwRet; i++)
1908   {
1909     DWORD dwNameSize = dwMaxKeyLen, dwType, dwLen = dwMaxDataLen;
1910
1911     dwRet = RegEnumValueW(hKeySrc, i, lpszName, &dwNameSize, NULL, &dwType, buff, &dwLen);
1912
1913     if (!dwRet)
1914       dwRet = SHSetValueW(hKeyDst, NULL, lpszName, dwType, lpBuff, dwLen);
1915   }
1916
1917   /* Free buffers if allocated */
1918   if (lpszName != szName)
1919     HeapFree(GetProcessHeap(), 0, lpszName);
1920   if (lpBuff != buff)
1921     HeapFree(GetProcessHeap(), 0, lpBuff);
1922
1923   if (lpszSubKey && hKeyDst)
1924     RegCloseKey(hKeyDst);
1925   return dwRet;
1926 }