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