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