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