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