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