Some -DSTRICT fixes.
[wine/multimedia.git] / dlls / shlwapi / reg.c
blob68a7b17c00f343b53db8f92ac12b1e2bce067268
1 /*
2 * SHLWAPI registry functions
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2001 Guy Albertelli
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.
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.
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
22 #include <string.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winerror.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "wine/debug.h"
31 #define NO_SHLWAPI_STREAM
32 #include "shlwapi.h"
33 #include "wine/unicode.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(shell);
37 /* Key/Value names for MIME content types */
38 static const char *lpszContentTypeA = "Content Type";
39 static const WCHAR lpszContentTypeW[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
41 static const char *szMimeDbContentA = "MIME\\Database\\Content Type\\";
42 static const WCHAR szMimeDbContentW[] = { 'M', 'I', 'M','E','\\',
43 'D','a','t','a','b','a','s','e','\\','C','o','n','t','e','n','t',
44 ' ','T','y','p','e','\\', '0' };
45 static const DWORD dwLenMimeDbContent = 27; /* strlen of szMimeDbContentA/W */
47 static const char *szExtensionA = "Extension";
48 static const WCHAR szExtensionW[] = { 'E', 'x', 't','e','n','s','i','o','n','\0' };
50 /* internal structure of what the HUSKEY points to */
51 typedef struct {
52 HKEY HKCUkey; /* HKEY of opened HKCU key */
53 HKEY HKLMkey; /* HKEY of opened HKLM key */
54 HKEY start; /* HKEY of where to start */
55 WCHAR key_string[MAX_PATH]; /* additional path from 'start' */
56 } Internal_HUSKEY, *LPInternal_HUSKEY;
59 #define REG_HKCU TRUE
60 #define REG_HKLM FALSE
61 /*************************************************************************
62 * REG_GetHKEYFromHUSKEY
64 * Function: Return the proper registry key from the HUSKEY structure
65 * also allow special predefined values.
67 HKEY REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which)
69 HKEY test = (HKEY) hUSKey;
70 LPInternal_HUSKEY mihk = (LPInternal_HUSKEY) hUSKey;
72 if ((test == HKEY_CLASSES_ROOT) ||
73 (test == HKEY_CURRENT_CONFIG) ||
74 (test == HKEY_CURRENT_USER) ||
75 (test == HKEY_DYN_DATA) ||
76 (test == HKEY_LOCAL_MACHINE) ||
77 (test == HKEY_PERFORMANCE_DATA) ||
78 /* FIXME: need to define for Win2k, ME, XP
79 * (test == HKEY_PERFORMANCE_TEXT) ||
80 * (test == HKEY_PERFORMANCE_NLSTEXT) ||
82 (test == HKEY_USERS)) return test;
83 if (which == REG_HKCU) return mihk->HKCUkey;
84 return mihk->HKLMkey;
88 /*************************************************************************
89 * SHRegOpenUSKeyA [SHLWAPI.@]
91 * Opens a user-specific registry key
93 LONG WINAPI SHRegOpenUSKeyA(
94 LPCSTR Path,
95 REGSAM AccessType,
96 HUSKEY hRelativeUSKey,
97 PHUSKEY phNewUSKey,
98 BOOL fIgnoreHKCU)
100 HKEY openHKCUkey=0;
101 HKEY openHKLMkey=0;
102 LONG ret2, ret1 = ~ERROR_SUCCESS;
103 LPInternal_HUSKEY ihky;
105 TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_a(Path),
106 (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey,
107 (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
109 /* now create the internal version of HUSKEY */
110 ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 ,
111 sizeof(Internal_HUSKEY));
112 MultiByteToWideChar(0, 0, Path, -1, ihky->key_string,
113 sizeof(ihky->key_string)-1);
115 if (hRelativeUSKey) {
116 openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
117 openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
119 else {
120 openHKCUkey = HKEY_CURRENT_USER;
121 openHKLMkey = HKEY_LOCAL_MACHINE;
124 ihky->HKCUkey = 0;
125 ihky->HKLMkey = 0;
126 if (!fIgnoreHKCU) {
127 ret1 = RegOpenKeyExA(openHKCUkey, Path,
128 0, AccessType, &ihky->HKCUkey);
129 /* if successful, then save real starting point */
130 if (ret1 != ERROR_SUCCESS)
131 ihky->HKCUkey = 0;
133 ret2 = RegOpenKeyExA(openHKLMkey, Path,
134 0, AccessType, &ihky->HKLMkey);
135 if (ret2 != ERROR_SUCCESS)
136 ihky->HKLMkey = 0;
138 if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
139 TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
141 /* if all attempts have failed then bail */
142 if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
143 HeapFree(GetProcessHeap(), 0, ihky);
144 if (phNewUSKey)
145 *phNewUSKey = (HUSKEY)0;
146 return ret2;
149 TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
150 if (phNewUSKey)
151 *phNewUSKey = (HUSKEY)ihky;
152 return ERROR_SUCCESS;
155 /*************************************************************************
156 * SHRegOpenUSKeyW [SHLWAPI.@]
158 * Opens a user-specific registry key
160 LONG WINAPI SHRegOpenUSKeyW(
161 LPCWSTR Path,
162 REGSAM AccessType,
163 HUSKEY hRelativeUSKey,
164 PHUSKEY phNewUSKey,
165 BOOL fIgnoreHKCU)
167 HKEY openHKCUkey=0;
168 HKEY openHKLMkey=0;
169 LONG ret2, ret1 = ~ERROR_SUCCESS;
170 LPInternal_HUSKEY ihky;
172 TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_w(Path),
173 (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey,
174 (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
176 /* now create the internal version of HUSKEY */
177 ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 ,
178 sizeof(Internal_HUSKEY));
179 lstrcpynW(ihky->key_string, Path, sizeof(ihky->key_string));
181 if (hRelativeUSKey) {
182 openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
183 openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
185 else {
186 openHKCUkey = HKEY_CURRENT_USER;
187 openHKLMkey = HKEY_LOCAL_MACHINE;
190 ihky->HKCUkey = 0;
191 ihky->HKLMkey = 0;
192 if (!fIgnoreHKCU) {
193 ret1 = RegOpenKeyExW(openHKCUkey, Path,
194 0, AccessType, &ihky->HKCUkey);
195 /* if successful, then save real starting point */
196 if (ret1 != ERROR_SUCCESS)
197 ihky->HKCUkey = 0;
199 ret2 = RegOpenKeyExW(openHKLMkey, Path,
200 0, AccessType, &ihky->HKLMkey);
201 if (ret2 != ERROR_SUCCESS)
202 ihky->HKLMkey = 0;
204 if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
205 TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
207 /* if all attempts have failed then bail */
208 if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
209 HeapFree(GetProcessHeap(), 0, ihky);
210 if (phNewUSKey)
211 *phNewUSKey = (HUSKEY)0;
212 return ret2;
215 TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
216 if (phNewUSKey)
217 *phNewUSKey = (HUSKEY)ihky;
218 return ERROR_SUCCESS;
221 /*************************************************************************
222 * SHRegCloseUSKey [SHLWAPI.@]
224 * Closes a user-specific registry key
226 LONG WINAPI SHRegCloseUSKey(
227 HUSKEY hUSKey)
229 LPInternal_HUSKEY mihk = (LPInternal_HUSKEY)hUSKey;
230 LONG ret = ERROR_SUCCESS;
232 if (mihk->HKCUkey)
233 ret = RegCloseKey(mihk->HKCUkey);
234 if (mihk->HKLMkey)
235 ret = RegCloseKey(mihk->HKLMkey);
236 HeapFree(GetProcessHeap(), 0, mihk);
237 return ret;
240 /*************************************************************************
241 * SHRegQueryUSValueA [SHLWAPI.@]
243 LONG WINAPI SHRegQueryUSValueA(
244 HUSKEY hUSKey, /* [in] */
245 LPCSTR pszValue,
246 LPDWORD pdwType,
247 LPVOID pvData,
248 LPDWORD pcbData,
249 BOOL fIgnoreHKCU,
250 LPVOID pvDefaultData,
251 DWORD dwDefaultDataSize)
253 LONG ret = ~ERROR_SUCCESS;
254 LONG i, maxmove;
255 HKEY dokey;
256 CHAR *src, *dst;
258 /* if user wants HKCU, and it exists, then try it */
259 if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
260 ret = RegQueryValueExA(dokey,
261 pszValue, 0, pdwType, pvData, pcbData);
262 TRACE("HKCU RegQueryValue returned %08lx\n", ret);
265 /* if HKCU did not work and HKLM exists, then try it */
266 if ((ret != ERROR_SUCCESS) &&
267 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
268 ret = RegQueryValueExA(dokey,
269 pszValue, 0, pdwType, pvData, pcbData);
270 TRACE("HKLM RegQueryValue returned %08lx\n", ret);
273 /* if neither worked, and default data exists, then use it */
274 if (ret != ERROR_SUCCESS) {
275 if (pvDefaultData && (dwDefaultDataSize != 0)) {
276 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
277 src = (CHAR*)pvDefaultData;
278 dst = (CHAR*)pvData;
279 for(i=0; i<maxmove; i++) *dst++ = *src++;
280 *pcbData = maxmove;
281 TRACE("setting default data\n");
282 ret = ERROR_SUCCESS;
285 return ret;
289 /*************************************************************************
290 * SHRegQueryUSValueW [SHLWAPI.@]
292 LONG WINAPI SHRegQueryUSValueW(
293 HUSKEY hUSKey, /* [in] */
294 LPCWSTR pszValue,
295 LPDWORD pdwType,
296 LPVOID pvData,
297 LPDWORD pcbData,
298 BOOL fIgnoreHKCU,
299 LPVOID pvDefaultData,
300 DWORD dwDefaultDataSize)
302 LONG ret = ~ERROR_SUCCESS;
303 LONG i, maxmove;
304 HKEY dokey;
305 CHAR *src, *dst;
307 /* if user wants HKCU, and it exists, then try it */
308 if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
309 ret = RegQueryValueExW(dokey,
310 pszValue, 0, pdwType, pvData, pcbData);
311 TRACE("HKCU RegQueryValue returned %08lx\n", ret);
314 /* if HKCU did not work and HKLM exists, then try it */
315 if ((ret != ERROR_SUCCESS) &&
316 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
317 ret = RegQueryValueExW(dokey,
318 pszValue, 0, pdwType, pvData, pcbData);
319 TRACE("HKLM RegQueryValue returned %08lx\n", ret);
322 /* if neither worked, and default data exists, then use it */
323 if (ret != ERROR_SUCCESS) {
324 if (pvDefaultData && (dwDefaultDataSize != 0)) {
325 maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize;
326 src = (CHAR*)pvDefaultData;
327 dst = (CHAR*)pvData;
328 for(i=0; i<maxmove; i++) *dst++ = *src++;
329 *pcbData = maxmove;
330 TRACE("setting default data\n");
331 ret = ERROR_SUCCESS;
334 return ret;
337 /*************************************************************************
338 * SHRegGetUSValueA [SHLWAPI.@]
340 * Gets a user-specific registry value
341 * Will open the key, query the value, and close the key
343 LONG WINAPI SHRegGetUSValueA(
344 LPCSTR pSubKey,
345 LPCSTR pValue,
346 LPDWORD pwType,
347 LPVOID pvData,
348 LPDWORD pcbData,
349 BOOL flagIgnoreHKCU,
350 LPVOID pDefaultData,
351 DWORD wDefaultDataSize)
353 HUSKEY myhuskey;
354 LONG ret;
356 if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
357 TRACE("key '%s', value '%s', datalen %ld, %s\n",
358 debugstr_a(pSubKey), debugstr_a(pValue), *pcbData,
359 (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
361 ret = SHRegOpenUSKeyA(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
362 if (ret == ERROR_SUCCESS) {
363 ret = SHRegQueryUSValueA(myhuskey, pValue, pwType, pvData,
364 pcbData, flagIgnoreHKCU, pDefaultData,
365 wDefaultDataSize);
366 SHRegCloseUSKey(myhuskey);
368 return ret;
371 /*************************************************************************
372 * SHRegGetUSValueW [SHLWAPI.@]
374 * Gets a user-specific registry value
375 * Will open the key, query the value, and close the key
377 LONG WINAPI SHRegGetUSValueW(
378 LPCWSTR pSubKey,
379 LPCWSTR pValue,
380 LPDWORD pwType,
381 LPVOID pvData,
382 LPDWORD pcbData,
383 BOOL flagIgnoreHKCU,
384 LPVOID pDefaultData,
385 DWORD wDefaultDataSize)
387 HUSKEY myhuskey;
388 LONG ret;
390 if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/
391 TRACE("key '%s', value '%s', datalen %ld, %s\n",
392 debugstr_w(pSubKey), debugstr_w(pValue), *pcbData,
393 (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
395 ret = SHRegOpenUSKeyW(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU);
396 if (ret == ERROR_SUCCESS) {
397 ret = SHRegQueryUSValueW(myhuskey, pValue, pwType, pvData,
398 pcbData, flagIgnoreHKCU, pDefaultData,
399 wDefaultDataSize);
400 SHRegCloseUSKey(myhuskey);
402 return ret;
405 /*************************************************************************
406 * SHRegGetBoolUSValueA [SHLWAPI.@]
408 BOOL WINAPI SHRegGetBoolUSValueA(
409 LPCSTR pszSubKey,
410 LPCSTR pszValue,
411 BOOL fIgnoreHKCU,
412 BOOL fDefault)
414 LONG retvalue;
415 DWORD type, datalen, work;
416 BOOL ret = fDefault;
417 CHAR data[10];
419 TRACE("key '%s', value '%s', %s\n",
420 debugstr_a(pszSubKey), debugstr_a(pszValue),
421 (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
423 datalen = sizeof(data)-1;
424 if (!(retvalue = SHRegGetUSValueA( pszSubKey, pszValue, &type,
425 data, &datalen,
426 fIgnoreHKCU, 0, 0))) {
427 /* process returned data via type into bool */
428 switch (type) {
429 case REG_SZ:
430 data[9] = '\0'; /* set end of string */
431 if (lstrcmpiA(data, "YES") == 0) ret = TRUE;
432 if (lstrcmpiA(data, "TRUE") == 0) ret = TRUE;
433 if (lstrcmpiA(data, "NO") == 0) ret = FALSE;
434 if (lstrcmpiA(data, "FALSE") == 0) ret = FALSE;
435 break;
436 case REG_DWORD:
437 work = *(LPDWORD)data;
438 ret = (work != 0);
439 break;
440 case REG_BINARY:
441 if (datalen == 1) {
442 ret = (data[0] != '\0');
443 break;
445 default:
446 FIXME("Unsupported registry data type %ld\n", type);
447 ret = FALSE;
449 TRACE("got value (type=%ld), returing <%s>\n", type,
450 (ret) ? "TRUE" : "FALSE");
452 else {
453 ret = fDefault;
454 TRACE("returning default data <%s>\n",
455 (ret) ? "TRUE" : "FALSE");
457 return ret;
460 /*************************************************************************
461 * SHRegGetBoolUSValueW [SHLWAPI.@]
463 BOOL WINAPI SHRegGetBoolUSValueW(
464 LPCWSTR pszSubKey,
465 LPCWSTR pszValue,
466 BOOL fIgnoreHKCU,
467 BOOL fDefault)
469 static const WCHAR wYES[]= {'Y','E','S','\0'};
470 static const WCHAR wTRUE[]= {'T','R','U','E','\0'};
471 static const WCHAR wNO[]= {'N','O','\0'};
472 static const WCHAR wFALSE[]={'F','A','L','S','E','\0'};
473 LONG retvalue;
474 DWORD type, datalen, work;
475 BOOL ret = fDefault;
476 WCHAR data[10];
478 TRACE("key '%s', value '%s', %s\n",
479 debugstr_w(pszSubKey), debugstr_w(pszValue),
480 (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM");
482 datalen = (sizeof(data)-1) * sizeof(WCHAR);
483 if (!(retvalue = SHRegGetUSValueW( pszSubKey, pszValue, &type,
484 data, &datalen,
485 fIgnoreHKCU, 0, 0))) {
486 /* process returned data via type into bool */
487 switch (type) {
488 case REG_SZ:
489 data[9] = L'\0'; /* set end of string */
490 if (lstrcmpiW(data, wYES)==0 || lstrcmpiW(data, wTRUE)==0)
491 ret = TRUE;
492 else if (lstrcmpiW(data, wNO)==0 || lstrcmpiW(data, wFALSE)==0)
493 ret = FALSE;
494 break;
495 case REG_DWORD:
496 work = *(LPDWORD)data;
497 ret = (work != 0);
498 break;
499 case REG_BINARY:
500 if (datalen == 1) {
501 ret = (data[0] != L'\0');
502 break;
504 default:
505 FIXME("Unsupported registry data type %ld\n", type);
506 ret = FALSE;
508 TRACE("got value (type=%ld), returing <%s>\n", type,
509 (ret) ? "TRUE" : "FALSE");
511 else {
512 ret = fDefault;
513 TRACE("returning default data <%s>\n",
514 (ret) ? "TRUE" : "FALSE");
516 return ret;
519 /*************************************************************************
520 * SHRegQueryInfoUSKeyA [SHLWAPI.@]
522 LONG WINAPI SHRegQueryInfoUSKeyA(
523 HUSKEY hUSKey, /* [in] */
524 LPDWORD pcSubKeys,
525 LPDWORD pcchMaxSubKeyLen,
526 LPDWORD pcValues,
527 LPDWORD pcchMaxValueNameLen,
528 SHREGENUM_FLAGS enumRegFlags)
530 HKEY dokey;
531 LONG ret;
533 TRACE("(0x%lx,%p,%p,%p,%p,%d)\n",
534 (LONG)hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
535 pcchMaxValueNameLen,enumRegFlags);
537 /* if user wants HKCU, and it exists, then try it */
538 if (((enumRegFlags == SHREGENUM_HKCU) ||
539 (enumRegFlags == SHREGENUM_DEFAULT)) &&
540 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
541 ret = RegQueryInfoKeyA(dokey, 0, 0, 0,
542 pcSubKeys, pcchMaxSubKeyLen, 0,
543 pcValues, pcchMaxValueNameLen, 0, 0, 0);
544 if ((ret == ERROR_SUCCESS) ||
545 (enumRegFlags == SHREGENUM_HKCU))
546 return ret;
548 if (((enumRegFlags == SHREGENUM_HKLM) ||
549 (enumRegFlags == SHREGENUM_DEFAULT)) &&
550 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
551 return RegQueryInfoKeyA(dokey, 0, 0, 0,
552 pcSubKeys, pcchMaxSubKeyLen, 0,
553 pcValues, pcchMaxValueNameLen, 0, 0, 0);
555 return ERROR_INVALID_FUNCTION;
558 /*************************************************************************
559 * SHRegQueryInfoUSKeyW [SHLWAPI.@]
561 LONG WINAPI SHRegQueryInfoUSKeyW(
562 HUSKEY hUSKey, /* [in] */
563 LPDWORD pcSubKeys,
564 LPDWORD pcchMaxSubKeyLen,
565 LPDWORD pcValues,
566 LPDWORD pcchMaxValueNameLen,
567 SHREGENUM_FLAGS enumRegFlags)
569 HKEY dokey;
570 LONG ret;
572 TRACE("(0x%lx,%p,%p,%p,%p,%d)\n",
573 (LONG)hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues,
574 pcchMaxValueNameLen,enumRegFlags);
576 /* if user wants HKCU, and it exists, then try it */
577 if (((enumRegFlags == SHREGENUM_HKCU) ||
578 (enumRegFlags == SHREGENUM_DEFAULT)) &&
579 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
580 ret = RegQueryInfoKeyW(dokey, 0, 0, 0,
581 pcSubKeys, pcchMaxSubKeyLen, 0,
582 pcValues, pcchMaxValueNameLen, 0, 0, 0);
583 if ((ret == ERROR_SUCCESS) ||
584 (enumRegFlags == SHREGENUM_HKCU))
585 return ret;
587 if (((enumRegFlags == SHREGENUM_HKLM) ||
588 (enumRegFlags == SHREGENUM_DEFAULT)) &&
589 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
590 return RegQueryInfoKeyW(dokey, 0, 0, 0,
591 pcSubKeys, pcchMaxSubKeyLen, 0,
592 pcValues, pcchMaxValueNameLen, 0, 0, 0);
594 return ERROR_INVALID_FUNCTION;
597 /*************************************************************************
598 * SHRegEnumUSKeyA [SHLWAPI.@]
600 LONG WINAPI SHRegEnumUSKeyA(
601 HUSKEY hUSKey, /* [in] */
602 DWORD dwIndex, /* [in] */
603 LPSTR pszName, /* [out] */
604 LPDWORD pcchValueNameLen, /* [in/out] */
605 SHREGENUM_FLAGS enumRegFlags) /* [in] */
607 HKEY dokey;
609 TRACE("(0x%lx,%ld,%p,%p(%ld),%d)\n",
610 (LONG)hUSKey, dwIndex, pszName, pcchValueNameLen,
611 *pcchValueNameLen, enumRegFlags);
613 if (((enumRegFlags == SHREGENUM_HKCU) ||
614 (enumRegFlags == SHREGENUM_DEFAULT)) &&
615 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
616 return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
617 0, 0, 0, 0);
620 if (((enumRegFlags == SHREGENUM_HKLM) ||
621 (enumRegFlags == SHREGENUM_DEFAULT)) &&
622 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
623 return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen,
624 0, 0, 0, 0);
626 FIXME("no support for SHREGENUM_BOTH\n");
627 return ERROR_INVALID_FUNCTION;
630 /*************************************************************************
631 * SHRegEnumUSKeyW [SHLWAPI.@]
633 LONG WINAPI SHRegEnumUSKeyW(
634 HUSKEY hUSKey, /* [in] */
635 DWORD dwIndex, /* [in] */
636 LPWSTR pszName, /* [out] */
637 LPDWORD pcchValueNameLen, /* [in/out] */
638 SHREGENUM_FLAGS enumRegFlags) /* [in] */
640 HKEY dokey;
642 TRACE("(0x%lx,%ld,%p,%p(%ld),%d)\n",
643 (LONG)hUSKey, dwIndex, pszName, pcchValueNameLen,
644 *pcchValueNameLen, enumRegFlags);
646 if (((enumRegFlags == SHREGENUM_HKCU) ||
647 (enumRegFlags == SHREGENUM_DEFAULT)) &&
648 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
649 return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
650 0, 0, 0, 0);
653 if (((enumRegFlags == SHREGENUM_HKLM) ||
654 (enumRegFlags == SHREGENUM_DEFAULT)) &&
655 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
656 return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen,
657 0, 0, 0, 0);
659 FIXME("no support for SHREGENUM_BOTH\n");
660 return ERROR_INVALID_FUNCTION;
663 /*************************************************************************
664 * SHRegWriteUSValueA [SHLWAPI.@]
666 LONG WINAPI SHRegWriteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, DWORD dwType,
667 LPVOID pvData, DWORD cbData, DWORD dwFlags)
669 HKEY dokey;
671 TRACE("(0x%lx,%s,%ld,%p,%ld,%ld)\n",
672 (LONG)hUSKey, debugstr_a(pszValue), dwType, pvData, cbData, dwFlags);
674 if ((dwFlags & SHREGSET_FORCE_HKCU) &&
675 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
676 RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
679 if ((dwFlags & SHREGSET_FORCE_HKLM) &&
680 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
681 RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
684 if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM))
685 return ERROR_SUCCESS;
687 FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
688 return ERROR_SUCCESS;
691 /*************************************************************************
692 * SHRegWriteUSValueW [SHLWAPI.@]
694 LONG WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, DWORD dwType,
695 LPVOID pvData, DWORD cbData, DWORD dwFlags)
697 HKEY dokey;
699 TRACE("(0x%lx,%s,%ld,%p,%ld,%ld)\n",
700 (LONG)hUSKey, debugstr_w(pszValue), dwType, pvData, cbData, dwFlags);
702 if ((dwFlags & SHREGSET_FORCE_HKCU) &&
703 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
704 RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
707 if ((dwFlags & SHREGSET_FORCE_HKLM) &&
708 (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
709 RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
712 if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM))
713 return ERROR_SUCCESS;
715 FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
716 return ERROR_SUCCESS;
719 /*************************************************************************
720 * SHRegGetPathA [SHLWAPI.@]
722 * Get a path from the registry.
724 * PARAMS
725 * hKey [I] Handle to registry key
726 * lpszSubKey [I] Name of sub key containing path to get
727 * lpszValue [I] Name of value containing path to get
728 * lpszPath [O] Buffer for returned path
729 * dwFlags [I] Reserved
731 * RETURNS
732 * Success: ERROR_SUCCESS. lpszPath contains the path.
733 * Failure: An error code from RegOpenKeyExA or SHQueryValueExA.
735 DWORD WINAPI SHRegGetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
736 LPSTR lpszPath, DWORD dwFlags)
738 DWORD dwSize = MAX_PATH;
740 TRACE("(hkey=%p,%s,%s,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
741 debugstr_a(lpszValue), lpszPath, dwFlags);
743 return SHGetValueA(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize);
746 /*************************************************************************
747 * SHRegGetPathW [SHLWAPI.@]
749 * See SHRegGetPathA.
751 DWORD WINAPI SHRegGetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
752 LPWSTR lpszPath, DWORD dwFlags)
754 DWORD dwSize = MAX_PATH;
756 TRACE("(hkey=%p,%s,%s,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
757 debugstr_w(lpszValue), lpszPath, dwFlags);
759 return SHGetValueW(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize);
763 /*************************************************************************
764 * SHRegSetPathA [SHLWAPI.@]
766 * Write a path to the registry.
768 * PARAMS
769 * hKey [I] Handle to registry key
770 * lpszSubKey [I] Name of sub key containing path to set
771 * lpszValue [I] Name of value containing path to set
772 * lpszPath [O] Path to write
773 * dwFlags [I] Reserved
775 * RETURNS
776 * Success: ERROR_SUCCESS.
777 * Failure: An error code from SHSetValueA.
779 DWORD WINAPI SHRegSetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
780 LPCSTR lpszPath, DWORD dwFlags)
782 char szBuff[MAX_PATH];
784 FIXME("(hkey=%p,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_a(lpszSubKey),
785 debugstr_a(lpszValue), lpszPath, dwFlags);
787 lstrcpyA(szBuff, lpszPath);
789 /* FIXME: PathUnExpandEnvStringsA(szBuff); */
791 return SHSetValueA(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
792 lstrlenA(szBuff));
795 /*************************************************************************
796 * SHRegSetPathW [SHLWAPI.@]
798 * See SHRegSetPathA.
800 DWORD WINAPI SHRegSetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
801 LPCWSTR lpszPath, DWORD dwFlags)
803 WCHAR szBuff[MAX_PATH];
805 FIXME("(hkey=%p,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_w(lpszSubKey),
806 debugstr_w(lpszValue), lpszPath, dwFlags);
808 lstrcpyW(szBuff, lpszPath);
810 /* FIXME: PathUnExpandEnvStringsW(szBuff); */
812 return SHSetValueW(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff,
813 lstrlenW(szBuff));
816 /*************************************************************************
817 * SHGetValueA [SHLWAPI.@]
819 * Get a value from the registry.
821 * PARAMS
822 * hKey [I] Handle to registry key
823 * lpszSubKey [I] Name of sub key containing value to get
824 * lpszValue [I] Name of value to get
825 * pwType [O] Pointer to the values type
826 * pvData [O] Pointer to the values data
827 * pcbData [O] Pointer to the values size
829 * RETURNS
830 * Success: ERROR_SUCCESS. Output parameters contain the details read.
831 * Failure: An error code from RegOpenKeyExA or SHQueryValueExA.
833 DWORD WINAPI SHGetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
834 LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
836 DWORD dwRet = 0;
837 HKEY hSubKey = 0;
839 TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_a(lpszSubKey),
840 debugstr_a(lpszValue), pwType, pvData, pcbData);
842 /* lpszSubKey can be 0. In this case the value is taken from the
843 * current key.
845 if(lpszSubKey)
846 dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
848 if (! dwRet)
850 /* SHQueryValueEx expands Environment strings */
851 dwRet = SHQueryValueExA(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData);
852 if (hSubKey) RegCloseKey(hSubKey);
854 return dwRet;
857 /*************************************************************************
858 * SHGetValueW [SHLWAPI.@]
860 * See SHGetValueA.
862 DWORD WINAPI SHGetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
863 LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
865 DWORD dwRet = 0;
866 HKEY hSubKey = 0;
868 TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_w(lpszSubKey),
869 debugstr_w(lpszValue), pwType, pvData, pcbData);
871 if(lpszSubKey)
872 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey);
874 if (! dwRet)
876 dwRet = SHQueryValueExW(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData);
877 if (hSubKey) RegCloseKey(hSubKey);
879 return dwRet;
882 /*************************************************************************
883 * SHSetValueA [SHLWAPI.@]
885 * Set a value in the registry.
887 * PARAMS
888 * hKey [I] Handle to registry key
889 * lpszSubKey [I] Name of sub key under hKey
890 * lpszValue [I] Name of value to set
891 * dwType [I] Type of the value
892 * pvData [I] Data of the value
893 * cbData [I] Size of the value
895 * RETURNS
896 * Success: ERROR_SUCCESS. The value is set with the data given.
897 * Failure: An error code from RegCreateKeyExA or RegSetValueExA
899 * NOTES
900 * If the sub key does not exist, it is created before the value is set. If
901 * The sub key is NULL or an empty string, then the value is added directly
902 * to hKey instead.
904 DWORD WINAPI SHSetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
905 DWORD dwType, LPCVOID pvData, DWORD cbData)
907 DWORD dwRet = ERROR_SUCCESS, dwDummy;
908 HKEY hSubKey;
909 LPSTR szEmpty = "";
911 TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
912 debugstr_a(lpszValue), dwType, pvData, cbData);
914 if (lpszSubKey && *lpszSubKey)
915 dwRet = RegCreateKeyExA(hKey, lpszSubKey, 0, szEmpty,
916 0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
917 else
918 hSubKey = hKey;
919 if (!dwRet)
921 dwRet = RegSetValueExA(hSubKey, lpszValue, 0, dwType, pvData, cbData);
922 if (hSubKey != hKey)
923 RegCloseKey(hSubKey);
925 return dwRet;
928 /*************************************************************************
929 * SHSetValueW [SHLWAPI.@]
931 * See SHSetValueA.
933 DWORD WINAPI SHSetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
934 DWORD dwType, LPCVOID pvData, DWORD cbData)
936 DWORD dwRet = ERROR_SUCCESS, dwDummy;
937 HKEY hSubKey;
938 WCHAR szEmpty[] = { '\0' };
940 TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
941 debugstr_w(lpszValue), dwType, pvData, cbData);
943 if (lpszSubKey && *lpszSubKey)
944 dwRet = RegCreateKeyExW(hKey, lpszSubKey, 0, szEmpty,
945 0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
946 else
947 hSubKey = hKey;
948 if (!dwRet)
950 dwRet = RegSetValueExW(hSubKey, lpszValue, 0, dwType, pvData, cbData);
951 if (hSubKey != hKey)
952 RegCloseKey(hSubKey);
954 return dwRet;
957 /*************************************************************************
958 * SHQueryInfoKeyA [SHLWAPI.@]
960 * Get information about a registry key. See RegQueryInfoKeyA.
962 LONG WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
963 LPDWORD pwValues, LPDWORD pwValueMax)
965 TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
966 pwValues, pwValueMax);
967 return RegQueryInfoKeyA(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
968 NULL, pwValues, pwValueMax, NULL, NULL, NULL);
971 /*************************************************************************
972 * SHQueryInfoKeyW [SHLWAPI.@]
974 * See SHQueryInfoKeyA
976 LONG WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
977 LPDWORD pwValues, LPDWORD pwValueMax)
979 TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
980 pwValues, pwValueMax);
981 return RegQueryInfoKeyW(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax,
982 NULL, pwValues, pwValueMax, NULL, NULL, NULL);
985 /*************************************************************************
986 * SHQueryValueExA [SHLWAPI.@]
988 * Get a value from the registry, expanding environment variable strings.
990 * PARAMS
991 * hKey [I] Handle to registry key
992 * lpszValue [I] Name of value to query
993 * lpReserved [O] Reserved for future use; must be NULL
994 * pwType [O] Optional pointer updated with the values type
995 * pvData [O] Optional pointer updated with the values data
996 * pcbData [O] Optional pointer updated with the values size
998 * RETURNS
999 * Success: ERROR_SUCCESS. Any non-NULL output parameters are updated with
1000 * information about the value.
1001 * Failure: ERROR_OUTOFMEMORY if memory allocation fails, or the type of the
1002 * data is REG_EXPAND_SZ and pcbData is NULL. Otherwise an error
1003 * code from RegQueryValueExA or ExpandEnvironmentStringsA.
1005 * NOTES
1006 * Either pwType, pvData or pcbData may be NULL if the caller doesn't want
1007 * the type, data or size information for the value.
1009 * If the type of the data is REG_EXPAND_SZ, it is expanded to REG_SZ. The
1010 * value returned will be truncated if it is of type REG_SZ and bigger than
1011 * the buffer given to store it.
1013 * REG_EXPAND_SZ
1014 * case 1: the unexpanded string is smaller than the expanded one
1015 * subcase 1: the buffer is to small to hold the unexpanded string:
1016 * function fails and returns the size of the unexpanded string.
1018 * subcase 2: buffer is to small to hold the expanded string:
1019 * the function return success (!!) and the result is truncated
1020 * *** This is clearly a error in the native implemantation. ***
1022 * case 2: the unexpanded string is bigger than the expanded one
1023 * The buffer must have enough space to hold the unexpanded
1024 * string even if the result is smaller.
1027 DWORD WINAPI SHQueryValueExA( HKEY hKey, LPCSTR lpszValue,
1028 LPDWORD lpReserved, LPDWORD pwType,
1029 LPVOID pvData, LPDWORD pcbData)
1031 DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen;
1033 TRACE("(hkey=%p,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_a(lpszValue),
1034 lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1036 if (pcbData) dwUnExpDataLen = *pcbData;
1038 dwRet = RegQueryValueExA(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen);
1040 if (pcbData && (dwType == REG_EXPAND_SZ))
1042 DWORD nBytesToAlloc;
1044 /* Expand type REG_EXPAND_SZ into REG_SZ */
1045 LPSTR szData;
1047 /* If the caller didn't supply a buffer or the buffer is to small we have
1048 * to allocate our own
1050 if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
1052 char cNull = '\0';
1053 nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData;
1055 szData = (LPSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc);
1056 RegQueryValueExA (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
1057 dwExpDataLen = ExpandEnvironmentStringsA(szData, &cNull, 1);
1058 dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1059 LocalFree((HLOCAL) szData);
1061 else
1063 nBytesToAlloc = lstrlenA(pvData) * sizeof (CHAR);
1064 szData = (LPSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc + 1);
1065 lstrcpyA(szData, pvData);
1066 dwExpDataLen = ExpandEnvironmentStringsA(szData, pvData, *pcbData / sizeof(CHAR));
1067 if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
1068 dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1069 LocalFree((HLOCAL) szData);
1073 /* Update the type and data size if the caller wanted them */
1074 if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ;
1075 if ( pwType ) *pwType = dwType;
1076 if ( pcbData ) *pcbData = dwUnExpDataLen;
1077 return dwRet;
1081 /*************************************************************************
1082 * SHQueryValueExW [SHLWAPI.@]
1084 * See SHQueryValueExA.
1086 DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue,
1087 LPDWORD lpReserved, LPDWORD pwType,
1088 LPVOID pvData, LPDWORD pcbData)
1090 DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen;
1092 TRACE("(hkey=%p,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_w(lpszValue),
1093 lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0);
1095 if (pcbData) dwUnExpDataLen = *pcbData;
1097 dwRet = RegQueryValueExW(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen);
1099 if (pcbData && (dwType == REG_EXPAND_SZ))
1101 DWORD nBytesToAlloc;
1103 /* Expand type REG_EXPAND_SZ into REG_SZ */
1104 LPWSTR szData;
1106 /* If the caller didn't supply a buffer or the buffer is to small we have
1107 * to allocate our own
1109 if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
1111 WCHAR cNull = '\0';
1112 nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData;
1114 szData = (LPWSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc);
1115 RegQueryValueExW (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
1116 dwExpDataLen = ExpandEnvironmentStringsW(szData, &cNull, 1);
1117 dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1118 LocalFree((HLOCAL) szData);
1120 else
1122 nBytesToAlloc = lstrlenW(pvData) * sizeof(WCHAR);
1123 szData = (LPWSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc + 1);
1124 lstrcpyW(szData, pvData);
1125 dwExpDataLen = ExpandEnvironmentStringsW(szData, pvData, *pcbData/sizeof(WCHAR) );
1126 if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
1127 dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
1128 LocalFree((HLOCAL) szData);
1132 /* Update the type and data size if the caller wanted them */
1133 if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ;
1134 if ( pwType ) *pwType = dwType;
1135 if ( pcbData ) *pcbData = dwUnExpDataLen;
1136 return dwRet;
1139 /*************************************************************************
1140 * SHDeleteKeyA [SHLWAPI.@]
1142 * Delete a registry key and any sub keys/values present
1144 * PARAMS
1145 * hKey [I] Handle to registry key
1146 * lpszSubKey [I] Name of sub key to delete
1148 * RETURNS
1149 * Success: ERROR_SUCCESS. The key is deleted.
1150 * Failure: An error code from RegOpenKeyExA, RegQueryInfoKeyA,
1151 * RegEnumKeyExA or RegDeleteKeyA.
1153 DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey)
1155 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1156 CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1157 HKEY hSubKey = 0;
1159 TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey));
1161 dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1162 if(!dwRet)
1164 /* Find how many subkeys there are */
1165 dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1166 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1167 if(!dwRet)
1169 dwMaxSubkeyLen++;
1170 if (dwMaxSubkeyLen > sizeof(szNameBuf))
1171 /* Name too big: alloc a buffer for it */
1172 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(CHAR));
1174 if(!lpszName)
1175 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1176 else
1178 /* Recursively delete all the subkeys */
1179 for(i = 0; i < dwKeyCount && !dwRet; i++)
1181 dwSize = dwMaxSubkeyLen;
1182 dwRet = RegEnumKeyExA(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1183 if(!dwRet)
1184 dwRet = SHDeleteKeyA(hSubKey, lpszName);
1186 if (lpszName != szNameBuf)
1187 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1191 RegCloseKey(hSubKey);
1192 if(!dwRet)
1193 dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1195 return dwRet;
1198 /*************************************************************************
1199 * SHDeleteKeyW [SHLWAPI.@]
1201 * See SHDeleteKeyA.
1203 DWORD WINAPI SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1205 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1206 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1207 HKEY hSubKey = 0;
1209 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1211 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1212 if(!dwRet)
1214 /* Find how many subkeys there are */
1215 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1216 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1217 if(!dwRet)
1219 dwMaxSubkeyLen++;
1220 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1221 /* Name too big: alloc a buffer for it */
1222 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1224 if(!lpszName)
1225 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1226 else
1228 /* Recursively delete all the subkeys */
1229 for(i = 0; i < dwKeyCount && !dwRet; i++)
1231 dwSize = dwMaxSubkeyLen;
1232 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1233 if(!dwRet)
1234 dwRet = SHDeleteKeyW(hSubKey, lpszName);
1237 if (lpszName != szNameBuf)
1238 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1242 RegCloseKey(hSubKey);
1243 if(!dwRet)
1244 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1246 return dwRet;
1249 /*************************************************************************
1250 * SHDeleteEmptyKeyA [SHLWAPI.@]
1252 * Delete a registry key with no sub keys.
1254 * PARAMS
1255 * hKey [I] Handle to registry key
1256 * lpszSubKey [I] Name of sub key to delete
1258 * RETURNS
1259 * Success: ERROR_SUCCESS. The key is deleted.
1260 * Failure: If the key is not empty, returns ERROR_KEY_HAS_CHILDREN. Otherwise
1261 * returns an error code from RegOpenKeyExA, RegQueryInfoKeyA or
1262 * RegDeleteKeyA.
1264 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hKey, LPCSTR lpszSubKey)
1266 DWORD dwRet, dwKeyCount = 0;
1267 HKEY hSubKey = 0;
1269 TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey));
1271 dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1272 if(!dwRet)
1274 dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1275 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1276 RegCloseKey(hSubKey);
1277 if(!dwRet)
1279 if (!dwKeyCount)
1280 dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1281 else
1282 dwRet = ERROR_KEY_HAS_CHILDREN;
1285 return dwRet;
1288 /*************************************************************************
1289 * SHDeleteEmptyKeyW [SHLWAPI.@]
1291 * See SHDeleteEmptyKeyA.
1293 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1295 DWORD dwRet, dwKeyCount = 0;
1296 HKEY hSubKey = 0;
1298 TRACE("(hkey=%p, %s)\n", hKey, debugstr_w(lpszSubKey));
1300 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1301 if(!dwRet)
1303 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1304 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1305 RegCloseKey(hSubKey);
1306 if(!dwRet)
1308 if (!dwKeyCount)
1309 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1310 else
1311 dwRet = ERROR_KEY_HAS_CHILDREN;
1314 return dwRet;
1317 /*************************************************************************
1318 * SHDeleteOrphanKeyA [SHLWAPI.@]
1320 * Delete a registry key with no sub keys or values.
1322 * PARAMS
1323 * hKey [I] Handle to registry key
1324 * lpszSubKey [I] Name of sub key to possibly delete
1326 * RETURNS
1327 * Success: ERROR_SUCCESS. The key has been deleted if it was an orphan.
1328 * Failure: An error from RegOpenKeyExA, RegQueryValueExA, or RegDeleteKeyA.
1330 DWORD WINAPI SHDeleteOrphanKeyA(HKEY hKey, LPCSTR lpszSubKey)
1332 HKEY hSubKey;
1333 DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
1335 TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey));
1337 dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1339 if(!dwRet)
1341 /* Get subkey and value count */
1342 dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1343 NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
1345 if(!dwRet && !dwKeyCount && !dwValueCount)
1347 dwRet = RegDeleteKeyA(hKey, lpszSubKey);
1349 RegCloseKey(hSubKey);
1351 return dwRet;
1354 /*************************************************************************
1355 * SHDeleteOrphanKeyW [SHLWAPI.@]
1357 * See SHDeleteOrphanKeyA.
1359 DWORD WINAPI SHDeleteOrphanKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1361 HKEY hSubKey;
1362 DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
1364 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1366 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1368 if(!dwRet)
1370 /* Get subkey and value count */
1371 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1372 NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
1374 if(!dwRet && !dwKeyCount && !dwValueCount)
1376 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1378 RegCloseKey(hSubKey);
1380 return dwRet;
1383 /*************************************************************************
1384 * SHDeleteValueA [SHLWAPI.@]
1386 * Delete a value from the registry.
1388 * PARAMS
1389 * hKey [I] Handle to registry key
1390 * lpszSubKey [I] Name of sub key containing value to delete
1391 * lpszValue [I] Name of value to delete
1393 * RETURNS
1394 * Success: ERROR_SUCCESS. The value is deleted.
1395 * Failure: An error code from RegOpenKeyExA or RegDeleteValueA.
1397 DWORD WINAPI SHDeleteValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue)
1399 DWORD dwRet;
1400 HKEY hSubKey;
1402 TRACE("(hkey=%p,%s,%s)\n", hKey, debugstr_a(lpszSubKey), debugstr_a(lpszValue));
1404 dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey);
1405 if (!dwRet)
1407 dwRet = RegDeleteValueA(hSubKey, lpszValue);
1408 RegCloseKey(hSubKey);
1410 return dwRet;
1413 /*************************************************************************
1414 * SHDeleteValueW [SHLWAPI.@]
1416 * See SHDeleteValueA.
1418 DWORD WINAPI SHDeleteValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue)
1420 DWORD dwRet;
1421 HKEY hSubKey;
1423 TRACE("(hkey=%p,%s,%s)\n", hKey, debugstr_w(lpszSubKey), debugstr_w(lpszValue));
1425 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey);
1426 if (!dwRet)
1428 dwRet = RegDeleteValueW(hSubKey, lpszValue);
1429 RegCloseKey(hSubKey);
1431 return dwRet;
1434 /*************************************************************************
1435 * SHEnumKeyExA [SHLWAPI.@]
1437 * Enumerate sub keys in a registry key.
1439 * PARAMS
1440 * hKey [I] Handle to registry key
1441 * dwIndex [I] Index of key to enumerate
1442 * lpszSubKey [O] Pointer updated with the subkey name
1443 * pwLen [O] Pointer updated with the subkey length
1445 * RETURN
1446 * Success: ERROR_SUCCESS. lpszSubKey and pwLen are updated.
1447 * Failure: An error code from RegEnumKeyExA.
1449 LONG WINAPI SHEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpszSubKey,
1450 LPDWORD pwLen)
1452 TRACE("(hkey=%p,%ld,%s,%p)\n", hKey, dwIndex, debugstr_a(lpszSubKey), pwLen);
1454 return RegEnumKeyExA(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL);
1457 /*************************************************************************
1458 * SHEnumKeyExW [SHLWAPI.@]
1460 * See SHEnumKeyExA.
1462 LONG WINAPI SHEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpszSubKey,
1463 LPDWORD pwLen)
1465 TRACE("(hkey=%p,%ld,%s,%p)\n", hKey, dwIndex, debugstr_w(lpszSubKey), pwLen);
1467 return RegEnumKeyExW(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL);
1470 /*************************************************************************
1471 * SHEnumValueA [SHLWAPI.@]
1473 * Enumerate values in a registry key.
1475 * PARAMS
1476 * hKey [I] Handle to registry key
1477 * dwIndex [I] Index of key to enumerate
1478 * lpszValue [O] Pointer updated with the values name
1479 * pwLen [O] Pointer updated with the values length
1480 * pwType [O] Pointer updated with the values type
1481 * pvData [O] Pointer updated with the values data
1482 * pcbData [O] Pointer updated with the values size
1484 * RETURNS
1485 * Success: ERROR_SUCCESS. Output parameters are updated.
1486 * Failure: An error code from RegEnumValueA.
1488 LONG WINAPI SHEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpszValue,
1489 LPDWORD pwLen, LPDWORD pwType,
1490 LPVOID pvData, LPDWORD pcbData)
1492 TRACE("(hkey=%p,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
1493 debugstr_a(lpszValue), pwLen, pwType, pvData, pcbData);
1495 return RegEnumValueA(hKey, dwIndex, lpszValue, pwLen, NULL,
1496 pwType, pvData, pcbData);
1499 /*************************************************************************
1500 * SHEnumValueW [SHLWAPI.@]
1502 * See SHEnumValueA.
1504 LONG WINAPI SHEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpszValue,
1505 LPDWORD pwLen, LPDWORD pwType,
1506 LPVOID pvData, LPDWORD pcbData)
1508 TRACE("(hkey=%p,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
1509 debugstr_w(lpszValue), pwLen, pwType, pvData, pcbData);
1511 return RegEnumValueW(hKey, dwIndex, lpszValue, pwLen, NULL,
1512 pwType, pvData, pcbData);
1515 /*************************************************************************
1516 * @ [SHLWAPI.205]
1518 * Wrapper for SHGetValueA in case machine is in safe mode.
1520 DWORD WINAPI SHLWAPI_205(HKEY hkey, LPCSTR pSubKey, LPCSTR pValue,
1521 LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
1523 if (GetSystemMetrics(SM_CLEANBOOT))
1524 return ERROR_INVALID_FUNCTION;
1525 return SHGetValueA(hkey, pSubKey, pValue, pwType, pvData, pbData);
1528 /*************************************************************************
1529 * @ [SHLWAPI.206]
1531 * Unicode version of SHLWAPI_205.
1533 DWORD WINAPI SHLWAPI_206(HKEY hkey, LPCWSTR pSubKey, LPCWSTR pValue,
1534 LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
1536 if (GetSystemMetrics(SM_CLEANBOOT))
1537 return ERROR_INVALID_FUNCTION;
1538 return SHGetValueW(hkey, pSubKey, pValue, pwType, pvData, pbData);
1541 /*************************************************************************
1542 * @ [SHLWAPI.320]
1544 * Set a MIME content type in the registry.
1546 * PARAMS
1547 * hKey [I] Handle to registry key
1548 * lpszSubKey [I] Name of sub key under hKey
1549 * lpszValue [I] Value to set
1551 * RETURNS
1552 * Success: TRUE
1553 * Failure: FALSE
1555 BOOL WINAPI SHLWAPI_320(LPCSTR lpszSubKey, LPCSTR lpszValue)
1557 DWORD dwRet;
1559 if (!lpszValue)
1561 WARN("Invalid lpszValue would crash under Win32!\n");
1562 return FALSE;
1565 dwRet = SHSetValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA,
1566 REG_SZ, lpszValue, strlen(lpszValue));
1567 return dwRet ? FALSE : TRUE;
1570 /*************************************************************************
1571 * @ [SHLWAPI.321]
1573 * Unicode version of SHLWAPI_320.
1575 BOOL WINAPI SHLWAPI_321(LPCWSTR lpszSubKey, LPCWSTR lpszValue)
1577 DWORD dwRet;
1579 if (!lpszValue)
1581 WARN("Invalid lpszValue would crash under Win32!\n");
1582 return FALSE;
1585 dwRet = SHSetValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW,
1586 REG_SZ, lpszValue, strlenW(lpszValue));
1587 return dwRet ? FALSE : TRUE;
1590 /*************************************************************************
1591 * @ [SHLWAPI.322]
1593 * Delete a MIME content type from the registry.
1595 * PARAMS
1596 * lpszSubKey [I] Name of sub key
1598 * RETURNS
1599 * Success: TRUE
1600 * Failure: FALSE
1602 BOOL WINAPI SHLWAPI_322(LPCSTR lpszSubKey)
1604 HRESULT ret = SHDeleteValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA);
1605 return ret ? FALSE : TRUE;
1608 /*************************************************************************
1609 * @ [SHLWAPI.323]
1611 * Unicode version of SHLWAPI_322.
1613 BOOL WINAPI SHLWAPI_323(LPCWSTR lpszSubKey)
1615 HRESULT ret = SHDeleteValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW);
1616 return ret ? FALSE : TRUE;
1619 /*************************************************************************
1620 * @ [SHLWAPI.328]
1622 * Get the registry path to a MIME content key.
1624 * PARAMS
1625 * lpszType [I] Content type to get the path for
1626 * lpszBuffer [O] Destination for path
1627 * dwLen [I] Length of lpszBuffer
1629 * RETURNS
1630 * Success: TRUE. lpszBuffer contains the full path.
1631 * Failure: FALSE.
1633 * NOTES
1634 * The base path for the key is "MIME\Database\Content Type\"
1636 BOOL WINAPI SHLWAPI_328(LPCSTR lpszType, LPSTR lpszBuffer, DWORD dwLen)
1638 TRACE("(%s,%p,%ld)\n", debugstr_a(lpszType), lpszBuffer, dwLen);
1640 if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer)
1642 DWORD dwStrLen = strlen(lpszType);
1644 if (dwStrLen < dwLen - dwLenMimeDbContent)
1646 memcpy(lpszBuffer, szMimeDbContentA, dwLenMimeDbContent);
1647 memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, dwStrLen + 1);
1648 return TRUE;
1651 return FALSE;
1654 /*************************************************************************
1655 * @ [SHLWAPI.329]
1657 * Unicode version of SHLWAPI_328.
1659 BOOL WINAPI SHLWAPI_329(LPCWSTR lpszType, LPWSTR lpszBuffer, DWORD dwLen)
1661 TRACE("(%s,%p,%ld)\n", debugstr_w(lpszType), lpszBuffer, dwLen);
1663 if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer)
1665 DWORD dwStrLen = strlenW(lpszType);
1667 if (dwStrLen < dwLen - dwLenMimeDbContent)
1669 memcpy(lpszBuffer, szMimeDbContentA, dwLenMimeDbContent * sizeof(WCHAR));
1670 memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, (dwStrLen + 1) * sizeof(WCHAR));
1671 return TRUE;
1674 return FALSE;
1677 /*************************************************************************
1678 * @ [SHLWAPI.324]
1680 * Set the file extension for a MIME content key.
1682 * PARAMS
1683 * lpszExt [I] File extension to set
1684 * lpszType [I] Content type to set the extension for
1686 * RETURNS
1687 * Success: TRUE. The file extension is set in the registry.
1688 * Failure: FALSE.
1690 BOOL WINAPI SHLWAPI_324(LPCSTR lpszExt, LPCSTR lpszType)
1692 DWORD dwLen;
1693 char szKey[MAX_PATH];
1695 TRACE("(%s,%s)\n", debugstr_a(lpszExt), debugstr_a(lpszType));
1697 if (!SHLWAPI_328(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1698 return FALSE;
1700 dwLen = strlen(lpszExt) + 1;
1702 if (SHSetValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA, REG_SZ, lpszExt, dwLen))
1703 return FALSE;
1704 return TRUE;
1707 /*************************************************************************
1708 * @ [SHLWAPI.325]
1710 * Unicode version of SHLWAPI_324.
1712 BOOL WINAPI SHLWAPI_325(LPCWSTR lpszExt, LPCWSTR lpszType)
1714 DWORD dwLen;
1715 WCHAR szKey[MAX_PATH];
1717 TRACE("(%s,%s)\n", debugstr_w(lpszExt), debugstr_w(lpszType));
1719 /* Get the full path to the key */
1720 if (!SHLWAPI_329(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1721 return FALSE;
1723 dwLen = (lstrlenW(lpszExt) + 1) * sizeof(WCHAR);
1725 if (SHSetValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW, REG_SZ, lpszExt, dwLen))
1726 return FALSE;
1727 return TRUE;
1730 /*************************************************************************
1731 * @ [SHLWAPI.326]
1733 * Delete a file extension from a MIME content type.
1735 * PARAMS
1736 * lpszType [I] Content type to delete the extension for
1738 * RETURNS
1739 * Success: TRUE. The file extension is deleted from the registry.
1740 * Failure: FALSE. The extension may have been removed but the key remains.
1742 * NOTES
1743 * If deleting the extension leaves an orphan key, the key is removed also.
1745 BOOL WINAPI SHLWAPI_326(LPCSTR lpszType)
1747 char szKey[MAX_PATH];
1749 TRACE("(%s)\n", debugstr_a(lpszType));
1751 if (!SHLWAPI_328(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1752 return FALSE;
1754 if (!SHDeleteValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA))
1755 return FALSE;
1757 if (!SHDeleteOrphanKeyA(HKEY_CLASSES_ROOT, szKey))
1758 return FALSE;
1759 return TRUE;
1762 /*************************************************************************
1763 * @ [SHLWAPI.327]
1765 * Unicode version of SHLWAPI_326.
1767 BOOL WINAPI SHLWAPI_327(LPCWSTR lpszType)
1769 WCHAR szKey[MAX_PATH];
1771 TRACE("(%s)\n", debugstr_w(lpszType));
1773 if (!SHLWAPI_329(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
1774 return FALSE;
1776 if (!SHDeleteValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW))
1777 return FALSE;
1779 if (!SHDeleteOrphanKeyW(HKEY_CLASSES_ROOT, szKey))
1780 return FALSE;
1781 return TRUE;
1784 /*************************************************************************
1785 * SHRegDuplicateHKey [SHLWAPI.@]
1787 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1789 HKEY newKey = 0;
1791 RegOpenKeyExA(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1792 TRACE("new key is %p\n", newKey);
1793 return newKey;
1797 /*************************************************************************
1798 * SHCopyKeyA [SHLWAPI.@]
1800 * Copy a key and its values/sub keys to another location.
1802 * PARAMS
1803 * hKeyDst [I] Destination key
1804 * lpszSubKey [I] Sub key under hKeyDst, or NULL to use hKeyDst directly
1805 * hKeySrc [I] Source key to copy from
1806 * dwReserved [I] Reserved, must be 0
1808 * RETURNS
1809 * Success: ERROR_SUCCESS. The key is copied to the destination key.
1810 * Failure: A standard windows error code.
1812 * NOTES
1813 * If hKeyDst is a key under hKeySrc, this function will misbehave
1814 * (It will loop until out of stack, or the registry is full).
1816 DWORD WINAPI SHCopyKeyA(HKEY hKeyDst, LPCSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved)
1818 WCHAR szSubKeyW[MAX_PATH];
1820 TRACE("(hkey=%p,%s,%p08x,%ld)\n", hKeyDst, debugstr_a(lpszSubKey), hKeySrc, dwReserved);
1822 if (lpszSubKey)
1823 MultiByteToWideChar(0, 0, lpszSubKey, -1, szSubKeyW, MAX_PATH);
1825 return SHCopyKeyW(hKeyDst, lpszSubKey ? szSubKeyW : NULL, hKeySrc, dwReserved);
1828 /*************************************************************************
1829 * SHCopyKeyW [SHLWAPI.@]
1831 * See SHCopyKeyA.
1833 DWORD WINAPI SHCopyKeyW(HKEY hKeyDst, LPCWSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved)
1835 DWORD dwKeyCount = 0, dwValueCount = 0, dwMaxKeyLen = 0;
1836 DWORD dwMaxValueLen = 0, dwMaxDataLen = 0, i;
1837 BYTE buff[1024];
1838 LPVOID lpBuff = (LPVOID)buff;
1839 WCHAR szName[MAX_PATH], *lpszName = szName;
1840 DWORD dwRet = S_OK;
1842 TRACE("hkey=%p,%s,%p08x,%ld)\n", hKeyDst, debugstr_w(lpszSubKey), hKeySrc, dwReserved);
1844 if(!hKeyDst || !hKeySrc)
1845 dwRet = ERROR_INVALID_PARAMETER;
1846 else
1848 /* Open destination key */
1849 if(lpszSubKey)
1850 dwRet = RegOpenKeyExW(hKeyDst, lpszSubKey, 0, KEY_ALL_ACCESS, &hKeyDst);
1852 if(dwRet)
1853 hKeyDst = 0; /* Don't close this key since we didn't open it */
1854 else
1856 /* Get details about sub keys and values */
1857 dwRet = RegQueryInfoKeyW(hKeySrc, NULL, NULL, NULL, &dwKeyCount, &dwMaxKeyLen,
1858 NULL, &dwValueCount, &dwMaxValueLen, &dwMaxDataLen,
1859 NULL, NULL);
1860 if(!dwRet)
1862 if (dwMaxValueLen > dwMaxKeyLen)
1863 dwMaxKeyLen = dwMaxValueLen; /* Get max size for key/value names */
1865 if (dwMaxKeyLen++ > MAX_PATH - 1)
1866 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxKeyLen * sizeof(WCHAR));
1868 if (dwMaxDataLen > sizeof(buff))
1869 lpBuff = HeapAlloc(GetProcessHeap(), 0, dwMaxDataLen);
1871 if (!lpszName || !lpBuff)
1872 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1877 /* Copy all the sub keys */
1878 for(i = 0; i < dwKeyCount && !dwRet; i++)
1880 HKEY hSubKeySrc, hSubKeyDst;
1881 DWORD dwSize = dwMaxKeyLen;
1883 dwRet = RegEnumKeyExW(hKeySrc, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1885 if(!dwRet)
1887 /* Open source sub key */
1888 dwRet = RegOpenKeyExW(hKeySrc, lpszName, 0, KEY_READ, &hSubKeySrc);
1890 if(!dwRet)
1892 /* Create destination sub key */
1893 dwRet = RegCreateKeyW(hKeyDst, lpszName, &hSubKeyDst);
1895 if(!dwRet)
1897 /* Recursively copy keys and values from the sub key */
1898 dwRet = SHCopyKeyW(hSubKeyDst, NULL, hSubKeySrc, 0);
1899 RegCloseKey(hSubKeyDst);
1902 RegCloseKey(hSubKeySrc);
1906 /* Copy all the values in this key */
1907 for (i = 0; i < dwValueCount && !dwRet; i++)
1909 DWORD dwNameSize = dwMaxKeyLen, dwType, dwLen = dwMaxDataLen;
1911 dwRet = RegEnumValueW(hKeySrc, i, lpszName, &dwNameSize, NULL, &dwType, buff, &dwLen);
1913 if (!dwRet)
1914 dwRet = SHSetValueW(hKeyDst, NULL, lpszName, dwType, lpBuff, dwLen);
1917 /* Free buffers if allocated */
1918 if (lpszName != szName)
1919 HeapFree(GetProcessHeap(), 0, lpszName);
1920 if (lpBuff != buff)
1921 HeapFree(GetProcessHeap(), 0, lpBuff);
1923 if (lpszSubKey && hKeyDst)
1924 RegCloseKey(hKeyDst);
1925 return dwRet;