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