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