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