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