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