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