1 /* 2 * Path Functions 3 * 4 * Copyright 1998, 1999, 2000 Juergen Schmied 5 * Copyright 2004 Juan Lang 6 * Copyright 2018-2022 Katayama Hirofumi MZ 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 * 22 * NOTES: 23 * 24 * Many of these functions are in SHLWAPI.DLL also 25 * 26 */ 27 28 #define WIN32_NO_STATUS 29 #define _INC_WINDOWS 30 #define COBJMACROS 31 32 #include <wine/config.h> 33 34 #include <windef.h> 35 #include <winbase.h> 36 #include <shlobj.h> 37 #include <undocshell.h> 38 #include <shlwapi.h> 39 #include <sddl.h> 40 #include <strsafe.h> 41 #include <wine/debug.h> 42 #include <wine/unicode.h> 43 #include <assert.h> 44 45 #include <shlwapi_undoc.h> 46 #include <shellutils.h> 47 48 #include <userenv.h> 49 50 #include "pidl.h" 51 #include "shell32_main.h" 52 #include "shresdef.h" 53 54 #undef _WIN32_WINNT 55 #define _WIN32_WINNT _WIN32_WINNT_WS03 56 57 WINE_DEFAULT_DEBUG_CHANNEL(shell); 58 59 static const BOOL is_win64 = sizeof(void *) > sizeof(int); 60 61 /* FIXME: Remove this */ 62 typedef enum _NT_PRODUCT_TYPE 63 { 64 NtProductWinNt = 1, 65 NtProductLanManNt, 66 NtProductServer 67 } NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE; 68 69 /* FIXME: We cannot refresh the RtlGetNtProductType value before reboot. */ 70 static BOOL 71 DoGetProductType(PNT_PRODUCT_TYPE ProductType) 72 { 73 HKEY hKey; 74 LONG error; 75 WCHAR szValue[9]; 76 DWORD cbValue; 77 static DWORD s_dwProductType = 0; 78 79 if (s_dwProductType != 0) 80 { 81 *ProductType = s_dwProductType; 82 return TRUE; 83 } 84 85 *ProductType = NtProductServer; 86 87 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_READ, &hKey); 88 if (error) 89 return FALSE; 90 91 cbValue = sizeof(szValue); 92 error = RegGetValueW(hKey, NULL, L"ProductType", RRF_RT_REG_SZ, NULL, (PVOID)szValue, &cbValue); 93 if (!error) 94 { 95 if (lstrcmpW(szValue, L"WinNT") == 0) 96 *ProductType = NtProductWinNt; 97 else if (lstrcmpW(szValue, L"LanmanNT") == 0) 98 *ProductType = NtProductLanManNt; 99 } 100 101 s_dwProductType = *ProductType; 102 103 RegCloseKey(hKey); 104 return TRUE; 105 } 106 107 BOOL APIENTRY IsRemovableDrive(DWORD iDrive) 108 { 109 WCHAR szRoot[] = L"C:\\"; 110 assert(L'A' + iDrive <= L'Z'); 111 szRoot[0] = (WCHAR)(L'A' + iDrive); 112 return GetDriveTypeW(szRoot) == DRIVE_REMOVABLE; 113 } 114 115 /* 116 ########## Combining and Constructing paths ########## 117 */ 118 119 static BOOL WINAPI 120 PathSearchOnExtensionsW( 121 _Inout_ LPWSTR pszPath, 122 _In_opt_ LPCWSTR *ppszDirs, 123 _In_ BOOL bDoSearch, 124 _In_ DWORD dwWhich) 125 { 126 if (*PathFindExtensionW(pszPath) != 0) 127 return FALSE; 128 129 if (bDoSearch) 130 return PathFindOnPathExW(pszPath, ppszDirs, dwWhich); 131 else 132 return PathFileExistsDefExtW(pszPath, dwWhich); 133 } 134 135 #if (_WIN32_WINNT >= _WIN32_WINNT_WS03) 136 static BOOL WINAPI PathIsAbsoluteW(_In_ LPCWSTR path) 137 { 138 return PathIsUNCW(path) || (PathGetDriveNumberW(path) != -1 && path[2] == L'\\'); 139 } 140 141 static BOOL WINAPI PathMakeAbsoluteW(_Inout_ LPWSTR path) 142 { 143 WCHAR path1[MAX_PATH]; 144 DWORD cch; 145 146 if (path == NULL) 147 return FALSE; 148 cch = GetCurrentDirectoryW(_countof(path1), path1); 149 if (!cch || cch > _countof(path1)) 150 return FALSE; 151 return (PathCombineW(path, path1, path) != NULL); 152 } 153 #endif 154 155 BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath); 156 157 static VOID WINAPI 158 PathQualifyExW(_Inout_ LPWSTR pszPath, _Inout_opt_ LPCWSTR pszDir, _In_ DWORD dwFlags) 159 { 160 INT iDrive, cchPathLeft; 161 WCHAR szTemp[MAX_PATH], szRoot[MAX_PATH]; 162 PWCHAR pchTemp = szTemp, pchPath; 163 BOOL bLFN; 164 165 TRACE("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszDir), dwFlags); 166 167 /* Save pszPath path into szTemp for rebuilding the path later */ 168 if (FAILED(StringCchCopyW(szTemp, _countof(szTemp), pszPath))) 169 return; 170 171 /* Replace every '/' by '\' */ 172 FixSlashesAndColonW(szTemp); 173 174 cchPathLeft = MAX_PATH; 175 176 /* Build the root-like path on pszPath, and set pchTemp */ 177 if (!PathIsUNCW(szTemp)) 178 { 179 /* 180 * Non-UNC path. 181 * Determine and normalize the root drive. 182 */ 183 iDrive = PathGetDriveNumberW(szTemp); 184 if (iDrive == -1) 185 { 186 /* 187 * No drive was specified in the path. Try to find one from the 188 * optional directory (if this fails, fall back to the one of the 189 * Windows directory). 190 */ 191 if (!pszDir || FAILED(StringCchCopyW(szRoot, _countof(szRoot), pszDir))) 192 { 193 /* pszDir was invalid or NULL. Fall back to the 194 * Windows directory and find its root. */ 195 szRoot[0] = UNICODE_NULL; 196 GetWindowsDirectoryW(szRoot, _countof(szRoot)); 197 iDrive = PathGetDriveNumberW(szRoot); 198 if (iDrive != -1) 199 PathBuildRootW(szRoot, iDrive); 200 } 201 202 if (szTemp[0] == L'\\') 203 { 204 PathStripToRootW(szRoot); 205 } 206 } 207 else 208 { 209 /* 210 * A drive is specified in the path, that can be either of the 211 * form 'C:\xxx' or of the form 'C:xxx' (relative path). Isolate 212 * the root part 'C:' and the rest of the path 'xxx' in pchTemp. 213 */ 214 PathBuildRootW(szRoot, iDrive); 215 pchTemp += 2; 216 if (*pchTemp == L'\\') 217 ++pchTemp; 218 } 219 220 bLFN = IsLFNDriveW(szRoot); 221 if (!bLFN) 222 { 223 PWCHAR pch; 224 for (pch = pchTemp; *pch != UNICODE_NULL; ++pch) 225 { 226 #define VALID_SHORT_PATH_CHAR_CLASSES ( \ 227 PATH_CHAR_CLASS_DOT | \ 228 PATH_CHAR_CLASS_BACKSLASH | \ 229 PATH_CHAR_CLASS_COLON | \ 230 PATH_CHAR_CLASS_OTHER_VALID \ 231 ) 232 if (!PathIsValidCharW(*pch, VALID_SHORT_PATH_CHAR_CLASSES)) 233 { 234 *pch = L'_'; 235 } 236 } 237 } 238 239 StringCchCopyW(pszPath, MAX_PATH, szRoot); 240 cchPathLeft -= lstrlenW(pszPath) + 1; 241 } 242 else /* UNC path: Begins with double backslash */ 243 { 244 bLFN = IsLFNDriveW(pchTemp); 245 if (bLFN) 246 { 247 pszPath[2] = UNICODE_NULL; /* Cut off */ 248 cchPathLeft -= (2 + 1); 249 pchTemp += 2; 250 } 251 else 252 { 253 PWCHAR pchSlash = StrChrW(pszPath + 2, L'\\'); 254 if (pchSlash) 255 pchSlash = StrChrW(pchSlash + 1, L'\\'); 256 257 if (pchSlash) 258 { 259 *(pchSlash + 1) = UNICODE_NULL; /* Cut off */ 260 pchTemp += pchSlash - pszPath; 261 cchPathLeft -= (INT)(SIZE_T)(pchSlash - pszPath) + 1; 262 } 263 else 264 { 265 bLFN = TRUE; 266 pszPath[2] = UNICODE_NULL; /* Cut off */ 267 cchPathLeft -= 2; 268 pchTemp += 2; 269 } 270 } 271 } 272 /* Now pszPath is a root-like path or an empty string. */ 273 274 /* Start appending the path components of szTemp to pszPath. */ 275 while (*pchTemp && cchPathLeft > 0) 276 { 277 /* Collapse any .\ and ..\ parts in the path */ 278 if (*pchTemp == L'.') 279 { 280 BOOL bDots = FALSE; /* '.' or '..' ? */ 281 282 if (pchTemp[1] == UNICODE_NULL || pchTemp[1] == L'\\') 283 { 284 /* Component '.' */ 285 bDots = TRUE; 286 } 287 else if (pchTemp[1] == L'.' && (pchTemp[2] == UNICODE_NULL || pchTemp[2] == L'\\')) 288 { 289 /* Component '..' */ 290 PathRemoveFileSpecW(pszPath); /* Remove the last component from pszPath */ 291 bDots = TRUE; 292 } 293 294 /* If a '.' or '..' was encountered, skip to the next component */ 295 if (bDots) 296 { 297 while (*pchTemp && *pchTemp != L'\\') 298 { 299 ++pchTemp; 300 } 301 302 while (*pchTemp == L'\\') 303 { 304 ++pchTemp; 305 } 306 307 continue; 308 } 309 } 310 311 /* Otherwise, copy the other path component */ 312 313 if (!PathAddBackslashW(pszPath)) /* Append a backslash at the end */ 314 break; 315 316 --cchPathLeft; 317 318 pchPath = &pszPath[lstrlenW(pszPath)]; 319 320 if (!bLFN) /* Not LFN? */ 321 { 322 /* Copy MS-DOS 8.3 filename */ 323 PWCHAR pchDot = NULL; 324 INT ich; 325 WCHAR szTitle[8 + 1] = L""; 326 INT cchTitle = 0; 327 WCHAR szDotExtension[1 + 3 + 1] = L""; 328 INT cchDotExtension = 0; 329 330 /* Copy the component to szTitle and szDotExtension... */ 331 while (*pchTemp && *pchTemp != L'\\') 332 { 333 if (*pchTemp == L'.') 334 { 335 pchDot = pchTemp; /* Remember the last position */ 336 337 /* Clear szDotExtension */ 338 cchDotExtension = 0; 339 ZeroMemory(szDotExtension, sizeof(szDotExtension)); 340 } 341 342 if (pchDot) 343 { 344 if (cchDotExtension < 1 + 3) 345 szDotExtension[cchDotExtension++] = *pchTemp; 346 } 347 else 348 { 349 if (cchTitle < 8) 350 szTitle[cchTitle++] = *pchTemp; 351 } 352 353 ++pchTemp; 354 } 355 356 /* Add file title 'szTitle' to pchPath */ 357 for (ich = 0; szTitle[ich] && cchPathLeft > 0; ++ich) 358 { 359 *pchPath++ = szTitle[ich]; 360 --cchPathLeft; 361 } 362 363 /* Add file extension 'szDotExtension' to pchPath */ 364 if (pchDot) 365 { 366 for (ich = 0; szDotExtension[ich] && cchPathLeft > 0; ++ich) 367 { 368 *pchPath++ = szDotExtension[ich]; 369 --cchPathLeft; 370 } 371 } 372 } 373 else /* LFN */ 374 { 375 /* Copy the component up to the next separator */ 376 while (*pchTemp != UNICODE_NULL && *pchTemp != L'\\' && cchPathLeft > 0) 377 { 378 *pchPath++ = *pchTemp++; 379 --cchPathLeft; 380 } 381 } 382 383 /* Skip the backslashes */ 384 while (*pchTemp == L'\\') 385 { 386 ++pchTemp; 387 } 388 389 /* Keep null-terminated */ 390 *pchPath = UNICODE_NULL; 391 } 392 393 /* Remove any trailing backslash */ 394 PathRemoveBackslashW(pszPath); 395 396 if (!(dwFlags & 1)) /* Remove the trailing dot? */ 397 { 398 pchPath = CharPrevW(pszPath, pszPath + lstrlenW(pszPath)); 399 if (*pchPath == L'.') 400 *pchPath = UNICODE_NULL; 401 } 402 } 403 404 /************************************************************************* 405 * PathAppend [SHELL32.36] 406 */ 407 BOOL WINAPI PathAppendAW( 408 LPVOID lpszPath1, 409 LPCVOID lpszPath2) 410 { 411 if (SHELL_OsIsUnicode()) 412 return PathAppendW(lpszPath1, lpszPath2); 413 return PathAppendA(lpszPath1, lpszPath2); 414 } 415 416 /************************************************************************* 417 * PathGetExtensionA [internal] 418 * 419 * NOTES 420 * exported by ordinal 421 * return value points to the first char after the dot 422 */ 423 static LPSTR PathGetExtensionA(LPCSTR lpszPath) 424 { 425 TRACE("(%s)\n",lpszPath); 426 427 lpszPath = PathFindExtensionA(lpszPath); 428 return (LPSTR)(*lpszPath?(lpszPath+1):lpszPath); 429 } 430 431 /************************************************************************* 432 * PathGetExtensionW [internal] 433 */ 434 static LPWSTR PathGetExtensionW(LPCWSTR lpszPath) 435 { 436 TRACE("(%s)\n",debugstr_w(lpszPath)); 437 438 lpszPath = PathFindExtensionW(lpszPath); 439 return (LPWSTR)(*lpszPath?(lpszPath+1):lpszPath); 440 } 441 442 /************************************************************************* 443 * SHPathGetExtension [SHELL32.158] 444 */ 445 LPVOID WINAPI SHPathGetExtensionW(LPCWSTR lpszPath, DWORD void1, DWORD void2) 446 { 447 return PathGetExtensionW(lpszPath); 448 } 449 450 /************************************************************************* 451 * PathRemoveFileSpec [SHELL32.35] 452 */ 453 BOOL WINAPI PathRemoveFileSpecAW(LPVOID lpszPath) 454 { 455 if (SHELL_OsIsUnicode()) 456 return PathRemoveFileSpecW(lpszPath); 457 return PathRemoveFileSpecA(lpszPath); 458 } 459 460 /* 461 Path Manipulations 462 */ 463 464 /************************************************************************* 465 * PathGetShortPathA [internal] 466 */ 467 static void PathGetShortPathA(LPSTR pszPath) 468 { 469 CHAR path[MAX_PATH]; 470 471 TRACE("%s\n", pszPath); 472 473 if (GetShortPathNameA(pszPath, path, MAX_PATH)) 474 { 475 lstrcpyA(pszPath, path); 476 } 477 } 478 479 /************************************************************************* 480 * PathGetShortPathW [internal] 481 */ 482 static void PathGetShortPathW(LPWSTR pszPath) 483 { 484 WCHAR path[MAX_PATH]; 485 486 TRACE("%s\n", debugstr_w(pszPath)); 487 488 if (GetShortPathNameW(pszPath, path, MAX_PATH)) 489 { 490 lstrcpyW(pszPath, path); 491 } 492 } 493 494 /************************************************************************* 495 * PathGetShortPath [SHELL32.92] 496 */ 497 VOID WINAPI PathGetShortPathAW(LPVOID pszPath) 498 { 499 if(SHELL_OsIsUnicode()) 500 PathGetShortPathW(pszPath); 501 PathGetShortPathA(pszPath); 502 } 503 504 /* 505 ########## Path Testing ########## 506 */ 507 508 /************************************************************************* 509 * PathIsRoot [SHELL32.29] 510 */ 511 BOOL WINAPI PathIsRootAW(LPCVOID lpszPath) 512 { 513 if (SHELL_OsIsUnicode()) 514 return PathIsRootW(lpszPath); 515 return PathIsRootA(lpszPath); 516 } 517 518 /************************************************************************* 519 * PathIsExeA [internal] 520 */ 521 static BOOL PathIsExeA (LPCSTR lpszPath) 522 { 523 LPCSTR lpszExtension = PathGetExtensionA(lpszPath); 524 int i; 525 static const char * const lpszExtensions[] = 526 {"exe", "com", "pif", "cmd", "bat", "scf", "scr", NULL }; 527 528 TRACE("path=%s\n",lpszPath); 529 530 for(i=0; lpszExtensions[i]; i++) 531 if (!lstrcmpiA(lpszExtension,lpszExtensions[i])) return TRUE; 532 533 return FALSE; 534 } 535 536 /************************************************************************* 537 * PathIsExeW [internal] 538 */ 539 BOOL PathIsExeW (LPCWSTR lpszPath) 540 { 541 LPCWSTR lpszExtension = PathGetExtensionW(lpszPath); 542 int i; 543 static const WCHAR lpszExtensions[][4] = 544 {L"exe", L"com", L"pif", L"cmd", L"bat", L"scf", L"scr", L"" }; 545 546 TRACE("path=%s\n",debugstr_w(lpszPath)); 547 548 for(i=0; lpszExtensions[i][0]; i++) 549 if (!wcsicmp(lpszExtension,lpszExtensions[i])) return TRUE; 550 551 return FALSE; 552 } 553 554 /************************************************************************* 555 * PathIsExe [SHELL32.43] 556 */ 557 BOOL WINAPI PathIsExeAW (LPCVOID path) 558 { 559 if (SHELL_OsIsUnicode()) 560 return PathIsExeW (path); 561 return PathIsExeA(path); 562 } 563 564 /************************************************************************* 565 * PathFileExists [SHELL32.45] 566 */ 567 BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath) 568 { 569 if (SHELL_OsIsUnicode()) 570 return PathFileExistsW (lpszPath); 571 return PathFileExistsA (lpszPath); 572 } 573 574 /************************************************************************* 575 * IsLFNDriveA [SHELL32.41] 576 */ 577 BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath) 578 { 579 WCHAR szBuffW[MAX_PATH], *pszW = NULL; 580 if (lpszPath) 581 { 582 SHAnsiToUnicode(lpszPath, szBuffW, _countof(szBuffW)); 583 pszW = szBuffW; 584 } 585 return IsLFNDriveW(pszW); 586 } 587 588 /************************************************************************* 589 * IsLFNDriveW [SHELL32.42] 590 */ 591 BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath) 592 { 593 DWORD cchMaxFileName, iDrive; 594 WCHAR szRoot[MAX_PATH]; 595 596 if (lpszPath == NULL || lpszPath[0] == UNICODE_NULL) 597 { 598 szRoot[0] = 0; 599 GetWindowsDirectoryW(szRoot, _countof(szRoot)); 600 lpszPath = szRoot; 601 } 602 603 if (PathIsUNCW(lpszPath)) 604 { 605 StringCchCopyW(szRoot, _countof(szRoot), lpszPath); 606 PathStripToRootW(szRoot); 607 608 if (StrChrW(szRoot + 2, L'\\') == NULL) 609 return TRUE; /* LFN */ 610 611 StringCchCatW(szRoot, _countof(szRoot), L"\\"); /* Add a backslash */ 612 } 613 else 614 { 615 iDrive = ((lpszPath[0] - L'A') & 0x1F); 616 PathBuildRootW(szRoot, iDrive); 617 618 if (!IsRemovableDrive(iDrive)) 619 { 620 /* FIXME: Cache correctly */ 621 } 622 } 623 624 #define MSDOS_8DOT3_LEN 12 /* MS-DOS 8.3 filename == length 12 */ 625 626 /* GetVolumeInformation requires a root path */ 627 if (!GetVolumeInformationW(szRoot, NULL, 0, NULL, &cchMaxFileName, NULL, NULL, 0)) 628 { 629 /* Don't return FALSE when GetVolumeInformationW fails. */ 630 return TRUE; 631 } 632 633 return cchMaxFileName > MSDOS_8DOT3_LEN; 634 } 635 636 /************************************************************************* 637 * IsLFNDrive [SHELL32.119] 638 */ 639 BOOL WINAPI IsLFNDriveAW(LPCVOID lpszPath) 640 { 641 if (SHELL_OsIsUnicode()) 642 return IsLFNDriveW(lpszPath); 643 return IsLFNDriveA(lpszPath); 644 } 645 646 /* 647 ########## Creating Something Unique ########## 648 */ 649 /************************************************************************* 650 * PathMakeUniqueNameA [internal] 651 */ 652 static BOOL PathMakeUniqueNameA( 653 LPSTR lpszBuffer, 654 DWORD dwBuffSize, 655 LPCSTR lpszShortName, 656 LPCSTR lpszLongName, 657 LPCSTR lpszPathName) 658 { 659 FIXME("%p %u %s %s %s stub\n", 660 lpszBuffer, dwBuffSize, debugstr_a(lpszShortName), 661 debugstr_a(lpszLongName), debugstr_a(lpszPathName)); 662 return TRUE; 663 } 664 665 /************************************************************************* 666 * PathMakeUniqueNameW [internal] 667 */ 668 static BOOL PathMakeUniqueNameW( 669 LPWSTR lpszBuffer, 670 DWORD dwBuffSize, 671 LPCWSTR lpszShortName, 672 LPCWSTR lpszLongName, 673 LPCWSTR lpszPathName) 674 { 675 FIXME("%p %u %s %s %s stub\n", 676 lpszBuffer, dwBuffSize, debugstr_w(lpszShortName), 677 debugstr_w(lpszLongName), debugstr_w(lpszPathName)); 678 return TRUE; 679 } 680 681 /************************************************************************* 682 * PathMakeUniqueName [SHELL32.47] 683 */ 684 BOOL WINAPI PathMakeUniqueNameAW( 685 LPVOID lpszBuffer, 686 DWORD dwBuffSize, 687 LPCVOID lpszShortName, 688 LPCVOID lpszLongName, 689 LPCVOID lpszPathName) 690 { 691 if (SHELL_OsIsUnicode()) 692 return PathMakeUniqueNameW(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName); 693 return PathMakeUniqueNameA(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName); 694 } 695 696 /************************************************************************* 697 * PathYetAnotherMakeUniqueName [SHELL32.75] 698 */ 699 BOOL WINAPI PathYetAnotherMakeUniqueName(LPWSTR buffer, LPCWSTR path, LPCWSTR shortname, LPCWSTR longname) 700 { 701 WCHAR pathW[MAX_PATH], retW[MAX_PATH]; 702 const WCHAR *file, *ext; 703 int i = 2; 704 705 TRACE("(%p, %s, %s, %s)\n", buffer, debugstr_w(path), debugstr_w(shortname), debugstr_w(longname)); 706 707 file = longname ? longname : shortname; 708 PathCombineW(pathW, path, file); 709 strcpyW(retW, pathW); 710 PathRemoveExtensionW(pathW); 711 712 ext = PathFindExtensionW(file); 713 714 /* now try to make it unique */ 715 while (PathFileExistsW(retW)) 716 { 717 sprintfW(retW, L"%s (%d)%s", pathW, i, ext); 718 i++; 719 } 720 721 strcpyW(buffer, retW); 722 TRACE("ret - %s\n", debugstr_w(buffer)); 723 724 return TRUE; 725 } 726 727 /* 728 ########## cleaning and resolving paths ########## 729 */ 730 731 /************************************************************************* 732 * PathCleanupSpec [SHELL32.171] 733 * 734 * lpszFile is changed in place. 735 */ 736 int WINAPI PathCleanupSpec( LPCWSTR lpszPathW, LPWSTR lpszFileW ) 737 { 738 int i = 0; 739 DWORD rc = 0; 740 int length = 0; 741 742 if (SHELL_OsIsUnicode()) 743 { 744 LPWSTR p = lpszFileW; 745 746 TRACE("Cleanup %s\n",debugstr_w(lpszFileW)); 747 748 if (lpszPathW) 749 length = strlenW(lpszPathW); 750 751 while (*p) 752 { 753 int gct = PathGetCharTypeW(*p); 754 if (gct == GCT_INVALID || gct == GCT_WILD || gct == GCT_SEPARATOR) 755 { 756 lpszFileW[i]='-'; 757 rc |= PCS_REPLACEDCHAR; 758 } 759 else 760 lpszFileW[i]=*p; 761 i++; 762 p++; 763 if (length + i == MAX_PATH) 764 { 765 rc |= PCS_FATAL | PCS_PATHTOOLONG; 766 break; 767 } 768 } 769 lpszFileW[i]=0; 770 } 771 else 772 { 773 LPSTR lpszFileA = (LPSTR)lpszFileW; 774 LPCSTR lpszPathA = (LPCSTR)lpszPathW; 775 LPSTR p = lpszFileA; 776 777 TRACE("Cleanup %s\n",debugstr_a(lpszFileA)); 778 779 if (lpszPathA) 780 length = strlen(lpszPathA); 781 782 while (*p) 783 { 784 int gct = PathGetCharTypeA(*p); 785 if (gct == GCT_INVALID || gct == GCT_WILD || gct == GCT_SEPARATOR) 786 { 787 lpszFileA[i]='-'; 788 rc |= PCS_REPLACEDCHAR; 789 } 790 else 791 lpszFileA[i]=*p; 792 i++; 793 p++; 794 if (length + i == MAX_PATH) 795 { 796 rc |= PCS_FATAL | PCS_PATHTOOLONG; 797 break; 798 } 799 } 800 lpszFileA[i]=0; 801 } 802 return rc; 803 } 804 805 /************************************************************************* 806 * PathQualifyA [SHELL32] 807 */ 808 VOID WINAPI PathQualifyA(LPSTR pszPath) 809 { 810 WCHAR szPath[MAX_PATH]; 811 TRACE("%s\n",pszPath); 812 SHAnsiToUnicode(pszPath, szPath, _countof(szPath)); 813 PathQualifyW(szPath); 814 SHUnicodeToAnsi(szPath, pszPath, MAX_PATH); 815 } 816 817 /************************************************************************* 818 * PathQualifyW [SHELL32] 819 */ 820 VOID WINAPI PathQualifyW(LPWSTR pszPath) 821 { 822 TRACE("%s\n",debugstr_w(pszPath)); 823 PathQualifyExW(pszPath, NULL, 0); 824 } 825 826 /************************************************************************* 827 * PathQualify [SHELL32.49] 828 */ 829 VOID WINAPI PathQualifyAW(LPVOID pszPath) 830 { 831 if (SHELL_OsIsUnicode()) 832 PathQualifyW(pszPath); 833 else 834 PathQualifyA(pszPath); 835 } 836 837 BOOL WINAPI PathResolveA(LPSTR path, LPCSTR *dirs, DWORD flags) 838 { 839 BOOL ret = FALSE; 840 LPWSTR *dirsW = NULL; 841 DWORD iDir, cDirs, cbDirs; 842 WCHAR pathW[MAX_PATH]; 843 844 TRACE("(%s,%p,0x%08x)\n", debugstr_a(path), dirs, flags); 845 846 if (dirs) 847 { 848 for (cDirs = 0; dirs[cDirs]; ++cDirs) 849 ; 850 851 cbDirs = (cDirs + 1) * sizeof(LPWSTR); 852 dirsW = SHAlloc(cbDirs); 853 if (!dirsW) 854 goto Cleanup; 855 856 ZeroMemory(dirsW, cbDirs); 857 for (iDir = 0; iDir < cDirs; ++iDir) 858 { 859 __SHCloneStrAtoW(&dirsW[iDir], dirs[iDir]); 860 if (dirsW[iDir] == NULL) 861 goto Cleanup; 862 } 863 } 864 865 SHAnsiToUnicode(path, pathW, _countof(pathW)); 866 867 ret = PathResolveW(pathW, (LPCWSTR*)dirsW, flags); 868 if (ret) 869 SHUnicodeToAnsi(pathW, path, MAX_PATH); 870 871 Cleanup: 872 if (dirsW) 873 { 874 for (iDir = 0; iDir < cDirs; ++iDir) 875 { 876 SHFree(dirsW[iDir]); 877 } 878 SHFree(dirsW); 879 } 880 return ret; 881 } 882 883 BOOL WINAPI PathResolveW(_Inout_ LPWSTR path, _Inout_opt_ LPCWSTR *dirs, _In_ DWORD flags) 884 { 885 DWORD dwWhich = WHICH_DEFAULT; /* The extensions to be searched */ 886 887 TRACE("(%s,%p,0x%08x)\n", debugstr_w(path), dirs, flags); 888 889 if (flags & PRF_DONTFINDLNK) 890 dwWhich &= ~WHICH_LNK; /* Don't search '.LNK' (shortcut) */ 891 892 if (flags & PRF_VERIFYEXISTS) 893 SetLastError(ERROR_FILE_NOT_FOUND); /* We set this error code at first in verification */ 894 895 PathUnquoteSpacesW(path); 896 897 if (PathIsRootW(path)) /* Root path */ 898 { 899 if (path[0] == L'\\' && path[1] == UNICODE_NULL) /* '\' only? */ 900 PathQualifyExW(path, ((flags & PRF_FIRSTDIRDEF) ? *dirs : NULL), 0); /* Qualify */ 901 902 if (flags & PRF_VERIFYEXISTS) 903 return PathFileExistsAndAttributesW(path, NULL); /* Check the existence */ 904 905 return TRUE; 906 } 907 908 if (PathIsFileSpecW(path)) /* Filename only */ 909 { 910 /* Try to find the path with program extensions applied? */ 911 if ((flags & PRF_TRYPROGRAMEXTENSIONS) && 912 PathSearchOnExtensionsW(path, dirs, TRUE, dwWhich)) 913 { 914 return TRUE; /* Found */ 915 } 916 917 /* Try to find the filename in the directories */ 918 if (PathFindOnPathW(path, dirs)) 919 goto CheckAbsoluteAndFinish; 920 921 return FALSE; /* Not found */ 922 } 923 924 if (PathIsURLW(path)) /* URL? */ 925 return FALSE; 926 927 /* Qualify the path */ 928 PathQualifyExW(path, ((flags & PRF_FIRSTDIRDEF) ? *dirs : NULL), 1); 929 930 TRACE("(%s)\n", debugstr_w(path)); 931 932 if (!(flags & PRF_VERIFYEXISTS)) /* Don't verify the existence? */ 933 return TRUE; 934 935 /* Try to find the path with program extensions applied? */ 936 if (!(flags & PRF_TRYPROGRAMEXTENSIONS) || 937 !PathSearchOnExtensionsW(path, dirs, FALSE, dwWhich)) 938 { 939 if (!PathFileExistsAndAttributesW(path, NULL)) 940 return FALSE; /* Not found */ 941 } 942 943 CheckAbsoluteAndFinish: 944 #if (_WIN32_WINNT >= _WIN32_WINNT_WS03) 945 if (!(flags & PRF_REQUIREABSOLUTE) || PathIsAbsoluteW(path)) 946 return TRUE; 947 948 if (!PathMakeAbsoluteW(path)) 949 return FALSE; 950 951 return PathFileExistsAndAttributesW(path, NULL); 952 #else 953 return TRUE; /* Found */ 954 #endif 955 } 956 957 /************************************************************************* 958 * PathResolve [SHELL32.51] 959 */ 960 BOOL WINAPI PathResolveAW(LPVOID path, LPCVOID *paths, DWORD flags) 961 { 962 if (SHELL_OsIsUnicode()) 963 return PathResolveW(path, (LPCWSTR*)paths, flags); 964 else 965 return PathResolveA(path, (LPCSTR*)paths, flags); 966 } 967 968 /************************************************************************* 969 * PathProcessCommandA 970 */ 971 static LONG PathProcessCommandA ( 972 LPCSTR lpszPath, 973 LPSTR lpszBuff, 974 DWORD dwBuffSize, 975 DWORD dwFlags) 976 { 977 FIXME("%s %p 0x%04x 0x%04x stub\n", 978 lpszPath, lpszBuff, dwBuffSize, dwFlags); 979 if(!lpszPath) return -1; 980 if(lpszBuff) strcpy(lpszBuff, lpszPath); 981 return strlen(lpszPath); 982 } 983 984 /************************************************************************* 985 * PathProcessCommandW 986 */ 987 static LONG PathProcessCommandW ( 988 LPCWSTR lpszPath, 989 LPWSTR lpszBuff, 990 DWORD dwBuffSize, 991 DWORD dwFlags) 992 { 993 FIXME("(%s, %p, 0x%04x, 0x%04x) stub\n", 994 debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags); 995 if(!lpszPath) return -1; 996 if(lpszBuff) strcpyW(lpszBuff, lpszPath); 997 return strlenW(lpszPath); 998 } 999 1000 /************************************************************************* 1001 * PathProcessCommand (SHELL32.653) 1002 */ 1003 LONG WINAPI PathProcessCommandAW ( 1004 LPCVOID lpszPath, 1005 LPVOID lpszBuff, 1006 DWORD dwBuffSize, 1007 DWORD dwFlags) 1008 { 1009 if (SHELL_OsIsUnicode()) 1010 return PathProcessCommandW(lpszPath, lpszBuff, dwBuffSize, dwFlags); 1011 return PathProcessCommandA(lpszPath, lpszBuff, dwBuffSize, dwFlags); 1012 } 1013 1014 /* 1015 ########## special ########## 1016 */ 1017 1018 /* !! MISSING Win2k3-compatible paths from the list below; absent from Wine !! */ 1019 #ifndef __REACTOS__ 1020 static const WCHAR Application_DataW[] = L"Application Data"; 1021 static const WCHAR Local_Settings_Application_DataW[] = L"Local Settings\\Application Data"; 1022 static const WCHAR Local_Settings_HistoryW[] = L"Local Settings\\History"; 1023 static const WCHAR Local_Settings_Temporary_Internet_FilesW[] = L"Local Settings\\Temporary Internet Files"; 1024 static const WCHAR MusicW[] = L"Music"; 1025 static const WCHAR PicturesW[] = L"Pictures"; 1026 static const WCHAR Program_FilesW[] = L"Program Files"; 1027 static const WCHAR Program_Files_Common_FilesW[] = L"Program Files\\Common Files"; 1028 static const WCHAR Start_Menu_ProgramsW[] = L"Start Menu\\Programs"; 1029 static const WCHAR Start_Menu_Admin_ToolsW[] = L"Start Menu\\Programs\\Administrative Tools"; 1030 static const WCHAR Start_Menu_StartupW[] = L"Start Menu\\Programs\\StartUp"; 1031 #endif 1032 1033 /* Long strings that are repeated many times: keep them here */ 1034 static const WCHAR szSHFolders[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"; 1035 static const WCHAR szSHUserFolders[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders"; 1036 #ifndef __REACTOS__ 1037 static const WCHAR szKnownFolderDescriptions[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FolderDescriptions"; 1038 static const WCHAR szKnownFolderRedirections[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders"; 1039 #endif 1040 1041 typedef enum _CSIDL_Type { 1042 CSIDL_Type_User, 1043 #ifdef __REACTOS__ 1044 CSIDL_Type_InMyDocuments, 1045 #endif 1046 CSIDL_Type_AllUsers, 1047 CSIDL_Type_CurrVer, 1048 CSIDL_Type_Disallowed, 1049 CSIDL_Type_NonExistent, 1050 CSIDL_Type_WindowsPath, 1051 CSIDL_Type_SystemPath, 1052 CSIDL_Type_SystemX86Path, 1053 } CSIDL_Type; 1054 1055 /* Cannot use #if _WIN32_WINNT >= 0x0600 because _WIN32_WINNT == 0x0600 here. */ 1056 #ifndef __REACTOS__ 1057 #define CSIDL_CONTACTS 0x0043 1058 #define CSIDL_DOWNLOADS 0x0047 1059 #define CSIDL_LINKS 0x004d 1060 #define CSIDL_APPDATA_LOCALLOW 0x004e 1061 #define CSIDL_SAVED_GAMES 0x0062 1062 #define CSIDL_SEARCHES 0x0063 1063 #endif 1064 1065 typedef struct 1066 { 1067 const KNOWNFOLDERID *id; 1068 CSIDL_Type type; 1069 LPCWSTR szValueName; 1070 LPCWSTR szDefaultPath; /* fallback string or resource ID */ 1071 INT nShell32IconIndex; 1072 } CSIDL_DATA; 1073 1074 static const CSIDL_DATA CSIDL_Data[] = 1075 { 1076 { /* 0x00 - CSIDL_DESKTOP */ 1077 &FOLDERID_Desktop, 1078 CSIDL_Type_User, 1079 L"Desktop", 1080 MAKEINTRESOURCEW(IDS_DESKTOPDIRECTORY), 1081 #ifdef __REACTOS__ 1082 0 1083 #else 1084 -IDI_SHELL_DESKTOP 1085 #endif 1086 }, 1087 { /* 0x01 - CSIDL_INTERNET */ 1088 &FOLDERID_InternetFolder, 1089 CSIDL_Type_Disallowed, 1090 NULL, 1091 NULL 1092 }, 1093 { /* 0x02 - CSIDL_PROGRAMS */ 1094 &FOLDERID_Programs, 1095 CSIDL_Type_User, 1096 L"Programs", 1097 MAKEINTRESOURCEW(IDS_PROGRAMS), 1098 #ifdef __REACTOS__ 1099 0 1100 #else 1101 -IDI_SHELL_PROGRAMS_FOLDER 1102 #endif 1103 }, 1104 { /* 0x03 - CSIDL_CONTROLS (.CPL files) */ 1105 &FOLDERID_ControlPanelFolder, 1106 CSIDL_Type_SystemPath, 1107 L"ControlPanelFolder", 1108 NULL, 1109 -IDI_SHELL_CONTROL_PANEL 1110 }, 1111 { /* 0x04 - CSIDL_PRINTERS */ 1112 &FOLDERID_PrintersFolder, 1113 CSIDL_Type_SystemPath, 1114 L"PrintersFolder", 1115 NULL, 1116 -IDI_SHELL_PRINTERS_FOLDER 1117 }, 1118 { /* 0x05 - CSIDL_PERSONAL */ 1119 &FOLDERID_Documents, 1120 CSIDL_Type_User, 1121 L"Personal", 1122 MAKEINTRESOURCEW(IDS_PERSONAL), 1123 -IDI_SHELL_MY_DOCUMENTS 1124 }, 1125 { /* 0x06 - CSIDL_FAVORITES */ 1126 &FOLDERID_Favorites, 1127 CSIDL_Type_User, 1128 L"Favorites", 1129 MAKEINTRESOURCEW(IDS_FAVORITES), 1130 -IDI_SHELL_FAVORITES 1131 }, 1132 { /* 0x07 - CSIDL_STARTUP */ 1133 &FOLDERID_Startup, 1134 CSIDL_Type_User, 1135 L"StartUp", 1136 MAKEINTRESOURCEW(IDS_STARTUP) 1137 }, 1138 { /* 0x08 - CSIDL_RECENT */ 1139 &FOLDERID_Recent, 1140 CSIDL_Type_User, 1141 L"Recent", 1142 MAKEINTRESOURCEW(IDS_RECENT), 1143 -IDI_SHELL_RECENT_DOCUMENTS 1144 }, 1145 { /* 0x09 - CSIDL_SENDTO */ 1146 &FOLDERID_SendTo, 1147 CSIDL_Type_User, 1148 L"SendTo", 1149 MAKEINTRESOURCEW(IDS_SENDTO) 1150 }, 1151 { /* 0x0a - CSIDL_BITBUCKET - Recycle Bin */ 1152 &FOLDERID_RecycleBinFolder, 1153 CSIDL_Type_Disallowed, 1154 L"RecycleBinFolder", 1155 NULL 1156 }, 1157 { /* 0x0b - CSIDL_STARTMENU */ 1158 &FOLDERID_StartMenu, 1159 CSIDL_Type_User, 1160 L"Start Menu", 1161 MAKEINTRESOURCEW(IDS_STARTMENU), 1162 -IDI_SHELL_TSKBAR_STARTMENU 1163 }, 1164 { /* 0x0c - CSIDL_MYDOCUMENTS */ 1165 &GUID_NULL, 1166 CSIDL_Type_Disallowed, /* matches WinXP--can't get its path */ 1167 NULL, 1168 NULL, 1169 -IDI_SHELL_MY_DOCUMENTS 1170 }, 1171 { /* 0x0d - CSIDL_MYMUSIC */ 1172 &FOLDERID_Music, 1173 #ifdef __REACTOS__ 1174 CSIDL_Type_InMyDocuments, 1175 #else 1176 CSIDL_Type_User, 1177 #endif 1178 L"My Music", 1179 MAKEINTRESOURCEW(IDS_MYMUSIC), 1180 -IDI_SHELL_MY_MUSIC 1181 }, 1182 { /* 0x0e - CSIDL_MYVIDEO */ 1183 &FOLDERID_Videos, 1184 #ifdef __REACTOS__ 1185 CSIDL_Type_InMyDocuments, 1186 #else 1187 CSIDL_Type_User, 1188 #endif 1189 L"My Video", 1190 MAKEINTRESOURCEW(IDS_MYVIDEO), 1191 -IDI_SHELL_MY_MOVIES 1192 }, 1193 { /* 0x0f - unassigned */ 1194 &GUID_NULL, 1195 CSIDL_Type_Disallowed, 1196 NULL, 1197 NULL, 1198 }, 1199 { /* 0x10 - CSIDL_DESKTOPDIRECTORY */ 1200 &FOLDERID_Desktop, 1201 CSIDL_Type_User, 1202 L"Desktop", 1203 MAKEINTRESOURCEW(IDS_DESKTOPDIRECTORY), 1204 #ifdef __REACTOS__ 1205 0 1206 #else 1207 -IDI_SHELL_DESKTOP 1208 #endif 1209 }, 1210 { /* 0x11 - CSIDL_DRIVES */ 1211 &FOLDERID_ComputerFolder, 1212 CSIDL_Type_Disallowed, 1213 L"MyComputerFolder", 1214 NULL, 1215 -IDI_SHELL_COMPUTER_FOLDER 1216 }, 1217 { /* 0x12 - CSIDL_NETWORK */ 1218 &FOLDERID_NetworkFolder, 1219 CSIDL_Type_Disallowed, 1220 L"NetworkPlacesFolder", 1221 NULL, 1222 -IDI_SHELL_NETWORK_FOLDER 1223 }, 1224 { /* 0x13 - CSIDL_NETHOOD */ 1225 &FOLDERID_NetHood, 1226 CSIDL_Type_User, 1227 L"NetHood", 1228 MAKEINTRESOURCEW(IDS_NETHOOD), 1229 -IDI_SHELL_NETWORK 1230 }, 1231 { /* 0x14 - CSIDL_FONTS */ 1232 &FOLDERID_Fonts, 1233 CSIDL_Type_WindowsPath, 1234 L"Fonts", 1235 L"Fonts", 1236 -IDI_SHELL_FONTS_FOLDER 1237 }, 1238 { /* 0x15 - CSIDL_TEMPLATES */ 1239 &FOLDERID_Templates, 1240 CSIDL_Type_User, 1241 L"Templates", 1242 MAKEINTRESOURCEW(IDS_TEMPLATES) 1243 }, 1244 { /* 0x16 - CSIDL_COMMON_STARTMENU */ 1245 &FOLDERID_CommonStartMenu, 1246 CSIDL_Type_AllUsers, 1247 L"Common Start Menu", 1248 MAKEINTRESOURCEW(IDS_STARTMENU), 1249 -IDI_SHELL_TSKBAR_STARTMENU 1250 }, 1251 { /* 0x17 - CSIDL_COMMON_PROGRAMS */ 1252 &FOLDERID_CommonPrograms, 1253 CSIDL_Type_AllUsers, 1254 L"Common Programs", 1255 MAKEINTRESOURCEW(IDS_PROGRAMS), 1256 #ifdef __REACTOS__ 1257 0 1258 #else 1259 -IDI_SHELL_PROGRAMS_FOLDER 1260 #endif 1261 }, 1262 { /* 0x18 - CSIDL_COMMON_STARTUP */ 1263 &FOLDERID_CommonStartup, 1264 CSIDL_Type_AllUsers, 1265 L"Common StartUp", 1266 MAKEINTRESOURCEW(IDS_STARTUP) 1267 }, 1268 { /* 0x19 - CSIDL_COMMON_DESKTOPDIRECTORY */ 1269 &FOLDERID_PublicDesktop, 1270 CSIDL_Type_AllUsers, 1271 L"Common Desktop", 1272 MAKEINTRESOURCEW(IDS_DESKTOPDIRECTORY), 1273 #ifdef __REACTOS__ 1274 0 1275 #else 1276 -IDI_SHELL_DESKTOP 1277 #endif 1278 }, 1279 { /* 0x1a - CSIDL_APPDATA */ 1280 &FOLDERID_RoamingAppData, 1281 CSIDL_Type_User, 1282 L"AppData", 1283 MAKEINTRESOURCEW(IDS_APPDATA) 1284 }, 1285 { /* 0x1b - CSIDL_PRINTHOOD */ 1286 &FOLDERID_PrintHood, 1287 CSIDL_Type_User, 1288 L"PrintHood", 1289 MAKEINTRESOURCEW(IDS_PRINTHOOD), 1290 -IDI_SHELL_PRINTERS_FOLDER 1291 }, 1292 { /* 0x1c - CSIDL_LOCAL_APPDATA */ 1293 &FOLDERID_LocalAppData, 1294 CSIDL_Type_User, 1295 L"Local AppData", 1296 MAKEINTRESOURCEW(IDS_LOCAL_APPDATA) 1297 }, 1298 { /* 0x1d - CSIDL_ALTSTARTUP */ 1299 &GUID_NULL, 1300 CSIDL_Type_NonExistent, 1301 NULL, 1302 NULL 1303 }, 1304 { /* 0x1e - CSIDL_COMMON_ALTSTARTUP */ 1305 &GUID_NULL, 1306 CSIDL_Type_NonExistent, 1307 NULL, 1308 NULL 1309 }, 1310 { /* 0x1f - CSIDL_COMMON_FAVORITES */ 1311 &FOLDERID_Favorites, 1312 CSIDL_Type_AllUsers, 1313 L"Common Favorites", 1314 MAKEINTRESOURCEW(IDS_FAVORITES), 1315 -IDI_SHELL_FAVORITES 1316 }, 1317 { /* 0x20 - CSIDL_INTERNET_CACHE */ 1318 &FOLDERID_InternetCache, 1319 CSIDL_Type_User, 1320 L"Cache", 1321 MAKEINTRESOURCEW(IDS_INTERNET_CACHE) 1322 }, 1323 { /* 0x21 - CSIDL_COOKIES */ 1324 &FOLDERID_Cookies, 1325 CSIDL_Type_User, 1326 L"Cookies", 1327 MAKEINTRESOURCEW(IDS_COOKIES) 1328 }, 1329 { /* 0x22 - CSIDL_HISTORY */ 1330 &FOLDERID_History, 1331 CSIDL_Type_User, 1332 L"History", 1333 MAKEINTRESOURCEW(IDS_HISTORY) 1334 }, 1335 { /* 0x23 - CSIDL_COMMON_APPDATA */ 1336 &FOLDERID_ProgramData, 1337 CSIDL_Type_AllUsers, 1338 L"Common AppData", 1339 MAKEINTRESOURCEW(IDS_APPDATA) 1340 }, 1341 { /* 0x24 - CSIDL_WINDOWS */ 1342 &FOLDERID_Windows, 1343 CSIDL_Type_WindowsPath, 1344 L"Windows", 1345 NULL, 1346 -IDI_SHELL_SYSTEM_GEAR 1347 }, 1348 { /* 0x25 - CSIDL_SYSTEM */ 1349 &FOLDERID_System, 1350 CSIDL_Type_SystemPath, 1351 L"System", 1352 NULL, 1353 -IDI_SHELL_SYSTEM_GEAR 1354 }, 1355 { /* 0x26 - CSIDL_PROGRAM_FILES */ 1356 &FOLDERID_ProgramFiles, 1357 CSIDL_Type_CurrVer, 1358 L"ProgramFiles", 1359 MAKEINTRESOURCEW(IDS_PROGRAM_FILES), 1360 #ifdef __REACTOS__ 1361 0 1362 #else 1363 -IDI_SHELL_PROGRAMS_FOLDER 1364 #endif 1365 }, 1366 { /* 0x27 - CSIDL_MYPICTURES */ 1367 &FOLDERID_Pictures, 1368 #ifdef __REACTOS__ 1369 CSIDL_Type_InMyDocuments, 1370 #else 1371 CSIDL_Type_User, 1372 #endif 1373 L"My Pictures", 1374 MAKEINTRESOURCEW(IDS_MYPICTURES), 1375 -IDI_SHELL_MY_PICTURES 1376 }, 1377 { /* 0x28 - CSIDL_PROFILE */ 1378 &FOLDERID_Profile, 1379 CSIDL_Type_User, 1380 NULL, 1381 NULL 1382 }, 1383 { /* 0x29 - CSIDL_SYSTEMX86 */ 1384 &FOLDERID_SystemX86, 1385 CSIDL_Type_SystemX86Path, 1386 NULL, 1387 NULL, 1388 -IDI_SHELL_SYSTEM_GEAR 1389 }, 1390 { /* 0x2a - CSIDL_PROGRAM_FILESX86 */ 1391 &FOLDERID_ProgramFilesX86, 1392 CSIDL_Type_CurrVer, 1393 L"ProgramFilesX86", 1394 L"Program Files (x86)", 1395 -IDI_SHELL_PROGRAMS_FOLDER 1396 }, 1397 { /* 0x2b - CSIDL_PROGRAM_FILES_COMMON */ 1398 &FOLDERID_ProgramFilesCommon, 1399 CSIDL_Type_CurrVer, 1400 L"ProgramFilesCommon", 1401 MAKEINTRESOURCEW(IDS_PROGRAM_FILES_COMMON), 1402 -IDI_SHELL_PROGRAMS_FOLDER 1403 }, 1404 { /* 0x2c - CSIDL_PROGRAM_FILES_COMMONX86 */ 1405 &FOLDERID_ProgramFilesCommonX86, 1406 CSIDL_Type_CurrVer, 1407 L"ProgramFilesCommonX86", 1408 L"Program Files (x86)\\Common Files", 1409 -IDI_SHELL_PROGRAMS_FOLDER 1410 }, 1411 { /* 0x2d - CSIDL_COMMON_TEMPLATES */ 1412 &FOLDERID_CommonTemplates, 1413 CSIDL_Type_AllUsers, 1414 L"Common Templates", 1415 MAKEINTRESOURCEW(IDS_TEMPLATES) 1416 }, 1417 { /* 0x2e - CSIDL_COMMON_DOCUMENTS */ 1418 &FOLDERID_PublicDocuments, 1419 CSIDL_Type_AllUsers, 1420 L"Common Documents", 1421 MAKEINTRESOURCEW(IDS_PERSONAL), 1422 -IDI_SHELL_MY_DOCUMENTS 1423 }, 1424 { /* 0x2f - CSIDL_COMMON_ADMINTOOLS */ 1425 &FOLDERID_CommonAdminTools, 1426 CSIDL_Type_AllUsers, 1427 L"Common Administrative Tools", 1428 MAKEINTRESOURCEW(IDS_ADMINTOOLS) 1429 }, 1430 { /* 0x30 - CSIDL_ADMINTOOLS */ 1431 &FOLDERID_AdminTools, 1432 CSIDL_Type_User, 1433 L"Administrative Tools", 1434 MAKEINTRESOURCEW(IDS_ADMINTOOLS) 1435 }, 1436 { /* 0x31 - CSIDL_CONNECTIONS */ 1437 &FOLDERID_ConnectionsFolder, 1438 CSIDL_Type_Disallowed, 1439 L"ConnectionsFolder", 1440 NULL, 1441 -IDI_SHELL_NETWORK_CONNECTIONS 1442 }, 1443 { /* 0x32 - unassigned */ 1444 &GUID_NULL, 1445 CSIDL_Type_Disallowed, 1446 NULL, 1447 NULL 1448 }, 1449 { /* 0x33 - unassigned */ 1450 &GUID_NULL, 1451 CSIDL_Type_Disallowed, 1452 NULL, 1453 NULL 1454 }, 1455 { /* 0x34 - unassigned */ 1456 &GUID_NULL, 1457 CSIDL_Type_Disallowed, 1458 NULL, 1459 NULL 1460 }, 1461 { /* 0x35 - CSIDL_COMMON_MUSIC */ 1462 &FOLDERID_PublicMusic, 1463 CSIDL_Type_AllUsers, 1464 L"CommonMusic", 1465 MAKEINTRESOURCEW(IDS_COMMON_MUSIC), 1466 -IDI_SHELL_MY_MUSIC 1467 }, 1468 { /* 0x36 - CSIDL_COMMON_PICTURES */ 1469 &FOLDERID_PublicPictures, 1470 CSIDL_Type_AllUsers, 1471 L"CommonPictures", 1472 MAKEINTRESOURCEW(IDS_COMMON_PICTURES), 1473 -IDI_SHELL_MY_PICTURES 1474 }, 1475 { /* 0x37 - CSIDL_COMMON_VIDEO */ 1476 &FOLDERID_PublicVideos, 1477 CSIDL_Type_AllUsers, 1478 L"CommonVideo", 1479 MAKEINTRESOURCEW(IDS_COMMON_VIDEO), 1480 -IDI_SHELL_MY_MOVIES 1481 }, 1482 { /* 0x38 - CSIDL_RESOURCES */ 1483 &FOLDERID_ResourceDir, 1484 CSIDL_Type_WindowsPath, 1485 NULL, 1486 L"Resources" 1487 }, 1488 { /* 0x39 - CSIDL_RESOURCES_LOCALIZED */ 1489 &FOLDERID_LocalizedResourcesDir, 1490 CSIDL_Type_NonExistent, 1491 NULL, 1492 NULL 1493 }, 1494 { /* 0x3a - CSIDL_COMMON_OEM_LINKS */ 1495 &FOLDERID_CommonOEMLinks, 1496 CSIDL_Type_AllUsers, 1497 NULL, 1498 L"OEM Links" 1499 }, 1500 { /* 0x3b - CSIDL_CDBURN_AREA */ 1501 &FOLDERID_CDBurning, 1502 CSIDL_Type_User, 1503 L"CD Burning", 1504 L"Local Settings\\Application Data\\Microsoft\\CD Burning" 1505 }, 1506 { /* 0x3c unassigned */ 1507 &GUID_NULL, 1508 CSIDL_Type_Disallowed, 1509 NULL, 1510 NULL 1511 }, 1512 { /* 0x3d - CSIDL_COMPUTERSNEARME */ 1513 &GUID_NULL, 1514 CSIDL_Type_Disallowed, /* FIXME */ 1515 NULL, 1516 NULL 1517 }, 1518 { /* 0x3e - CSIDL_PROFILES */ 1519 &GUID_NULL, 1520 CSIDL_Type_Disallowed, /* oddly, this matches WinXP */ 1521 NULL, 1522 NULL 1523 }, 1524 /* Cannot use #if _WIN32_WINNT >= 0x0600 because _WIN32_WINNT == 0x0600 here. */ 1525 #ifndef __REACTOS__ 1526 { /* 0x3f */ 1527 &FOLDERID_AddNewPrograms, 1528 CSIDL_Type_Disallowed, 1529 NULL, 1530 NULL 1531 }, 1532 { /* 0x40 */ 1533 &FOLDERID_AppUpdates, 1534 CSIDL_Type_Disallowed, 1535 NULL, 1536 NULL 1537 }, 1538 { /* 0x41 */ 1539 &FOLDERID_ChangeRemovePrograms, 1540 CSIDL_Type_Disallowed, 1541 NULL, 1542 NULL 1543 }, 1544 { /* 0x42 */ 1545 &FOLDERID_ConflictFolder, 1546 CSIDL_Type_Disallowed, 1547 NULL, 1548 NULL 1549 }, 1550 { /* 0x43 - CSIDL_CONTACTS */ 1551 &FOLDERID_Contacts, 1552 CSIDL_Type_User, 1553 NULL, 1554 L"Contacts" 1555 }, 1556 { /* 0x44 */ 1557 &FOLDERID_DeviceMetadataStore, 1558 CSIDL_Type_Disallowed, /* FIXME */ 1559 NULL, 1560 NULL 1561 }, 1562 { /* 0x45 */ 1563 &GUID_NULL, 1564 CSIDL_Type_User, 1565 NULL, 1566 L"Documents" 1567 }, 1568 { /* 0x46 */ 1569 &FOLDERID_DocumentsLibrary, 1570 CSIDL_Type_Disallowed, /* FIXME */ 1571 NULL, 1572 NULL 1573 }, 1574 { /* 0x47 - CSIDL_DOWNLOADS */ 1575 &FOLDERID_Downloads, 1576 #ifdef __REACTOS__ 1577 CSIDL_Type_InMyDocuments, 1578 #else 1579 CSIDL_Type_User, 1580 #endif 1581 NULL, 1582 L"Downloads" 1583 }, 1584 { /* 0x48 */ 1585 &FOLDERID_Games, 1586 CSIDL_Type_Disallowed, 1587 NULL, 1588 NULL 1589 }, 1590 { /* 0x49 */ 1591 &FOLDERID_GameTasks, 1592 CSIDL_Type_Disallowed, /* FIXME */ 1593 NULL, 1594 NULL 1595 }, 1596 { /* 0x4a */ 1597 &FOLDERID_HomeGroup, 1598 CSIDL_Type_Disallowed, 1599 NULL, 1600 NULL 1601 }, 1602 { /* 0x4b */ 1603 &FOLDERID_ImplicitAppShortcuts, 1604 CSIDL_Type_Disallowed, /* FIXME */ 1605 NULL, 1606 NULL 1607 }, 1608 { /* 0x4c */ 1609 &FOLDERID_Libraries, 1610 CSIDL_Type_Disallowed, /* FIXME */ 1611 NULL, 1612 NULL 1613 }, 1614 { /* 0x4d - CSIDL_LINKS */ 1615 &FOLDERID_Links, 1616 CSIDL_Type_User, 1617 NULL, 1618 L"Links" 1619 }, 1620 { /* 0x4e - CSIDL_APPDATA_LOCALLOW */ 1621 &FOLDERID_LocalAppDataLow, 1622 CSIDL_Type_User, 1623 NULL, 1624 L"AppData\\LocalLow" 1625 }, 1626 { /* 0x4f */ 1627 &FOLDERID_MusicLibrary, 1628 CSIDL_Type_Disallowed, /* FIXME */ 1629 NULL, 1630 NULL 1631 }, 1632 { /* 0x50 */ 1633 &FOLDERID_OriginalImages, 1634 CSIDL_Type_Disallowed, /* FIXME */ 1635 NULL, 1636 NULL 1637 }, 1638 { /* 0x51 */ 1639 &FOLDERID_PhotoAlbums, 1640 CSIDL_Type_User, 1641 NULL, 1642 L"Pictures\\Slide Shows" 1643 }, 1644 { /* 0x52 */ 1645 &FOLDERID_PicturesLibrary, 1646 CSIDL_Type_Disallowed, /* FIXME */ 1647 NULL, 1648 NULL 1649 }, 1650 { /* 0x53 */ 1651 &FOLDERID_Playlists, 1652 CSIDL_Type_User, 1653 NULL, 1654 L"Music\\Playlists" 1655 }, 1656 { /* 0x54 */ 1657 &FOLDERID_ProgramFilesX64, 1658 CSIDL_Type_NonExistent, 1659 NULL, 1660 NULL 1661 }, 1662 { /* 0x55 */ 1663 &FOLDERID_ProgramFilesCommonX64, 1664 CSIDL_Type_NonExistent, 1665 NULL, 1666 NULL 1667 }, 1668 { /* 0x56 */ 1669 &FOLDERID_Public, 1670 CSIDL_Type_CurrVer, /* FIXME */ 1671 NULL, 1672 L"Users\\Public" 1673 }, 1674 { /* 0x57 */ 1675 &FOLDERID_PublicDownloads, 1676 CSIDL_Type_AllUsers, 1677 NULL, 1678 L"Downloads" 1679 }, 1680 { /* 0x58 */ 1681 &FOLDERID_PublicGameTasks, 1682 CSIDL_Type_AllUsers, 1683 NULL, 1684 L"Microsoft\\Windows\\GameExplorer" 1685 }, 1686 { /* 0x59 */ 1687 &FOLDERID_PublicLibraries, 1688 CSIDL_Type_AllUsers, 1689 NULL, 1690 L"Microsoft\\Windows\\Libraries" 1691 }, 1692 { /* 0x5a */ 1693 &FOLDERID_PublicRingtones, 1694 CSIDL_Type_AllUsers, 1695 NULL, 1696 L"Microsoft\\Windows\\Ringtones" 1697 }, 1698 { /* 0x5b */ 1699 &FOLDERID_QuickLaunch, 1700 CSIDL_Type_Disallowed, /* FIXME */ 1701 NULL, 1702 NULL 1703 }, 1704 { /* 0x5c */ 1705 &FOLDERID_RecordedTVLibrary, 1706 CSIDL_Type_Disallowed, /* FIXME */ 1707 NULL, 1708 NULL 1709 }, 1710 { /* 0x5d */ 1711 &FOLDERID_Ringtones, 1712 CSIDL_Type_Disallowed, /* FIXME */ 1713 NULL, 1714 NULL 1715 }, 1716 { /* 0x5e */ 1717 &FOLDERID_SampleMusic, 1718 CSIDL_Type_AllUsers, 1719 NULL, 1720 L"Music\\Sample Music" 1721 }, 1722 { /* 0x5f */ 1723 &FOLDERID_SamplePictures, 1724 CSIDL_Type_AllUsers, 1725 NULL, 1726 L"Pictures\\Sample Pictures" 1727 }, 1728 { /* 0x60 */ 1729 &FOLDERID_SamplePlaylists, 1730 CSIDL_Type_AllUsers, 1731 NULL, 1732 L"Music\\Sample Playlists" 1733 }, 1734 { /* 0x61 */ 1735 &FOLDERID_SampleVideos, 1736 CSIDL_Type_AllUsers, 1737 NULL, 1738 L"Videos\\Sample Videos" 1739 }, 1740 { /* 0x62 - CSIDL_SAVED_GAMES */ 1741 &FOLDERID_SavedGames, 1742 CSIDL_Type_User, 1743 NULL, 1744 L"Saved Games" 1745 }, 1746 { /* 0x63 - CSIDL_SEARCHES */ 1747 &FOLDERID_SavedSearches, 1748 CSIDL_Type_User, 1749 NULL, 1750 L"Searches" 1751 }, 1752 { /* 0x64 */ 1753 &FOLDERID_SEARCH_CSC, 1754 CSIDL_Type_Disallowed, 1755 NULL, 1756 NULL 1757 }, 1758 { /* 0x65 */ 1759 &FOLDERID_SEARCH_MAPI, 1760 CSIDL_Type_Disallowed, 1761 NULL, 1762 NULL 1763 }, 1764 { /* 0x66 */ 1765 &FOLDERID_SearchHome, 1766 CSIDL_Type_Disallowed, 1767 NULL, 1768 NULL 1769 }, 1770 { /* 0x67 */ 1771 &FOLDERID_SidebarDefaultParts, 1772 CSIDL_Type_Disallowed, /* FIXME */ 1773 NULL, 1774 NULL 1775 }, 1776 { /* 0x68 */ 1777 &FOLDERID_SidebarParts, 1778 CSIDL_Type_Disallowed, /* FIXME */ 1779 NULL, 1780 NULL 1781 }, 1782 { /* 0x69 */ 1783 &FOLDERID_SyncManagerFolder, 1784 CSIDL_Type_Disallowed, 1785 NULL, 1786 NULL 1787 }, 1788 { /* 0x6a */ 1789 &FOLDERID_SyncResultsFolder, 1790 CSIDL_Type_Disallowed, 1791 NULL, 1792 NULL 1793 }, 1794 { /* 0x6b */ 1795 &FOLDERID_SyncSetupFolder, 1796 CSIDL_Type_Disallowed, 1797 NULL, 1798 NULL 1799 }, 1800 { /* 0x6c */ 1801 &FOLDERID_UserPinned, 1802 CSIDL_Type_Disallowed, /* FIXME */ 1803 NULL, 1804 NULL 1805 }, 1806 { /* 0x6d */ 1807 &FOLDERID_UserProfiles, 1808 CSIDL_Type_CurrVer, 1809 L"Users", 1810 L"Users" 1811 }, 1812 { /* 0x6e */ 1813 &FOLDERID_UserProgramFiles, 1814 CSIDL_Type_Disallowed, /* FIXME */ 1815 NULL, 1816 NULL 1817 }, 1818 { /* 0x6f */ 1819 &FOLDERID_UserProgramFilesCommon, 1820 CSIDL_Type_Disallowed, /* FIXME */ 1821 NULL, 1822 NULL 1823 }, 1824 { /* 0x70 */ 1825 &FOLDERID_UsersFiles, 1826 CSIDL_Type_Disallowed, 1827 NULL, 1828 NULL 1829 }, 1830 { /* 0x71 */ 1831 &FOLDERID_UsersLibraries, 1832 CSIDL_Type_Disallowed, 1833 NULL, 1834 NULL 1835 }, 1836 { /* 0x72 */ 1837 &FOLDERID_VideosLibrary, 1838 CSIDL_Type_Disallowed, /* FIXME */ 1839 NULL, 1840 NULL 1841 } 1842 #endif 1843 }; 1844 1845 INT SHGetSpecialFolderID(_In_ LPCWSTR pszName) 1846 { 1847 UINT csidl; 1848 1849 for (csidl = 0; csidl < _countof(CSIDL_Data); ++csidl) 1850 { 1851 const CSIDL_DATA *pData = &CSIDL_Data[csidl]; 1852 if (pData->szValueName && lstrcmpiW(pszName, pData->szValueName) == 0) 1853 return csidl; 1854 } 1855 1856 return -1; 1857 } 1858 1859 INT Shell_ParseSpecialFolder(_In_ LPCWSTR pszStart, _Out_ LPWSTR *ppch, _Out_ INT *pcch) 1860 { 1861 LPCWSTR pszPath, pchBackslash; 1862 WCHAR szPath[MAX_PATH]; 1863 1864 pchBackslash = StrChrW(pszStart, L'\\'); 1865 if (pchBackslash) 1866 { 1867 *ppch = (LPWSTR)(pchBackslash + 1); 1868 *pcch = (pchBackslash - pszStart) + 1; 1869 StrCpyNW(szPath, pszStart, min(*pcch, _countof(szPath))); 1870 pszPath = szPath; 1871 } 1872 else 1873 { 1874 *ppch = NULL; 1875 *pcch = lstrlenW(pszStart); 1876 pszPath = pszStart; 1877 } 1878 1879 return SHGetSpecialFolderID(pszPath); 1880 } 1881 1882 #ifndef __REACTOS__ 1883 static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest); 1884 #else 1885 static HRESULT _SHExpandEnvironmentStrings(HANDLE hToken, LPCWSTR szSrc, LPWSTR szDest, DWORD cchDest); 1886 #endif 1887 1888 /* Gets the value named value from the registry key 1889 * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders 1890 * (or from rootKey\userPrefix\... if userPrefix is not NULL) into path, which 1891 * is assumed to be MAX_PATH WCHARs in length. 1892 * If it exists, expands the value and writes the expanded value to 1893 * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders 1894 * Returns successful error code if the value was retrieved from the registry, 1895 * and a failure otherwise. 1896 */ 1897 #ifndef __REACTOS__ 1898 static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix, 1899 #else 1900 static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, HANDLE hToken, LPCWSTR userPrefix, 1901 #endif 1902 LPCWSTR value, LPWSTR path) 1903 { 1904 HRESULT hr; 1905 WCHAR shellFolderPath[MAX_PATH], userShellFolderPath[MAX_PATH]; 1906 LPCWSTR pShellFolderPath, pUserShellFolderPath; 1907 HKEY userShellFolderKey, shellFolderKey; 1908 DWORD dwType, dwPathLen; 1909 1910 TRACE("%p,%s,%s,%p\n",rootKey, debugstr_w(userPrefix), debugstr_w(value), 1911 path); 1912 1913 if (userPrefix) 1914 { 1915 strcpyW(shellFolderPath, userPrefix); 1916 PathAddBackslashW(shellFolderPath); 1917 strcatW(shellFolderPath, szSHFolders); 1918 pShellFolderPath = shellFolderPath; 1919 strcpyW(userShellFolderPath, userPrefix); 1920 PathAddBackslashW(userShellFolderPath); 1921 strcatW(userShellFolderPath, szSHUserFolders); 1922 pUserShellFolderPath = userShellFolderPath; 1923 } 1924 else 1925 { 1926 pUserShellFolderPath = szSHUserFolders; 1927 pShellFolderPath = szSHFolders; 1928 } 1929 1930 if (RegCreateKeyW(rootKey, pShellFolderPath, &shellFolderKey)) 1931 { 1932 TRACE("Failed to create %s\n", debugstr_w(pShellFolderPath)); 1933 return E_FAIL; 1934 } 1935 if (RegCreateKeyW(rootKey, pUserShellFolderPath, &userShellFolderKey)) 1936 { 1937 TRACE("Failed to create %s\n", 1938 debugstr_w(pUserShellFolderPath)); 1939 RegCloseKey(shellFolderKey); 1940 return E_FAIL; 1941 } 1942 1943 dwPathLen = MAX_PATH * sizeof(WCHAR); 1944 if (!RegQueryValueExW(userShellFolderKey, value, NULL, &dwType, 1945 (LPBYTE)path, &dwPathLen) && (dwType == REG_EXPAND_SZ || dwType == REG_SZ)) 1946 { 1947 LONG ret; 1948 1949 path[dwPathLen / sizeof(WCHAR)] = '\0'; 1950 if (dwType == REG_EXPAND_SZ && path[0] == '%') 1951 { 1952 WCHAR szTemp[MAX_PATH]; 1953 1954 #ifndef __REACTOS__ 1955 _SHExpandEnvironmentStrings(path, szTemp); 1956 #else 1957 hr = _SHExpandEnvironmentStrings(hToken, path, szTemp, _countof(szTemp)); 1958 if (FAILED(hr)) 1959 goto end; 1960 #endif 1961 lstrcpynW(path, szTemp, MAX_PATH); 1962 } 1963 ret = RegSetValueExW(shellFolderKey, value, 0, REG_SZ, (LPBYTE)path, 1964 (strlenW(path) + 1) * sizeof(WCHAR)); 1965 if (ret != ERROR_SUCCESS) 1966 hr = HRESULT_FROM_WIN32(ret); 1967 else 1968 hr = S_OK; 1969 } 1970 else 1971 hr = E_FAIL; 1972 #ifdef __REACTOS__ 1973 end: 1974 #endif 1975 RegCloseKey(shellFolderKey); 1976 RegCloseKey(userShellFolderKey); 1977 TRACE("returning 0x%08x\n", hr); 1978 return hr; 1979 } 1980 1981 BOOL _SHGetUserProfileDirectoryW(HANDLE hToken, LPWSTR szPath, LPDWORD lpcchPath) 1982 { 1983 BOOL result; 1984 if (!hToken) 1985 { 1986 OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken); 1987 result = GetUserProfileDirectoryW(hToken, szPath, lpcchPath); 1988 CloseHandle(hToken); 1989 } 1990 else if ((INT) hToken == -1) 1991 { 1992 result = GetDefaultUserProfileDirectoryW(szPath, lpcchPath); 1993 } 1994 else 1995 { 1996 result = GetUserProfileDirectoryW(hToken, szPath, lpcchPath); 1997 } 1998 TRACE("_SHGetUserProfileDirectoryW returning %S\n", szPath); 1999 return result; 2000 } 2001 2002 /* Gets a 'semi-expanded' default value of the CSIDL with index folder into 2003 * pszPath, based on the entries in CSIDL_Data. By semi-expanded, I mean: 2004 * - The entry's szDefaultPath may be either a string value or an integer 2005 * resource identifier. In the latter case, the string value of the resource 2006 * is written. 2007 * - Depending on the entry's type, the path may begin with an (unexpanded) 2008 * environment variable name. The caller is responsible for expanding 2009 * environment strings if so desired. 2010 * The types that are prepended with environment variables are: 2011 * CSIDL_Type_User: %USERPROFILE% 2012 * CSIDL_Type_AllUsers: %ALLUSERSPROFILE% 2013 * CSIDL_Type_CurrVer: %SystemDrive% 2014 * (Others might make sense too, but as yet are unneeded.) 2015 */ 2016 #ifndef __REACTOS__ 2017 static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath) 2018 #else 2019 static HRESULT _SHGetDefaultValue(HANDLE hToken, BYTE folder, LPWSTR pszPath) 2020 #endif 2021 { 2022 HRESULT hr; 2023 WCHAR resourcePath[MAX_PATH]; 2024 #ifdef __REACTOS__ 2025 NT_PRODUCT_TYPE ProductType; 2026 #endif 2027 2028 TRACE("0x%02x,%p\n", folder, pszPath); 2029 2030 if (folder >= ARRAY_SIZE(CSIDL_Data)) 2031 return E_INVALIDARG; 2032 2033 if (!pszPath) 2034 return E_INVALIDARG; 2035 2036 #ifdef __REACTOS__ 2037 if (hToken != NULL && hToken != (HANDLE)-1) 2038 { 2039 FIXME("unsupported for user other than current or default\n"); 2040 } 2041 #endif 2042 2043 if (!is_win64) 2044 { 2045 BOOL is_wow64; 2046 2047 switch (folder) 2048 { 2049 case CSIDL_PROGRAM_FILES: 2050 case CSIDL_PROGRAM_FILESX86: 2051 IsWow64Process( GetCurrentProcess(), &is_wow64 ); 2052 folder = is_wow64 ? CSIDL_PROGRAM_FILESX86 : CSIDL_PROGRAM_FILES; 2053 break; 2054 case CSIDL_PROGRAM_FILES_COMMON: 2055 case CSIDL_PROGRAM_FILES_COMMONX86: 2056 IsWow64Process( GetCurrentProcess(), &is_wow64 ); 2057 folder = is_wow64 ? CSIDL_PROGRAM_FILES_COMMONX86 : CSIDL_PROGRAM_FILES_COMMON; 2058 break; 2059 } 2060 } 2061 2062 switch (CSIDL_Data[folder].type) 2063 { 2064 case CSIDL_Type_User: 2065 strcpyW(pszPath, L"%USERPROFILE%"); 2066 break; 2067 #ifdef __REACTOS__ 2068 case CSIDL_Type_InMyDocuments: 2069 strcpyW(pszPath, L"%USERPROFILE%"); 2070 if (DoGetProductType(&ProductType) && ProductType == NtProductWinNt) 2071 { 2072 if (IS_INTRESOURCE(CSIDL_Data[CSIDL_MYDOCUMENTS].szDefaultPath)) 2073 { 2074 WCHAR szItem[MAX_PATH]; 2075 LoadStringW(shell32_hInstance, 2076 LOWORD(CSIDL_Data[CSIDL_MYDOCUMENTS].szDefaultPath), 2077 szItem, ARRAY_SIZE(szItem)); 2078 PathAppendW(pszPath, szItem); 2079 } 2080 else 2081 { 2082 PathAppendW(pszPath, CSIDL_Data[CSIDL_MYDOCUMENTS].szDefaultPath); 2083 } 2084 } 2085 break; 2086 #endif 2087 case CSIDL_Type_AllUsers: 2088 #ifndef __REACTOS__ 2089 strcpyW(pszPath, L"%PUBLIC%"); 2090 #else 2091 strcpyW(pszPath, L"%ALLUSERSPROFILE%"); 2092 #endif 2093 break; 2094 case CSIDL_Type_CurrVer: 2095 strcpyW(pszPath, L"%SystemDrive%"); 2096 break; 2097 default: 2098 ; /* no corresponding env. var, do nothing */ 2099 } 2100 2101 hr = S_OK; 2102 if (CSIDL_Data[folder].szDefaultPath) 2103 { 2104 if (IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath)) 2105 { 2106 if (LoadStringW(shell32_hInstance, 2107 LOWORD(CSIDL_Data[folder].szDefaultPath), resourcePath, MAX_PATH)) 2108 { 2109 PathAppendW(pszPath, resourcePath); 2110 } 2111 else 2112 { 2113 ERR("(%d,%s), LoadString failed, missing translation?\n", folder, 2114 debugstr_w(pszPath)); 2115 hr = E_FAIL; 2116 } 2117 } 2118 else 2119 { 2120 PathAppendW(pszPath, CSIDL_Data[folder].szDefaultPath); 2121 } 2122 } 2123 TRACE("returning 0x%08x\n", hr); 2124 return hr; 2125 } 2126 2127 /* Gets the (unexpanded) value of the folder with index folder into pszPath. 2128 * The folder's type is assumed to be CSIDL_Type_CurrVer. Its default value 2129 * can be overridden in the HKLM\\Software\\Microsoft\\Windows\\CurrentVersion key. 2130 * If dwFlags has SHGFP_TYPE_DEFAULT set or if the value isn't overridden in 2131 * the registry, uses _SHGetDefaultValue to get the value. 2132 */ 2133 static HRESULT _SHGetCurrentVersionPath(DWORD dwFlags, BYTE folder, 2134 LPWSTR pszPath) 2135 { 2136 HRESULT hr; 2137 2138 TRACE("0x%08x,0x%02x,%p\n", dwFlags, folder, pszPath); 2139 2140 if (folder >= ARRAY_SIZE(CSIDL_Data)) 2141 return E_INVALIDARG; 2142 if (CSIDL_Data[folder].type != CSIDL_Type_CurrVer) 2143 return E_INVALIDARG; 2144 if (!pszPath) 2145 return E_INVALIDARG; 2146 2147 if (dwFlags & SHGFP_TYPE_DEFAULT) 2148 #ifndef __REACTOS__ 2149 hr = _SHGetDefaultValue(folder, pszPath); 2150 #else 2151 hr = _SHGetDefaultValue(NULL, folder, pszPath); 2152 #endif 2153 else 2154 { 2155 HKEY hKey; 2156 2157 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", &hKey)) 2158 hr = E_FAIL; 2159 else 2160 { 2161 DWORD dwType, dwPathLen = MAX_PATH * sizeof(WCHAR); 2162 2163 if (RegQueryValueExW(hKey, CSIDL_Data[folder].szValueName, NULL, 2164 &dwType, (LPBYTE)pszPath, &dwPathLen) || 2165 (dwType != REG_SZ && dwType != REG_EXPAND_SZ)) 2166 { 2167 #ifndef __REACTOS__ 2168 hr = _SHGetDefaultValue(folder, pszPath); 2169 #else 2170 hr = _SHGetDefaultValue(NULL, folder, pszPath); 2171 #endif 2172 dwType = REG_EXPAND_SZ; 2173 switch (folder) 2174 { 2175 case CSIDL_PROGRAM_FILESX86: 2176 case CSIDL_PROGRAM_FILES_COMMONX86: 2177 /* these two should never be set on 32-bit setups */ 2178 if (!is_win64) 2179 { 2180 BOOL is_wow64; 2181 IsWow64Process( GetCurrentProcess(), &is_wow64 ); 2182 if (!is_wow64) break; 2183 } 2184 /* fall through */ 2185 default: 2186 RegSetValueExW(hKey, CSIDL_Data[folder].szValueName, 0, dwType, 2187 (LPBYTE)pszPath, (strlenW(pszPath)+1)*sizeof(WCHAR)); 2188 } 2189 } 2190 else 2191 { 2192 pszPath[dwPathLen / sizeof(WCHAR)] = '\0'; 2193 hr = S_OK; 2194 } 2195 RegCloseKey(hKey); 2196 } 2197 } 2198 TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath)); 2199 return hr; 2200 } 2201 2202 static LPWSTR _GetUserSidStringFromToken(HANDLE Token) 2203 { 2204 char InfoBuffer[64]; 2205 PTOKEN_USER UserInfo; 2206 DWORD InfoSize; 2207 LPWSTR SidStr; 2208 2209 UserInfo = (PTOKEN_USER) InfoBuffer; 2210 if (! GetTokenInformation(Token, TokenUser, InfoBuffer, sizeof(InfoBuffer), 2211 &InfoSize)) 2212 { 2213 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 2214 return NULL; 2215 UserInfo = HeapAlloc(GetProcessHeap(), 0, InfoSize); 2216 if (UserInfo == NULL) 2217 return NULL; 2218 if (! GetTokenInformation(Token, TokenUser, UserInfo, InfoSize, 2219 &InfoSize)) 2220 { 2221 HeapFree(GetProcessHeap(), 0, UserInfo); 2222 return NULL; 2223 } 2224 } 2225 2226 if (! ConvertSidToStringSidW(UserInfo->User.Sid, &SidStr)) 2227 SidStr = NULL; 2228 2229 if (UserInfo != (PTOKEN_USER) InfoBuffer) 2230 HeapFree(GetProcessHeap(), 0, UserInfo); 2231 2232 return SidStr; 2233 } 2234 2235 /* Gets the user's path (unexpanded) for the CSIDL with index folder: 2236 * If SHGFP_TYPE_DEFAULT is set, calls _SHGetDefaultValue for it. Otherwise 2237 * calls _SHGetUserShellFolderPath for it. Where it looks depends on hToken: 2238 * - if hToken is -1, looks in HKEY_USERS\.Default 2239 * - otherwise looks first in HKEY_CURRENT_USER, followed by HKEY_LOCAL_MACHINE 2240 * if HKEY_CURRENT_USER doesn't contain any entries. If both fail, finally 2241 * calls _SHGetDefaultValue for it. 2242 */ 2243 static HRESULT _SHGetUserProfilePath(HANDLE hToken, DWORD dwFlags, BYTE folder, 2244 LPWSTR pszPath) 2245 { 2246 const WCHAR *szValueName; 2247 WCHAR buffer[40]; 2248 HRESULT hr; 2249 2250 TRACE("%p,0x%08x,0x%02x,%p\n", hToken, dwFlags, folder, pszPath); 2251 2252 if (folder >= ARRAY_SIZE(CSIDL_Data)) 2253 return E_INVALIDARG; 2254 #ifdef __REACTOS__ 2255 if (CSIDL_Data[folder].type != CSIDL_Type_User && 2256 CSIDL_Data[folder].type != CSIDL_Type_InMyDocuments) 2257 #else 2258 if (CSIDL_Data[folder].type != CSIDL_Type_User) 2259 #endif 2260 { 2261 return E_INVALIDARG; 2262 } 2263 if (!pszPath) 2264 return E_INVALIDARG; 2265 2266 if (dwFlags & SHGFP_TYPE_DEFAULT) 2267 { 2268 #ifndef __REACTOS__ 2269 hr = _SHGetDefaultValue(folder, pszPath); 2270 #else 2271 hr = _SHGetDefaultValue(hToken, folder, pszPath); 2272 #endif 2273 } 2274 else 2275 { 2276 static const WCHAR DefaultW[] = L".Default"; 2277 LPCWSTR userPrefix = NULL; 2278 HKEY hRootKey; 2279 2280 if (hToken == (HANDLE)-1) 2281 { 2282 hRootKey = HKEY_USERS; 2283 userPrefix = DefaultW; 2284 } 2285 else if (hToken == NULL) 2286 hRootKey = HKEY_CURRENT_USER; 2287 else 2288 { 2289 hRootKey = HKEY_USERS; 2290 userPrefix = _GetUserSidStringFromToken(hToken); 2291 if (userPrefix == NULL) 2292 { 2293 hr = E_FAIL; 2294 goto error; 2295 } 2296 } 2297 2298 /* For CSIDL_Type_User we also use the GUID if no szValueName is provided */ 2299 szValueName = CSIDL_Data[folder].szValueName; 2300 if (!szValueName) 2301 { 2302 StringFromGUID2( CSIDL_Data[folder].id, buffer, 39 ); 2303 szValueName = &buffer[0]; 2304 } 2305 2306 #ifndef __REACTOS__ 2307 hr = _SHGetUserShellFolderPath(hRootKey, userPrefix, szValueName, pszPath); 2308 if (FAILED(hr) && hRootKey != HKEY_LOCAL_MACHINE) 2309 hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, szValueName, pszPath); 2310 if (FAILED(hr)) 2311 hr = _SHGetDefaultValue(folder, pszPath); 2312 #else 2313 hr = _SHGetUserShellFolderPath(hRootKey, hToken, userPrefix, szValueName, pszPath); 2314 if (FAILED(hr) && hRootKey != HKEY_LOCAL_MACHINE) 2315 hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, hToken, NULL, szValueName, pszPath); 2316 if (FAILED(hr)) 2317 hr = _SHGetDefaultValue(hToken, folder, pszPath); 2318 #endif 2319 if (userPrefix != NULL && userPrefix != DefaultW) 2320 LocalFree((HLOCAL) userPrefix); 2321 } 2322 error: 2323 TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath)); 2324 return hr; 2325 } 2326 2327 /* Gets the (unexpanded) path for the CSIDL with index folder. If dwFlags has 2328 * SHGFP_TYPE_DEFAULT set, calls _SHGetDefaultValue. Otherwise calls 2329 * _SHGetUserShellFolderPath for it, looking only in HKEY_LOCAL_MACHINE. 2330 * If this fails, falls back to _SHGetDefaultValue. 2331 */ 2332 static HRESULT _SHGetAllUsersProfilePath(DWORD dwFlags, BYTE folder, 2333 LPWSTR pszPath) 2334 { 2335 HRESULT hr; 2336 2337 TRACE("0x%08x,0x%02x,%p\n", dwFlags, folder, pszPath); 2338 2339 if (folder >= ARRAY_SIZE(CSIDL_Data)) 2340 return E_INVALIDARG; 2341 if (CSIDL_Data[folder].type != CSIDL_Type_AllUsers) 2342 return E_INVALIDARG; 2343 if (!pszPath) 2344 return E_INVALIDARG; 2345 2346 if (dwFlags & SHGFP_TYPE_DEFAULT) 2347 #ifndef __REACTOS__ 2348 hr = _SHGetDefaultValue(folder, pszPath); 2349 #else 2350 hr = _SHGetDefaultValue(NULL, folder, pszPath); 2351 #endif 2352 else 2353 { 2354 #ifndef __REACTOS__ 2355 hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, 2356 #else 2357 hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, NULL, 2358 #endif 2359 CSIDL_Data[folder].szValueName, pszPath); 2360 if (FAILED(hr)) 2361 #ifndef __REACTOS__ 2362 hr = _SHGetDefaultValue(folder, pszPath); 2363 #else 2364 hr = _SHGetDefaultValue(NULL, folder, pszPath); 2365 #endif 2366 } 2367 TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath)); 2368 return hr; 2369 } 2370 2371 #ifndef __REACTOS__ 2372 static HRESULT _SHOpenProfilesKey(PHKEY pKey) 2373 { 2374 LONG lRet; 2375 DWORD disp; 2376 2377 lRet = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList", 0, NULL, 0, 2378 KEY_ALL_ACCESS, NULL, pKey, &disp); 2379 return HRESULT_FROM_WIN32(lRet); 2380 } 2381 2382 /* Reads the value named szValueName from the key profilesKey (assumed to be 2383 * opened by _SHOpenProfilesKey) into szValue, which is assumed to be MAX_PATH 2384 * WCHARs in length. If it doesn't exist, returns szDefault (and saves 2385 * szDefault to the registry). 2386 */ 2387 static HRESULT _SHGetProfilesValue(HKEY profilesKey, LPCWSTR szValueName, 2388 LPWSTR szValue, LPCWSTR szDefault) 2389 { 2390 HRESULT hr; 2391 DWORD type, dwPathLen = MAX_PATH * sizeof(WCHAR); 2392 LONG lRet; 2393 2394 TRACE("%p,%s,%p,%s\n", profilesKey, debugstr_w(szValueName), szValue, 2395 debugstr_w(szDefault)); 2396 lRet = RegQueryValueExW(profilesKey, szValueName, NULL, &type, 2397 (LPBYTE)szValue, &dwPathLen); 2398 if (!lRet && (type == REG_SZ || type == REG_EXPAND_SZ) && dwPathLen 2399 && *szValue) 2400 { 2401 dwPathLen /= sizeof(WCHAR); 2402 szValue[dwPathLen] = '\0'; 2403 hr = S_OK; 2404 } 2405 else 2406 { 2407 /* Missing or invalid value, set a default */ 2408 lstrcpynW(szValue, szDefault, MAX_PATH); 2409 TRACE("Setting missing value %s to %s\n", debugstr_w(szValueName), 2410 debugstr_w(szValue)); 2411 lRet = RegSetValueExW(profilesKey, szValueName, 0, REG_EXPAND_SZ, 2412 (LPBYTE)szValue, 2413 (strlenW(szValue) + 1) * sizeof(WCHAR)); 2414 if (lRet) 2415 hr = HRESULT_FROM_WIN32(lRet); 2416 else 2417 hr = S_OK; 2418 } 2419 TRACE("returning 0x%08x (output value is %s)\n", hr, debugstr_w(szValue)); 2420 return hr; 2421 } 2422 #endif 2423 2424 /* Attempts to expand environment variables from szSrc into szDest, which is 2425 * assumed to be MAX_PATH characters in length. Before referring to the 2426 * environment, handles a few variables directly, because the environment 2427 * variables may not be set when this is called (as during Wine's installation 2428 * when default values are being written to the registry). 2429 * The directly handled environment variables, and their source, are: 2430 * - ALLUSERSPROFILE, USERPROFILE: reads from the registry 2431 * - SystemDrive: uses GetSystemDirectoryW and uses the drive portion of its 2432 * path 2433 * If one of the directly handled environment variables is expanded, only 2434 * expands a single variable, and only in the beginning of szSrc. 2435 */ 2436 #ifndef __REACTOS__ 2437 static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest) 2438 #else 2439 static HRESULT _SHExpandEnvironmentStrings(HANDLE hToken, LPCWSTR szSrc, LPWSTR szDest, DWORD cchDest) 2440 #endif 2441 { 2442 HRESULT hr; 2443 #ifndef __REACTOS__ 2444 WCHAR szTemp[MAX_PATH], szProfilesPrefix[MAX_PATH] = { 0 }; 2445 HKEY key = NULL; 2446 #else 2447 WCHAR szTemp[MAX_PATH]; 2448 #endif 2449 2450 TRACE("%s, %p\n", debugstr_w(szSrc), szDest); 2451 2452 if (!szSrc || !szDest) return E_INVALIDARG; 2453 2454 /* short-circuit if there's nothing to expand */ 2455 if (szSrc[0] != '%') 2456 { 2457 strcpyW(szDest, szSrc); 2458 hr = S_OK; 2459 goto end; 2460 } 2461 #ifndef __REACTOS__ 2462 /* Get the profile prefix, we'll probably be needing it */ 2463 hr = _SHOpenProfilesKey(&key); 2464 if (SUCCEEDED(hr)) 2465 { 2466 WCHAR def_val[MAX_PATH]; 2467 2468 /* get the system drive */ 2469 GetSystemDirectoryW(def_val, MAX_PATH); 2470 strcpyW( def_val + 3, L"Users" ); 2471 2472 hr = _SHGetProfilesValue(key, L"ProfilesDirectory", szProfilesPrefix, def_val ); 2473 } 2474 #else 2475 hr = S_OK; 2476 #endif 2477 2478 *szDest = 0; 2479 strcpyW(szTemp, szSrc); 2480 while (SUCCEEDED(hr) && szTemp[0] == '%') 2481 { 2482 if (!strncmpiW(szTemp, L"%ALLUSERSPROFILE%", ARRAY_SIZE(L"%ALLUSERSPROFILE%")-1)) 2483 { 2484 #ifndef __REACTOS__ 2485 WCHAR szAllUsers[MAX_PATH]; 2486 2487 strcpyW(szDest, szProfilesPrefix); 2488 hr = _SHGetProfilesValue(key, L"AllUsersProfile", szAllUsers, L"Public"); 2489 PathAppendW(szDest, szAllUsers); 2490 #else 2491 DWORD cchSize = cchDest; 2492 if (!GetAllUsersProfileDirectoryW(szDest, &cchSize)) 2493 goto fallback_expand; 2494 #endif 2495 PathAppendW(szDest, szTemp + ARRAY_SIZE(L"%ALLUSERSPROFILE%")-1); 2496 } 2497 #ifndef __REACTOS__ 2498 else if (!strncmpiW(szTemp, L"%PUBLIC%", ARRAY_SIZE(L"%PUBLIC%")-1)) 2499 { 2500 WCHAR szAllUsers[MAX_PATH], def_val[MAX_PATH]; 2501 2502 GetSystemDirectoryW(def_val, MAX_PATH); 2503 strcpyW( def_val + 3, L"Users\\Public" ); 2504 2505 hr = _SHGetProfilesValue(key, L"Public", szAllUsers, def_val); 2506 PathAppendW(szDest, szAllUsers); 2507 PathAppendW(szDest, szTemp + ARRAY_SIZE(L"%PUBLIC%")-1); 2508 } 2509 #endif 2510 else if (!strncmpiW(szTemp, L"%USERPROFILE%", ARRAY_SIZE(L"%USERPROFILE%")-1)) 2511 { 2512 #ifndef __REACTOS__ 2513 WCHAR userName[MAX_PATH]; 2514 DWORD userLen = MAX_PATH; 2515 2516 strcpyW(szDest, szProfilesPrefix); 2517 GetUserNameW(userName, &userLen); 2518 PathAppendW(szDest, userName); 2519 #else 2520 DWORD cchSize = cchDest; 2521 if (!_SHGetUserProfileDirectoryW(hToken, szDest, &cchSize)) 2522 goto fallback_expand; 2523 #endif 2524 PathAppendW(szDest, szTemp + ARRAY_SIZE(L"%USERPROFILE%")-1); 2525 } 2526 else if (!strncmpiW(szTemp, L"%SystemDrive%", ARRAY_SIZE(L"%SystemDrive%")-1)) 2527 { 2528 #ifndef __REACTOS__ 2529 GetSystemDirectoryW(szDest, MAX_PATH); 2530 #else 2531 if (!GetSystemDirectoryW(szDest, cchDest)) 2532 goto fallback_expand; 2533 #endif 2534 strcpyW(szDest + 3, szTemp + ARRAY_SIZE(L"%SystemDrive%")-1 + 1); 2535 } 2536 else 2537 #ifdef __REACTOS__ 2538 fallback_expand: 2539 #endif 2540 { 2541 #ifndef __REACTOS__ 2542 DWORD ret = ExpandEnvironmentStringsW(szTemp, szDest, MAX_PATH); 2543 #else 2544 DWORD ret = SHExpandEnvironmentStringsForUserW(hToken, szTemp, szDest, cchDest); 2545 #endif 2546 2547 #ifndef __REACTOS__ 2548 if (ret > MAX_PATH) 2549 #else 2550 if (ret > cchDest) 2551 #endif 2552 hr = E_NOT_SUFFICIENT_BUFFER; 2553 else if (ret == 0) 2554 hr = HRESULT_FROM_WIN32(GetLastError()); 2555 else if (!strcmpW( szTemp, szDest )) break; /* nothing expanded */ 2556 } 2557 if (SUCCEEDED(hr)) strcpyW(szTemp, szDest); 2558 } 2559 end: 2560 #ifndef __REACTOS__ 2561 if (key) 2562 RegCloseKey(key); 2563 #endif 2564 TRACE("returning 0x%08x (input was %s, output is %s)\n", hr, 2565 debugstr_w(szSrc), debugstr_w(szDest)); 2566 return hr; 2567 } 2568 2569 /************************************************************************* 2570 * SHGetFolderPathW [SHELL32.@] 2571 * 2572 * Convert nFolder to path. 2573 * 2574 * RETURNS 2575 * Success: S_OK 2576 * Failure: standard HRESULT error codes. 2577 * 2578 * NOTES 2579 * Most values can be overridden in either 2580 * HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders 2581 * or in the same location in HKLM. 2582 * The "Shell Folders" registry key was used in NT4 and earlier systems. 2583 * Beginning with Windows 2000, the "User Shell Folders" key is used, so 2584 * changes made to it are made to the former key too. This synchronization is 2585 * done on-demand: not until someone requests the value of one of these paths 2586 * (by calling one of the SHGet functions) is the value synchronized. 2587 * Furthermore, the HKCU paths take precedence over the HKLM paths. 2588 */ 2589 HRESULT WINAPI SHGetFolderPathW( 2590 HWND hwndOwner, /* [I] owner window */ 2591 int nFolder, /* [I] CSIDL identifying the folder */ 2592 HANDLE hToken, /* [I] access token */ 2593 DWORD dwFlags, /* [I] which path to return */ 2594 LPWSTR pszPath) /* [O] converted path */ 2595 { 2596 HRESULT hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, NULL, pszPath); 2597 if(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) 2598 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 2599 return hr; 2600 } 2601 2602 HRESULT WINAPI SHGetFolderPathAndSubDirA( 2603 HWND hwndOwner, /* [I] owner window */ 2604 int nFolder, /* [I] CSIDL identifying the folder */ 2605 HANDLE hToken, /* [I] access token */ 2606 DWORD dwFlags, /* [I] which path to return */ 2607 LPCSTR pszSubPath, /* [I] sub directory of the specified folder */ 2608 LPSTR pszPath) /* [O] converted path */ 2609 { 2610 int length; 2611 HRESULT hr = S_OK; 2612 LPWSTR pszSubPathW = NULL; 2613 LPWSTR pszPathW = NULL; 2614 2615 TRACE("%p,%#x,%p,%#x,%s,%p\n", hwndOwner, nFolder, hToken, dwFlags, debugstr_a(pszSubPath), pszPath); 2616 2617 if(pszPath) { 2618 pszPathW = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR)); 2619 if(!pszPathW) { 2620 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); 2621 goto cleanup; 2622 } 2623 } 2624 TRACE("%08x,%08x,%s\n",nFolder, dwFlags, debugstr_w(pszSubPathW)); 2625 2626 /* SHGetFolderPathAndSubDirW does not distinguish if pszSubPath isn't 2627 * set (null), or an empty string.therefore call it without the parameter set 2628 * if pszSubPath is an empty string 2629 */ 2630 if (pszSubPath && pszSubPath[0]) { 2631 length = MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, NULL, 0); 2632 pszSubPathW = HeapAlloc(GetProcessHeap(), 0, length * sizeof(WCHAR)); 2633 if(!pszSubPathW) { 2634 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); 2635 goto cleanup; 2636 } 2637 MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, pszSubPathW, length); 2638 } 2639 2640 hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, pszSubPathW, pszPathW); 2641 2642 if (SUCCEEDED(hr) && pszPath) 2643 WideCharToMultiByte(CP_ACP, 0, pszPathW, -1, pszPath, MAX_PATH, NULL, NULL); 2644 2645 cleanup: 2646 HeapFree(GetProcessHeap(), 0, pszPathW); 2647 HeapFree(GetProcessHeap(), 0, pszSubPathW); 2648 return hr; 2649 } 2650 2651 /************************************************************************* 2652 * SHGetFolderPathAndSubDirW [SHELL32.@] 2653 */ 2654 HRESULT WINAPI SHGetFolderPathAndSubDirW( 2655 HWND hwndOwner, /* [I] owner window */ 2656 int nFolder, /* [I] CSIDL identifying the folder */ 2657 HANDLE hToken, /* [I] access token */ 2658 DWORD dwFlags, /* [I] which path to return */ 2659 LPCWSTR pszSubPath,/* [I] sub directory of the specified folder */ 2660 LPWSTR pszPath) /* [O] converted path */ 2661 { 2662 HRESULT hr; 2663 WCHAR szBuildPath[MAX_PATH], szTemp[MAX_PATH]; 2664 DWORD folder = nFolder & CSIDL_FOLDER_MASK; 2665 CSIDL_Type type; 2666 int ret; 2667 2668 TRACE("%p,%#x,%p,%#x,%s,%p\n", hwndOwner, nFolder, hToken, dwFlags, debugstr_w(pszSubPath), pszPath); 2669 2670 /* Windows always NULL-terminates the resulting path regardless of success 2671 * or failure, so do so first 2672 */ 2673 if (pszPath) 2674 *pszPath = '\0'; 2675 2676 if (folder >= ARRAY_SIZE(CSIDL_Data)) 2677 return E_INVALIDARG; 2678 if ((SHGFP_TYPE_CURRENT != dwFlags) && (SHGFP_TYPE_DEFAULT != dwFlags)) 2679 return E_INVALIDARG; 2680 szTemp[0] = 0; 2681 type = CSIDL_Data[folder].type; 2682 switch (type) 2683 { 2684 case CSIDL_Type_Disallowed: 2685 hr = E_INVALIDARG; 2686 break; 2687 case CSIDL_Type_NonExistent: 2688 hr = S_FALSE; 2689 break; 2690 case CSIDL_Type_WindowsPath: 2691 GetWindowsDirectoryW(szTemp, MAX_PATH); 2692 if (CSIDL_Data[folder].szDefaultPath && 2693 !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) && 2694 *CSIDL_Data[folder].szDefaultPath) 2695 { 2696 PathAddBackslashW(szTemp); 2697 strcatW(szTemp, CSIDL_Data[folder].szDefaultPath); 2698 } 2699 hr = S_OK; 2700 break; 2701 case CSIDL_Type_SystemPath: 2702 GetSystemDirectoryW(szTemp, MAX_PATH); 2703 if (CSIDL_Data[folder].szDefaultPath && 2704 !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) && 2705 *CSIDL_Data[folder].szDefaultPath) 2706 { 2707 PathAddBackslashW(szTemp); 2708 strcatW(szTemp, CSIDL_Data[folder].szDefaultPath); 2709 } 2710 hr = S_OK; 2711 break; 2712 case CSIDL_Type_SystemX86Path: 2713 if (!GetSystemWow64DirectoryW(szTemp, MAX_PATH)) GetSystemDirectoryW(szTemp, MAX_PATH); 2714 if (CSIDL_Data[folder].szDefaultPath && 2715 !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) && 2716 *CSIDL_Data[folder].szDefaultPath) 2717 { 2718 PathAddBackslashW(szTemp); 2719 strcatW(szTemp, CSIDL_Data[folder].szDefaultPath); 2720 } 2721 hr = S_OK; 2722 break; 2723 case CSIDL_Type_CurrVer: 2724 hr = _SHGetCurrentVersionPath(dwFlags, folder, szTemp); 2725 break; 2726 case CSIDL_Type_User: 2727 #ifdef __REACTOS__ 2728 case CSIDL_Type_InMyDocuments: 2729 #endif 2730 hr = _SHGetUserProfilePath(hToken, dwFlags, folder, szTemp); 2731 break; 2732 case CSIDL_Type_AllUsers: 2733 hr = _SHGetAllUsersProfilePath(dwFlags, folder, szTemp); 2734 break; 2735 default: 2736 FIXME("bogus type %d, please fix\n", type); 2737 hr = E_INVALIDARG; 2738 break; 2739 } 2740 2741 /* Expand environment strings if necessary */ 2742 if (*szTemp == '%') 2743 #ifndef __REACTOS__ 2744 hr = _SHExpandEnvironmentStrings(szTemp, szBuildPath); 2745 #else 2746 hr = _SHExpandEnvironmentStrings(hToken, szTemp, szBuildPath, _countof(szBuildPath)); 2747 #endif 2748 else 2749 strcpyW(szBuildPath, szTemp); 2750 2751 if (FAILED(hr)) goto end; 2752 2753 if(pszSubPath) { 2754 /* make sure the new path does not exceed the buffer length 2755 * and remember to backslash and terminate it */ 2756 if(MAX_PATH < (lstrlenW(szBuildPath) + lstrlenW(pszSubPath) + 2)) { 2757 hr = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE); 2758 goto end; 2759 } 2760 PathAppendW(szBuildPath, pszSubPath); 2761 PathRemoveBackslashW(szBuildPath); 2762 } 2763 /* Copy the path if it's available before we might return */ 2764 if (SUCCEEDED(hr) && pszPath) 2765 strcpyW(pszPath, szBuildPath); 2766 2767 /* if we don't care about existing directories we are ready */ 2768 if(nFolder & CSIDL_FLAG_DONT_VERIFY) goto end; 2769 2770 if (PathFileExistsW(szBuildPath)) goto end; 2771 2772 /* not existing but we are not allowed to create it. The return value 2773 * is verified against shell32 version 6.0. 2774 */ 2775 if (!(nFolder & CSIDL_FLAG_CREATE)) 2776 { 2777 hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 2778 goto end; 2779 } 2780 2781 /* create directory/directories */ 2782 ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, NULL); 2783 if (ret && ret != ERROR_ALREADY_EXISTS) 2784 { 2785 ERR("Failed to create directory %s.\n", debugstr_w(szBuildPath)); 2786 hr = E_FAIL; 2787 goto end; 2788 } 2789 2790 TRACE("Created missing system directory %s\n", debugstr_w(szBuildPath)); 2791 2792 end: 2793 #ifdef __REACTOS__ 2794 /* create desktop.ini for custom icon */ 2795 if ((nFolder & CSIDL_FLAG_CREATE) && 2796 CSIDL_Data[folder].nShell32IconIndex) 2797 { 2798 WCHAR szIconLocation[MAX_PATH]; 2799 DWORD dwAttributes; 2800 2801 /* make the directory a read-only folder */ 2802 dwAttributes = GetFileAttributesW(szBuildPath); 2803 dwAttributes |= FILE_ATTRIBUTE_READONLY; 2804 SetFileAttributesW(szBuildPath, dwAttributes); 2805 2806 /* build the desktop.ini file path */ 2807 PathAppendW(szBuildPath, L"desktop.ini"); 2808 2809 /* build the icon location */ 2810 StringCchPrintfW(szIconLocation, _countof(szIconLocation), 2811 L"%%SystemRoot%%\\system32\\shell32.dll,%d", 2812 CSIDL_Data[folder].nShell32IconIndex); 2813 2814 /* write desktop.ini */ 2815 WritePrivateProfileStringW(L".ShellClassInfo", L"IconResource", szIconLocation, szBuildPath); 2816 2817 /* flush! */ 2818 WritePrivateProfileStringW(NULL, NULL, NULL, szBuildPath); 2819 2820 /* make the desktop.ini a system and hidden file */ 2821 dwAttributes = GetFileAttributesW(szBuildPath); 2822 dwAttributes |= FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN; 2823 SetFileAttributesW(szBuildPath, dwAttributes); 2824 } 2825 #endif 2826 2827 TRACE("returning 0x%08x (final path is %s)\n", hr, debugstr_w(szBuildPath)); 2828 return hr; 2829 } 2830 2831 /************************************************************************* 2832 * SHGetFolderPathA [SHELL32.@] 2833 * 2834 * See SHGetFolderPathW. 2835 */ 2836 HRESULT WINAPI SHGetFolderPathA( 2837 HWND hwndOwner, 2838 int nFolder, 2839 HANDLE hToken, 2840 DWORD dwFlags, 2841 LPSTR pszPath) 2842 { 2843 WCHAR szTemp[MAX_PATH]; 2844 HRESULT hr; 2845 2846 TRACE("%p,%d,%p,%#x,%p\n", hwndOwner, nFolder, hToken, dwFlags, pszPath); 2847 2848 if (pszPath) 2849 *pszPath = '\0'; 2850 hr = SHGetFolderPathW(hwndOwner, nFolder, hToken, dwFlags, szTemp); 2851 if (SUCCEEDED(hr) && pszPath) 2852 WideCharToMultiByte(CP_ACP, 0, szTemp, -1, pszPath, MAX_PATH, NULL, 2853 NULL); 2854 2855 return hr; 2856 } 2857 2858 /* For each folder in folders, if its value has not been set in the registry, 2859 * calls _SHGetUserProfilePath or _SHGetAllUsersProfilePath (depending on the 2860 * folder's type) to get the unexpanded value first. 2861 * Writes the unexpanded value to User Shell Folders, and queries it with 2862 * SHGetFolderPathW to force the creation of the directory if it doesn't 2863 * already exist. SHGetFolderPathW also returns the expanded value, which 2864 * this then writes to Shell Folders. 2865 */ 2866 static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, 2867 LPCWSTR szUserShellFolderPath, LPCWSTR szShellFolderPath, const UINT folders[], 2868 UINT foldersLen) 2869 { 2870 const WCHAR *szValueName; 2871 WCHAR buffer[40]; 2872 UINT i; 2873 WCHAR path[MAX_PATH]; 2874 HRESULT hr = S_OK; 2875 HKEY hUserKey = NULL, hKey = NULL; 2876 DWORD dwType, dwPathLen; 2877 LONG ret; 2878 2879 TRACE("%p,%p,%s,%p,%u\n", hRootKey, hToken, 2880 debugstr_w(szUserShellFolderPath), folders, foldersLen); 2881 2882 ret = RegCreateKeyW(hRootKey, szUserShellFolderPath, &hUserKey); 2883 if (ret) 2884 hr = HRESULT_FROM_WIN32(ret); 2885 else 2886 { 2887 ret = RegCreateKeyW(hRootKey, szShellFolderPath, &hKey); 2888 if (ret) 2889 hr = HRESULT_FROM_WIN32(ret); 2890 } 2891 for (i = 0; SUCCEEDED(hr) && i < foldersLen; i++) 2892 { 2893 dwPathLen = MAX_PATH * sizeof(WCHAR); 2894 2895 /* For CSIDL_Type_User we also use the GUID if no szValueName is provided */ 2896 szValueName = CSIDL_Data[folders[i]].szValueName; 2897 #ifdef __REACTOS__ 2898 if (!szValueName && 2899 (CSIDL_Data[folders[i]].type == CSIDL_Type_User || 2900 CSIDL_Data[folders[i]].type == CSIDL_Type_InMyDocuments)) 2901 #else 2902 if (!szValueName && CSIDL_Data[folders[i]].type == CSIDL_Type_User) 2903 #endif 2904 { 2905 StringFromGUID2( CSIDL_Data[folders[i]].id, buffer, 39 ); 2906 szValueName = &buffer[0]; 2907 } 2908 2909 if (!RegQueryValueExW(hUserKey, szValueName, NULL, 2910 &dwType, (LPBYTE)path, &dwPathLen) && 2911 (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) 2912 { 2913 hr = SHGetFolderPathW(NULL, folders[i] | CSIDL_FLAG_CREATE, 2914 hToken, SHGFP_TYPE_CURRENT, path); 2915 } 2916 else 2917 { 2918 *path = '\0'; 2919 #ifdef __REACTOS__ 2920 if (CSIDL_Data[folders[i]].type == CSIDL_Type_User || 2921 CSIDL_Data[folders[i]].type == CSIDL_Type_InMyDocuments) 2922 #else 2923 if (CSIDL_Data[folders[i]].type == CSIDL_Type_User) 2924 #endif 2925 _SHGetUserProfilePath(hToken, SHGFP_TYPE_CURRENT, folders[i], 2926 path); 2927 else if (CSIDL_Data[folders[i]].type == CSIDL_Type_AllUsers) 2928 _SHGetAllUsersProfilePath(SHGFP_TYPE_CURRENT, folders[i], path); 2929 else if (CSIDL_Data[folders[i]].type == CSIDL_Type_WindowsPath) 2930 { 2931 GetWindowsDirectoryW(path, MAX_PATH); 2932 if (CSIDL_Data[folders[i]].szDefaultPath && 2933 !IS_INTRESOURCE(CSIDL_Data[folders[i]].szDefaultPath)) 2934 { 2935 PathAddBackslashW(path); 2936 strcatW(path, CSIDL_Data[folders[i]].szDefaultPath); 2937 } 2938 } 2939 else 2940 hr = E_FAIL; 2941 if (*path) 2942 { 2943 ret = RegSetValueExW(hUserKey, szValueName, 0, REG_EXPAND_SZ, 2944 (LPBYTE)path, (strlenW(path) + 1) * sizeof(WCHAR)); 2945 if (ret) 2946 hr = HRESULT_FROM_WIN32(ret); 2947 else 2948 { 2949 hr = SHGetFolderPathW(NULL, folders[i] | CSIDL_FLAG_CREATE, 2950 hToken, SHGFP_TYPE_CURRENT, path); 2951 ret = RegSetValueExW(hKey, szValueName, 0, REG_SZ, 2952 (LPBYTE)path, (strlenW(path) + 1) * sizeof(WCHAR)); 2953 if (ret) 2954 hr = HRESULT_FROM_WIN32(ret); 2955 } 2956 } 2957 } 2958 } 2959 if (hUserKey) 2960 RegCloseKey(hUserKey); 2961 if (hKey) 2962 RegCloseKey(hKey); 2963 2964 TRACE("returning 0x%08x\n", hr); 2965 return hr; 2966 } 2967 2968 static HRESULT _SHRegisterUserShellFolders(BOOL bDefault) 2969 { 2970 static const UINT folders[] = { 2971 CSIDL_PROGRAMS, 2972 CSIDL_PERSONAL, 2973 CSIDL_FAVORITES, 2974 CSIDL_APPDATA, 2975 CSIDL_STARTUP, 2976 CSIDL_RECENT, 2977 CSIDL_SENDTO, 2978 CSIDL_STARTMENU, 2979 CSIDL_MYMUSIC, 2980 CSIDL_MYVIDEO, 2981 CSIDL_DESKTOPDIRECTORY, 2982 CSIDL_NETHOOD, 2983 CSIDL_TEMPLATES, 2984 CSIDL_PRINTHOOD, 2985 CSIDL_LOCAL_APPDATA, 2986 CSIDL_INTERNET_CACHE, 2987 CSIDL_COOKIES, 2988 CSIDL_HISTORY, 2989 CSIDL_MYPICTURES, 2990 CSIDL_FONTS, 2991 CSIDL_ADMINTOOLS, 2992 /* Cannot use #if _WIN32_WINNT >= 0x0600 because _WIN32_WINNT == 0x0600 here. */ 2993 #ifndef __REACTOS__ 2994 CSIDL_CONTACTS, 2995 CSIDL_DOWNLOADS, 2996 CSIDL_LINKS, 2997 CSIDL_APPDATA_LOCALLOW, 2998 CSIDL_SAVED_GAMES, 2999 CSIDL_SEARCHES 3000 #endif 3001 }; 3002 WCHAR userShellFolderPath[MAX_PATH], shellFolderPath[MAX_PATH]; 3003 LPCWSTR pUserShellFolderPath, pShellFolderPath; 3004 HRESULT hr = S_OK; 3005 HKEY hRootKey; 3006 HANDLE hToken; 3007 3008 TRACE("%s\n", bDefault ? "TRUE" : "FALSE"); 3009 if (bDefault) 3010 { 3011 hToken = (HANDLE)-1; 3012 hRootKey = HKEY_USERS; 3013 strcpyW(userShellFolderPath, L".Default"); 3014 PathAddBackslashW(userShellFolderPath); 3015 strcatW(userShellFolderPath, szSHUserFolders); 3016 pUserShellFolderPath = userShellFolderPath; 3017 strcpyW(shellFolderPath, L".Default"); 3018 PathAddBackslashW(shellFolderPath); 3019 strcatW(shellFolderPath, szSHFolders); 3020 pShellFolderPath = shellFolderPath; 3021 } 3022 else 3023 { 3024 hToken = NULL; 3025 hRootKey = HKEY_CURRENT_USER; 3026 pUserShellFolderPath = szSHUserFolders; 3027 pShellFolderPath = szSHFolders; 3028 } 3029 3030 hr = _SHRegisterFolders(hRootKey, hToken, pUserShellFolderPath, 3031 pShellFolderPath, folders, ARRAY_SIZE(folders)); 3032 TRACE("returning 0x%08x\n", hr); 3033 return hr; 3034 } 3035 3036 static HRESULT _SHRegisterCommonShellFolders(void) 3037 { 3038 static const UINT folders[] = { 3039 CSIDL_COMMON_STARTMENU, 3040 CSIDL_COMMON_PROGRAMS, 3041 CSIDL_COMMON_STARTUP, 3042 CSIDL_COMMON_DESKTOPDIRECTORY, 3043 CSIDL_COMMON_FAVORITES, 3044 CSIDL_COMMON_APPDATA, 3045 CSIDL_COMMON_TEMPLATES, 3046 CSIDL_COMMON_DOCUMENTS, 3047 CSIDL_COMMON_ADMINTOOLS, 3048 CSIDL_COMMON_MUSIC, 3049 CSIDL_COMMON_PICTURES, 3050 CSIDL_COMMON_VIDEO, 3051 }; 3052 HRESULT hr; 3053 3054 TRACE("\n"); 3055 hr = _SHRegisterFolders(HKEY_LOCAL_MACHINE, NULL, szSHUserFolders, 3056 szSHFolders, folders, ARRAY_SIZE(folders)); 3057 TRACE("returning 0x%08x\n", hr); 3058 return hr; 3059 } 3060 3061 /* Register the default values in the registry, as some apps seem to depend 3062 * on their presence. The set registered was taken from Windows XP. 3063 */ 3064 HRESULT SHELL_RegisterShellFolders(void) 3065 { 3066 HRESULT hr; 3067 3068 hr = _SHRegisterUserShellFolders(TRUE); 3069 if (SUCCEEDED(hr)) 3070 hr = _SHRegisterUserShellFolders(FALSE); 3071 if (SUCCEEDED(hr)) 3072 hr = _SHRegisterCommonShellFolders(); 3073 return hr; 3074 } 3075 3076 /************************************************************************* 3077 * SHGetSpecialFolderPathA [SHELL32.@] 3078 */ 3079 BOOL WINAPI SHGetSpecialFolderPathA ( 3080 HWND hwndOwner, 3081 LPSTR szPath, 3082 int nFolder, 3083 BOOL bCreate) 3084 { 3085 return SHGetFolderPathA(hwndOwner, nFolder + (bCreate ? CSIDL_FLAG_CREATE : 0), NULL, 0, 3086 szPath) == S_OK; 3087 } 3088 3089 /************************************************************************* 3090 * SHGetSpecialFolderPathW 3091 */ 3092 BOOL WINAPI SHGetSpecialFolderPathW ( 3093 HWND hwndOwner, 3094 LPWSTR szPath, 3095 int nFolder, 3096 BOOL bCreate) 3097 { 3098 return SHGetFolderPathW(hwndOwner, nFolder + (bCreate ? CSIDL_FLAG_CREATE : 0), NULL, 0, 3099 szPath) == S_OK; 3100 } 3101 3102 #ifdef __REACTOS__ 3103 HRESULT SHGetFolderLocationHelper(HWND hwnd, int nFolder, REFCLSID clsid, LPITEMIDLIST *ppidl) 3104 { 3105 HRESULT hr; 3106 IShellFolder *psf; 3107 LPITEMIDLIST parent, child; 3108 EXTERN_C HRESULT SHBindToObject(IShellFolder *psf, LPCITEMIDLIST pidl, REFIID riid, void **ppvObj); 3109 *ppidl = NULL; 3110 if (FAILED(hr = SHGetFolderLocation(hwnd, nFolder, NULL, 0, &parent))) 3111 return hr; 3112 if (SUCCEEDED(hr = SHBindToObject(NULL, parent, &IID_IShellFolder, (void**)&psf))) 3113 { 3114 WCHAR clsidstr[2 + 38 + 1]; 3115 clsidstr[0] = clsidstr[1] = L':'; 3116 StringFromGUID2(clsid, clsidstr + 2, 38 + 1); 3117 hr = IShellFolder_ParseDisplayName(psf, hwnd, NULL, clsidstr, NULL, &child, NULL); 3118 if (SUCCEEDED(hr)) 3119 *ppidl = ILCombine(parent, child); 3120 IShellFolder_Release(psf); 3121 ILFree(child); 3122 } 3123 ILFree(parent); 3124 return hr; 3125 } 3126 #endif 3127 3128 /************************************************************************* 3129 * SHGetFolderLocation [SHELL32.@] 3130 * 3131 * Gets the folder locations from the registry and creates a pidl. 3132 * 3133 * PARAMS 3134 * hwndOwner [I] 3135 * nFolder [I] CSIDL_xxxxx 3136 * hToken [I] token representing user, or NULL for current user, or -1 for 3137 * default user 3138 * dwReserved [I] must be zero 3139 * ppidl [O] PIDL of a special folder 3140 * 3141 * RETURNS 3142 * Success: S_OK 3143 * Failure: Standard OLE-defined error result, S_FALSE or E_INVALIDARG 3144 * 3145 * NOTES 3146 * Creates missing reg keys and directories. 3147 * Mostly forwards to SHGetFolderPathW, but a few values of nFolder return 3148 * virtual folders that are handled here. 3149 */ 3150 HRESULT WINAPI SHGetFolderLocation( 3151 HWND hwndOwner, 3152 int nFolder, 3153 HANDLE hToken, 3154 DWORD dwReserved, 3155 LPITEMIDLIST *ppidl) 3156 { 3157 HRESULT hr = E_INVALIDARG; 3158 #ifdef __REACTOS__ 3159 WCHAR szPath[MAX_PATH]; 3160 #endif 3161 3162 TRACE("%p 0x%08x %p 0x%08x %p\n", 3163 hwndOwner, nFolder, hToken, dwReserved, ppidl); 3164 3165 if (!ppidl) 3166 return E_INVALIDARG; 3167 if (dwReserved) 3168 return E_INVALIDARG; 3169 3170 #ifdef __REACTOS__ 3171 if ((nFolder & CSIDL_FLAG_NO_ALIAS) && 3172 SHGetSpecialFolderPathW(hwndOwner, szPath, (nFolder & CSIDL_FOLDER_MASK), FALSE)) 3173 { 3174 *ppidl = ILCreateFromPathW(szPath); 3175 if (*ppidl) 3176 return S_OK; 3177 } 3178 #endif 3179 /* The virtual folders' locations are not user-dependent */ 3180 *ppidl = NULL; 3181 switch (nFolder & CSIDL_FOLDER_MASK) 3182 { 3183 case CSIDL_DESKTOP: 3184 *ppidl = _ILCreateDesktop(); 3185 break; 3186 3187 case CSIDL_PERSONAL: 3188 *ppidl = _ILCreateMyDocuments(); 3189 break; 3190 3191 case CSIDL_INTERNET: 3192 *ppidl = _ILCreateIExplore(); 3193 break; 3194 3195 case CSIDL_CONTROLS: 3196 *ppidl = _ILCreateControlPanel(); 3197 break; 3198 3199 case CSIDL_PRINTERS: 3200 *ppidl = _ILCreatePrinters(); 3201 break; 3202 3203 case CSIDL_BITBUCKET: 3204 *ppidl = _ILCreateBitBucket(); 3205 break; 3206 3207 case CSIDL_DRIVES: 3208 *ppidl = _ILCreateMyComputer(); 3209 break; 3210 3211 case CSIDL_NETWORK: 3212 *ppidl = _ILCreateNetwork(); 3213 break; 3214 3215 #ifdef __REACTOS__ 3216 case CSIDL_CONNECTIONS: 3217 hr = SHGetFolderLocationHelper(hwndOwner, CSIDL_CONTROLS, &CLSID_NetworkConnections, ppidl); 3218 break; 3219 #endif 3220 3221 default: 3222 { 3223 WCHAR szPath[MAX_PATH]; 3224 3225 hr = SHGetFolderPathW(hwndOwner, nFolder, hToken, 3226 SHGFP_TYPE_CURRENT, szPath); 3227 if (SUCCEEDED(hr)) 3228 { 3229 DWORD attributes=0; 3230 3231 TRACE("Value=%s\n", debugstr_w(szPath)); 3232 hr = SHILCreateFromPathW(szPath, ppidl, &attributes); 3233 } 3234 else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) 3235 { 3236 /* unlike SHGetFolderPath, SHGetFolderLocation in shell32 3237 * version 6.0 returns E_FAIL for nonexistent paths 3238 */ 3239 hr = E_FAIL; 3240 } 3241 } 3242 } 3243 if(*ppidl) 3244 hr = S_OK; 3245 3246 TRACE("-- (new pidl %p)\n",*ppidl); 3247 return hr; 3248 } 3249 3250 /************************************************************************* 3251 * SHGetSpecialFolderLocation [SHELL32.@] 3252 * 3253 * NOTES 3254 * In NT5, SHGetSpecialFolderLocation needs the <winntdir>/Recent 3255 * directory. 3256 */ 3257 HRESULT WINAPI SHGetSpecialFolderLocation( 3258 HWND hwndOwner, 3259 INT nFolder, 3260 LPITEMIDLIST * ppidl) 3261 { 3262 HRESULT hr = E_INVALIDARG; 3263 3264 TRACE("(%p,0x%x,%p)\n", hwndOwner,nFolder,ppidl); 3265 3266 if (!ppidl) 3267 return E_INVALIDARG; 3268 3269 hr = SHGetFolderLocation(hwndOwner, nFolder, NULL, 0, ppidl); 3270 return hr; 3271 } 3272