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