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