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