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