[LT2013]
[reactos.git] / dll / win32 / shell32 / shellpath.cpp
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 #include "precomp.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(shell);
30
31 /*
32 ########## Combining and Constructing paths ##########
33 */
34
35 /*************************************************************************
36 * PathAppend [SHELL32.36]
37 */
38 BOOL WINAPI PathAppendAW(
39 LPVOID lpszPath1,
40 LPCVOID lpszPath2)
41 {
42 if (SHELL_OsIsUnicode())
43 return PathAppendW((LPWSTR)lpszPath1, (LPCWSTR)lpszPath2);
44 return PathAppendA((LPSTR)lpszPath1, (LPCSTR)lpszPath2);
45 }
46
47 /*************************************************************************
48 * PathBuildRoot [SHELL32.30]
49 */
50 LPVOID WINAPI PathBuildRootAW(LPVOID lpszPath, int drive)
51 {
52 if(SHELL_OsIsUnicode())
53 return PathBuildRootW((LPWSTR)lpszPath, drive);
54 return PathBuildRootA((LPSTR)lpszPath, drive);
55 }
56
57 /*************************************************************************
58 * PathGetExtensionA [internal]
59 *
60 * NOTES
61 * exported by ordinal
62 * return value points to the first char after the dot
63 */
64 static LPSTR PathGetExtensionA(LPCSTR lpszPath)
65 {
66 TRACE("(%s)\n",lpszPath);
67
68 lpszPath = PathFindExtensionA(lpszPath);
69 return (LPSTR)(*lpszPath?(lpszPath+1):lpszPath);
70 }
71
72 /*************************************************************************
73 * PathGetExtensionW [internal]
74 */
75 static LPWSTR PathGetExtensionW(LPCWSTR lpszPath)
76 {
77 TRACE("(%s)\n",debugstr_w(lpszPath));
78
79 lpszPath = PathFindExtensionW(lpszPath);
80 return (LPWSTR)(*lpszPath?(lpszPath+1):lpszPath);
81 }
82
83 /*************************************************************************
84 * SHPathGetExtension [SHELL32.158]
85 */
86 EXTERN_C LPVOID WINAPI SHPathGetExtensionW(LPCWSTR lpszPath, DWORD void1, DWORD void2)
87 {
88 return PathGetExtensionW(lpszPath);
89 }
90
91 /*************************************************************************
92 * PathRemoveFileSpec [SHELL32.35]
93 */
94 BOOL WINAPI PathRemoveFileSpecAW(LPVOID lpszPath)
95 {
96 if (SHELL_OsIsUnicode())
97 return PathRemoveFileSpecW((LPWSTR)lpszPath);
98 return PathRemoveFileSpecA((LPSTR)lpszPath);
99 }
100
101 /*
102 Path Manipulations
103 */
104
105 /*************************************************************************
106 * PathGetShortPathA [internal]
107 */
108 static void PathGetShortPathA(LPSTR pszPath)
109 {
110 CHAR path[MAX_PATH];
111
112 TRACE("%s\n", pszPath);
113
114 if (GetShortPathNameA(pszPath, path, MAX_PATH))
115 {
116 lstrcpyA(pszPath, path);
117 }
118 }
119
120 /*************************************************************************
121 * PathGetShortPathW [internal]
122 */
123 static void PathGetShortPathW(LPWSTR pszPath)
124 {
125 WCHAR path[MAX_PATH];
126
127 TRACE("%s\n", debugstr_w(pszPath));
128
129 if (GetShortPathNameW(pszPath, path, MAX_PATH))
130 {
131 wcscpy(pszPath, path);
132 }
133 }
134
135 /*************************************************************************
136 * PathGetShortPath [SHELL32.92]
137 */
138 EXTERN_C VOID WINAPI PathGetShortPathAW(LPVOID pszPath)
139 {
140 if(SHELL_OsIsUnicode())
141 PathGetShortPathW((LPWSTR)pszPath);
142 PathGetShortPathA((LPSTR)pszPath);
143 }
144
145 /*
146 ########## Path Testing ##########
147 */
148
149 /*************************************************************************
150 * PathIsRoot [SHELL32.29]
151 */
152 BOOL WINAPI PathIsRootAW(LPCVOID lpszPath)
153 {
154 if (SHELL_OsIsUnicode())
155 return PathIsRootW((LPWSTR)lpszPath);
156 return PathIsRootA((LPSTR)lpszPath);
157 }
158
159 /*************************************************************************
160 * PathIsExeA [internal]
161 */
162 static BOOL PathIsExeA (LPCSTR lpszPath)
163 {
164 LPCSTR lpszExtension = PathGetExtensionA(lpszPath);
165 int i;
166 static const char * const lpszExtensions[] =
167 {"exe", "com", "pif", "cmd", "bat", "scf", "scr", NULL };
168
169 TRACE("path=%s\n",lpszPath);
170
171 for(i=0; lpszExtensions[i]; i++)
172 if (!lstrcmpiA(lpszExtension,lpszExtensions[i])) return TRUE;
173
174 return FALSE;
175 }
176
177 /*************************************************************************
178 * PathIsExeW [internal]
179 */
180 BOOL PathIsExeW (LPCWSTR lpszPath)
181 {
182 LPCWSTR lpszExtension = PathGetExtensionW(lpszPath);
183 int i;
184 static const WCHAR lpszExtensions[][4] =
185 {{'e','x','e','\0'}, {'c','o','m','\0'}, {'p','i','f','\0'},
186 {'c','m','d','\0'}, {'b','a','t','\0'}, {'s','c','f','\0'},
187 {'s','c','r','\0'}, {'\0'} };
188
189 TRACE("path=%s\n",debugstr_w(lpszPath));
190
191 for(i=0; lpszExtensions[i][0]; i++)
192 if (!strcmpiW(lpszExtension,lpszExtensions[i])) return TRUE;
193
194 return FALSE;
195 }
196
197 /*************************************************************************
198 * PathIsExe [SHELL32.43]
199 */
200 BOOL WINAPI PathIsExeAW (LPCVOID path)
201 {
202 if (SHELL_OsIsUnicode())
203 return PathIsExeW ((LPWSTR)path);
204 return PathIsExeA((LPSTR)path);
205 }
206
207 /*************************************************************************
208 * PathFileExists [SHELL32.45]
209 */
210 BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath)
211 {
212 if (SHELL_OsIsUnicode())
213 return PathFileExistsW ((LPWSTR)lpszPath);
214 return PathFileExistsA ((LPSTR)lpszPath);
215 }
216
217 /*************************************************************************
218 * PathIsSameRoot [SHELL32.650]
219 */
220 BOOL WINAPI PathIsSameRootAW(LPCVOID lpszPath1, LPCVOID lpszPath2)
221 {
222 if (SHELL_OsIsUnicode())
223 return PathIsSameRootW((LPCWSTR)lpszPath1, (LPCWSTR)lpszPath2);
224 return PathIsSameRootA((LPCSTR)lpszPath1, (LPCSTR)lpszPath2);
225 }
226
227 /*************************************************************************
228 * IsLFNDriveA [SHELL32.41]
229 */
230 EXTERN_C BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath)
231 {
232 DWORD fnlen;
233
234 if (!GetVolumeInformationA(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0))
235 return FALSE;
236 return fnlen > 12;
237 }
238
239 /*************************************************************************
240 * IsLFNDriveW [SHELL32.42]
241 */
242 EXTERN_C BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath)
243 {
244 DWORD fnlen;
245
246 if (!GetVolumeInformationW(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0))
247 return FALSE;
248 return fnlen > 12;
249 }
250
251 /*************************************************************************
252 * IsLFNDrive [SHELL32.119]
253 */
254 EXTERN_C BOOL WINAPI IsLFNDriveAW(LPCVOID lpszPath)
255 {
256 if (SHELL_OsIsUnicode())
257 return IsLFNDriveW((LPCWSTR)lpszPath);
258 return IsLFNDriveA((LPCSTR)lpszPath);
259 }
260
261 /*
262 ########## Creating Something Unique ##########
263 */
264 /*************************************************************************
265 * PathMakeUniqueNameA [internal]
266 */
267 static BOOL PathMakeUniqueNameA(
268 LPSTR lpszBuffer,
269 DWORD dwBuffSize,
270 LPCSTR lpszShortName,
271 LPCSTR lpszLongName,
272 LPCSTR lpszPathName)
273 {
274 FIXME("%p %u %s %s %s stub\n",
275 lpszBuffer, dwBuffSize, debugstr_a(lpszShortName),
276 debugstr_a(lpszLongName), debugstr_a(lpszPathName));
277 return TRUE;
278 }
279
280 /*************************************************************************
281 * PathMakeUniqueNameW [internal]
282 */
283 static BOOL PathMakeUniqueNameW(
284 LPWSTR lpszBuffer,
285 DWORD dwBuffSize,
286 LPCWSTR lpszShortName,
287 LPCWSTR lpszLongName,
288 LPCWSTR lpszPathName)
289 {
290 FIXME("%p %u %s %s %s stub\n",
291 lpszBuffer, dwBuffSize, debugstr_w(lpszShortName),
292 debugstr_w(lpszLongName), debugstr_w(lpszPathName));
293 return TRUE;
294 }
295
296 /*************************************************************************
297 * PathMakeUniqueName [SHELL32.47]
298 */
299 BOOL WINAPI PathMakeUniqueNameAW(
300 LPVOID lpszBuffer,
301 DWORD dwBuffSize,
302 LPCVOID lpszShortName,
303 LPCVOID lpszLongName,
304 LPCVOID lpszPathName)
305 {
306 if (SHELL_OsIsUnicode())
307 return PathMakeUniqueNameW((LPWSTR)lpszBuffer, dwBuffSize, (LPCWSTR)lpszShortName, (LPCWSTR)lpszLongName, (LPCWSTR)lpszPathName);
308 return PathMakeUniqueNameA((LPSTR)lpszBuffer, dwBuffSize, (LPCSTR)lpszShortName, (LPCSTR)lpszLongName, (LPCSTR)lpszPathName);
309 }
310
311 /*************************************************************************
312 * PathYetAnotherMakeUniqueName [SHELL32.75]
313 *
314 * NOTES
315 * exported by ordinal
316 */
317 BOOL WINAPI PathYetAnotherMakeUniqueName(
318 LPWSTR lpszBuffer,
319 LPCWSTR lpszPathName,
320 LPCWSTR lpszShortName,
321 LPCWSTR lpszLongName)
322 {
323 FIXME("(%p, %s, %s ,%s):stub.\n",
324 lpszBuffer, debugstr_w(lpszPathName), debugstr_w(lpszShortName), debugstr_w(lpszLongName));
325 return TRUE;
326 }
327
328
329 /*
330 ########## cleaning and resolving paths ##########
331 */
332
333 /*************************************************************************
334 * PathCleanupSpec [SHELL32.171]
335 *
336 * lpszFile is changed in place.
337 */
338 int WINAPI PathCleanupSpec( LPCWSTR lpszPathW, LPWSTR lpszFileW )
339 {
340 int i = 0;
341 DWORD rc = 0;
342 int length = 0;
343
344 if (SHELL_OsIsUnicode())
345 {
346 LPWSTR p = lpszFileW;
347
348 TRACE("Cleanup %s\n",debugstr_w(lpszFileW));
349
350 if (lpszPathW)
351 length = wcslen(lpszPathW);
352
353 while (*p)
354 {
355 int gct = PathGetCharTypeW(*p);
356 if (gct == GCT_INVALID || gct == GCT_WILD || gct == GCT_SEPARATOR)
357 {
358 lpszFileW[i]='-';
359 rc |= PCS_REPLACEDCHAR;
360 }
361 else
362 lpszFileW[i]=*p;
363 i++;
364 p++;
365 if (length + i == MAX_PATH)
366 {
367 rc |= PCS_FATAL | PCS_PATHTOOLONG;
368 break;
369 }
370 }
371 lpszFileW[i]=0;
372 }
373 else
374 {
375 LPSTR lpszFileA = (LPSTR)lpszFileW;
376 LPCSTR lpszPathA = (LPCSTR)lpszPathW;
377 LPSTR p = lpszFileA;
378
379 TRACE("Cleanup %s\n",debugstr_a(lpszFileA));
380
381 if (lpszPathA)
382 length = strlen(lpszPathA);
383
384 while (*p)
385 {
386 int gct = PathGetCharTypeA(*p);
387 if (gct == GCT_INVALID || gct == GCT_WILD || gct == GCT_SEPARATOR)
388 {
389 lpszFileA[i]='-';
390 rc |= PCS_REPLACEDCHAR;
391 }
392 else
393 lpszFileA[i]=*p;
394 i++;
395 p++;
396 if (length + i == MAX_PATH)
397 {
398 rc |= PCS_FATAL | PCS_PATHTOOLONG;
399 break;
400 }
401 }
402 lpszFileA[i]=0;
403 }
404 return rc;
405 }
406
407 /*************************************************************************
408 * PathQualifyA [SHELL32]
409 */
410 static BOOL PathQualifyA(LPCSTR pszPath)
411 {
412 FIXME("%s\n",pszPath);
413 return 0;
414 }
415
416 /*************************************************************************
417 * PathQualifyW [SHELL32]
418 */
419 static BOOL PathQualifyW(LPCWSTR pszPath)
420 {
421 FIXME("%s\n",debugstr_w(pszPath));
422 return 0;
423 }
424
425 /*************************************************************************
426 * PathQualify [SHELL32.49]
427 */
428 BOOL WINAPI PathQualifyAW(LPCVOID pszPath)
429 {
430 if (SHELL_OsIsUnicode())
431 return PathQualifyW((LPCWSTR)pszPath);
432 return PathQualifyA((LPCSTR)pszPath);
433 }
434
435 /*************************************************************************
436 * PathResolveA [SHELL32.51]
437 */
438 static BOOL PathResolveA(
439 LPSTR lpszPath,
440 LPCSTR *alpszPaths,
441 DWORD dwFlags)
442 {
443 FIXME("(%s,%p,0x%08x),stub!\n",
444 lpszPath, *alpszPaths, dwFlags);
445 return 0;
446 }
447
448 /*************************************************************************
449 * PathResolveW [SHELL32]
450 */
451 static BOOL PathResolveW(
452 LPWSTR lpszPath,
453 LPCWSTR *alpszPaths,
454 DWORD dwFlags)
455 {
456 FIXME("(%s,%p,0x%08x),stub!\n",
457 debugstr_w(lpszPath), debugstr_w(*alpszPaths), dwFlags);
458 return 0;
459 }
460
461 /*************************************************************************
462 * PathResolve [SHELL32.51]
463 */
464 BOOL WINAPI PathResolveAW(
465 LPVOID lpszPath,
466 LPCVOID *alpszPaths,
467 DWORD dwFlags)
468 {
469 if (SHELL_OsIsUnicode())
470 return PathResolveW((LPWSTR)lpszPath, (LPCWSTR *)alpszPaths, dwFlags);
471 return PathResolveA((LPSTR)lpszPath, (LPCSTR *)alpszPaths, dwFlags);
472 }
473
474 /*************************************************************************
475 * PathProcessCommandA [SHELL32.653]
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) wcscpy(lpszBuff, lpszPath);
503 return wcslen(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((LPCWSTR)lpszPath, (LPWSTR)lpszBuff, dwBuffSize, dwFlags);
517 return PathProcessCommandA((LPCSTR)lpszPath, (LPSTR)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 static const WCHAR CacheW[] = {'C','a','c','h','e','\0'};
528 static const WCHAR CD_BurningW[] = {'C','D',' ','B','u','r','n','i','n','g','\0'};
529 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'};
530 static const WCHAR Common_AppDataW[] = {'C','o','m','m','o','n',' ','A','p','p','D','a','t','a','\0'};
531 static const WCHAR Common_DesktopW[] = {'C','o','m','m','o','n',' ','D','e','s','k','t','o','p','\0'};
532 static const WCHAR Common_DocumentsW[] = {'C','o','m','m','o','n',' ','D','o','c','u','m','e','n','t','s','\0'};
533 static const WCHAR CommonFilesDirW[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r','\0'};
534 static const WCHAR CommonMusicW[] = {'C','o','m','m','o','n','M','u','s','i','c','\0'};
535 static const WCHAR CommonPicturesW[] = {'C','o','m','m','o','n','P','i','c','t','u','r','e','s','\0'};
536 static const WCHAR Common_ProgramsW[] = {'C','o','m','m','o','n',' ','P','r','o','g','r','a','m','s','\0'};
537 static const WCHAR Common_StartUpW[] = {'C','o','m','m','o','n',' ','S','t','a','r','t','U','p','\0'};
538 static const WCHAR Common_Start_MenuW[] = {'C','o','m','m','o','n',' ','S','t','a','r','t',' ','M','e','n','u','\0'};
539 static const WCHAR Common_TemplatesW[] = {'C','o','m','m','o','n',' ','T','e','m','p','l','a','t','e','s','\0'};
540 static const WCHAR CommonVideoW[] = {'C','o','m','m','o','n','V','i','d','e','o','\0'};
541 static const WCHAR CookiesW[] = {'C','o','o','k','i','e','s','\0'};
542 static const WCHAR DesktopW[] = {'D','e','s','k','t','o','p','\0'};
543 static const WCHAR FavoritesW[] = {'F','a','v','o','r','i','t','e','s','\0'};
544 static const WCHAR FontsW[] = {'F','o','n','t','s','\0'};
545 static const WCHAR HistoryW[] = {'H','i','s','t','o','r','y','\0'};
546 static const WCHAR Local_AppDataW[] = {'L','o','c','a','l',' ','A','p','p','D','a','t','a','\0'};
547 static const WCHAR My_MusicW[] = {'M','y',' ','M','u','s','i','c','\0'};
548 static const WCHAR My_PicturesW[] = {'M','y',' ','P','i','c','t','u','r','e','s','\0'};
549 static const WCHAR My_VideoW[] = {'M','y',' ','V','i','d','e','o','\0'};
550 static const WCHAR NetHoodW[] = {'N','e','t','H','o','o','d','\0'};
551 static const WCHAR PersonalW[] = {'P','e','r','s','o','n','a','l','\0'};
552 static const WCHAR PrintHoodW[] = {'P','r','i','n','t','H','o','o','d','\0'};
553 static const WCHAR ProgramFilesDirW[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r','\0'};
554 static const WCHAR ProgramsW[] = {'P','r','o','g','r','a','m','s','\0'};
555 static const WCHAR RecentW[] = {'R','e','c','e','n','t','\0'};
556 static const WCHAR ResourcesW[] = {'R','e','s','o','u','r','c','e','s','\0'};
557 static const WCHAR SendToW[] = {'S','e','n','d','T','o','\0'};
558 static const WCHAR StartUpW[] = {'S','t','a','r','t','U','p','\0'};
559 static const WCHAR Start_MenuW[] = {'S','t','a','r','t',' ','M','e','n','u','\0'};
560 static const WCHAR TemplatesW[] = {'T','e','m','p','l','a','t','e','s','\0'};
561 static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t','\0'};
562 static const WCHAR AllUsersProfileW[] = {'%','A','L','L','U','S','E','R','S','P','R','O','F','I','L','E','%','\0'};
563 static const WCHAR UserProfileW[] = {'%','U','S','E','R','P','R','O','F','I','L','E','%','\0'};
564 static const WCHAR SystemDriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%','\0'};
565 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};
566 static const WCHAR ProfilesDirectoryW[] = {'P','r','o','f','i','l','e','s','D','i','r','e','c','t','o','r','y',0};
567 static const WCHAR AllUsersProfileValueW[] = {'A','l','l','U','s','e','r','s','P','r','o','f','i','l','e','\0'};
568 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'};
569 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'};
570 /* This defaults to L"Documents and Settings" on Windows 2000/XP, but we're
571 * acting more Windows 9x-like for now.
572 */
573 static const WCHAR szDefaultProfileDirW[] = {'p','r','o','f','i','l','e','s','\0'};
574 static const WCHAR AllUsersW[] = {'A','l','l',' ','U','s','e','r','s','\0'};
575
576 typedef enum _CSIDL_Type {
577 CSIDL_Type_User,
578 CSIDL_Type_AllUsers,
579 CSIDL_Type_CurrVer,
580 CSIDL_Type_Disallowed,
581 CSIDL_Type_NonExistent,
582 CSIDL_Type_WindowsPath,
583 CSIDL_Type_SystemPath,
584 } CSIDL_Type;
585
586 typedef struct
587 {
588 CSIDL_Type type;
589 LPCWSTR szValueName;
590 LPCWSTR szDefaultPath; /* fallback string or resource ID */
591 } CSIDL_DATA;
592
593 static const CSIDL_DATA CSIDL_Data[] =
594 {
595 { /* 0x00 - CSIDL_DESKTOP */
596 CSIDL_Type_User,
597 DesktopW,
598 MAKEINTRESOURCEW(IDS_DESKTOPDIRECTORY)
599 },
600 { /* 0x01 - CSIDL_INTERNET */
601 CSIDL_Type_Disallowed,
602 NULL,
603 NULL
604 },
605 { /* 0x02 - CSIDL_PROGRAMS */
606 CSIDL_Type_User,
607 ProgramsW,
608 MAKEINTRESOURCEW(IDS_PROGRAMS)
609 },
610 { /* 0x03 - CSIDL_CONTROLS (.CPL files) */
611 CSIDL_Type_SystemPath,
612 NULL,
613 NULL
614 },
615 { /* 0x04 - CSIDL_PRINTERS */
616 CSIDL_Type_SystemPath,
617 NULL,
618 NULL
619 },
620 { /* 0x05 - CSIDL_PERSONAL */
621 CSIDL_Type_User,
622 PersonalW,
623 MAKEINTRESOURCEW(IDS_PERSONAL)
624 },
625 { /* 0x06 - CSIDL_FAVORITES */
626 CSIDL_Type_User,
627 FavoritesW,
628 MAKEINTRESOURCEW(IDS_FAVORITES)
629 },
630 { /* 0x07 - CSIDL_STARTUP */
631 CSIDL_Type_User,
632 StartUpW,
633 MAKEINTRESOURCEW(IDS_STARTUP)
634 },
635 { /* 0x08 - CSIDL_RECENT */
636 CSIDL_Type_User,
637 RecentW,
638 MAKEINTRESOURCEW(IDS_RECENT)
639 },
640 { /* 0x09 - CSIDL_SENDTO */
641 CSIDL_Type_User,
642 SendToW,
643 MAKEINTRESOURCEW(IDS_SENDTO)
644 },
645 { /* 0x0a - CSIDL_BITBUCKET - Recycle Bin */
646 CSIDL_Type_Disallowed,
647 NULL,
648 NULL,
649 },
650 { /* 0x0b - CSIDL_STARTMENU */
651 CSIDL_Type_User,
652 Start_MenuW,
653 MAKEINTRESOURCEW(IDS_STARTMENU)
654 },
655 { /* 0x0c - CSIDL_MYDOCUMENTS */
656 CSIDL_Type_Disallowed, /* matches WinXP--can't get its path */
657 NULL,
658 NULL
659 },
660 { /* 0x0d - CSIDL_MYMUSIC */
661 CSIDL_Type_User,
662 My_MusicW,
663 MAKEINTRESOURCEW(IDS_MYMUSIC)
664 },
665 { /* 0x0e - CSIDL_MYVIDEO */
666 CSIDL_Type_User,
667 My_VideoW,
668 MAKEINTRESOURCEW(IDS_MYVIDEO)
669 },
670 { /* 0x0f - unassigned */
671 CSIDL_Type_Disallowed,
672 NULL,
673 NULL,
674 },
675 { /* 0x10 - CSIDL_DESKTOPDIRECTORY */
676 CSIDL_Type_User,
677 DesktopW,
678 MAKEINTRESOURCEW(IDS_DESKTOPDIRECTORY)
679 },
680 { /* 0x11 - CSIDL_DRIVES */
681 CSIDL_Type_Disallowed,
682 NULL,
683 NULL,
684 },
685 { /* 0x12 - CSIDL_NETWORK */
686 CSIDL_Type_Disallowed,
687 NULL,
688 NULL,
689 },
690 { /* 0x13 - CSIDL_NETHOOD */
691 CSIDL_Type_User,
692 NetHoodW,
693 MAKEINTRESOURCEW(IDS_NETHOOD)
694 },
695 { /* 0x14 - CSIDL_FONTS */
696 CSIDL_Type_WindowsPath,
697 FontsW,
698 FontsW
699 },
700 { /* 0x15 - CSIDL_TEMPLATES */
701 CSIDL_Type_User,
702 TemplatesW,
703 MAKEINTRESOURCEW(IDS_TEMPLATES)
704 },
705 { /* 0x16 - CSIDL_COMMON_STARTMENU */
706 CSIDL_Type_AllUsers,
707 Common_Start_MenuW,
708 MAKEINTRESOURCEW(IDS_STARTMENU)
709 },
710 { /* 0x17 - CSIDL_COMMON_PROGRAMS */
711 CSIDL_Type_AllUsers,
712 Common_ProgramsW,
713 MAKEINTRESOURCEW(IDS_PROGRAMS)
714 },
715 { /* 0x18 - CSIDL_COMMON_STARTUP */
716 CSIDL_Type_AllUsers,
717 Common_StartUpW,
718 MAKEINTRESOURCEW(IDS_STARTUP)
719 },
720 { /* 0x19 - CSIDL_COMMON_DESKTOPDIRECTORY */
721 CSIDL_Type_AllUsers,
722 Common_DesktopW,
723 MAKEINTRESOURCEW(IDS_DESKTOP)
724 },
725 { /* 0x1a - CSIDL_APPDATA */
726 CSIDL_Type_User,
727 AppDataW,
728 MAKEINTRESOURCEW(IDS_APPDATA)
729 },
730 { /* 0x1b - CSIDL_PRINTHOOD */
731 CSIDL_Type_User,
732 PrintHoodW,
733 MAKEINTRESOURCEW(IDS_PRINTHOOD)
734 },
735 { /* 0x1c - CSIDL_LOCAL_APPDATA */
736 CSIDL_Type_User,
737 Local_AppDataW,
738 MAKEINTRESOURCEW(IDS_LOCAL_APPDATA)
739 },
740 { /* 0x1d - CSIDL_ALTSTARTUP */
741 CSIDL_Type_NonExistent,
742 NULL,
743 NULL
744 },
745 { /* 0x1e - CSIDL_COMMON_ALTSTARTUP */
746 CSIDL_Type_NonExistent,
747 NULL,
748 NULL
749 },
750 { /* 0x1f - CSIDL_COMMON_FAVORITES */
751 CSIDL_Type_AllUsers,
752 FavoritesW,
753 MAKEINTRESOURCEW(IDS_FAVORITES)
754 },
755 { /* 0x20 - CSIDL_INTERNET_CACHE */
756 CSIDL_Type_User,
757 CacheW,
758 MAKEINTRESOURCEW(IDS_INTERNET_CACHE)
759 },
760 { /* 0x21 - CSIDL_COOKIES */
761 CSIDL_Type_User,
762 CookiesW,
763 MAKEINTRESOURCEW(IDS_COOKIES)
764 },
765 { /* 0x22 - CSIDL_HISTORY */
766 CSIDL_Type_User,
767 HistoryW,
768 MAKEINTRESOURCEW(IDS_HISTORY)
769 },
770 { /* 0x23 - CSIDL_COMMON_APPDATA */
771 CSIDL_Type_AllUsers,
772 Common_AppDataW,
773 MAKEINTRESOURCEW(IDS_APPDATA)
774 },
775 { /* 0x24 - CSIDL_WINDOWS */
776 CSIDL_Type_WindowsPath,
777 NULL,
778 NULL
779 },
780 { /* 0x25 - CSIDL_SYSTEM */
781 CSIDL_Type_SystemPath,
782 NULL,
783 NULL
784 },
785 { /* 0x26 - CSIDL_PROGRAM_FILES */
786 CSIDL_Type_CurrVer,
787 ProgramFilesDirW,
788 MAKEINTRESOURCEW(IDS_PROGRAM_FILES)
789 },
790 { /* 0x27 - CSIDL_MYPICTURES */
791 CSIDL_Type_User,
792 My_PicturesW,
793 MAKEINTRESOURCEW(IDS_MYPICTURES)
794 },
795 { /* 0x28 - CSIDL_PROFILE */
796 CSIDL_Type_User,
797 NULL,
798 NULL
799 },
800 { /* 0x29 - CSIDL_SYSTEMX86 */
801 CSIDL_Type_NonExistent,
802 NULL,
803 NULL
804 },
805 { /* 0x2a - CSIDL_PROGRAM_FILESX86 */
806 CSIDL_Type_NonExistent,
807 NULL,
808 NULL
809 },
810 { /* 0x2b - CSIDL_PROGRAM_FILES_COMMON */
811 CSIDL_Type_CurrVer,
812 CommonFilesDirW,
813 MAKEINTRESOURCEW(IDS_PROGRAM_FILES_COMMON)
814 },
815 { /* 0x2c - CSIDL_PROGRAM_FILES_COMMONX86 */
816 CSIDL_Type_NonExistent,
817 NULL,
818 NULL
819 },
820 { /* 0x2d - CSIDL_COMMON_TEMPLATES */
821 CSIDL_Type_AllUsers,
822 Common_TemplatesW,
823 MAKEINTRESOURCEW(IDS_TEMPLATES)
824 },
825 { /* 0x2e - CSIDL_COMMON_DOCUMENTS */
826 CSIDL_Type_AllUsers,
827 Common_DocumentsW,
828 MAKEINTRESOURCEW(IDS_COMMON_DOCUMENTS)
829 },
830 { /* 0x2f - CSIDL_COMMON_ADMINTOOLS */
831 CSIDL_Type_AllUsers,
832 Common_Administrative_ToolsW,
833 MAKEINTRESOURCEW(IDS_ADMINTOOLS)
834 },
835 { /* 0x30 - CSIDL_ADMINTOOLS */
836 CSIDL_Type_User,
837 Administrative_ToolsW,
838 MAKEINTRESOURCEW(IDS_ADMINTOOLS)
839 },
840 { /* 0x31 - CSIDL_CONNECTIONS */
841 CSIDL_Type_Disallowed,
842 NULL,
843 NULL
844 },
845 { /* 0x32 - unassigned */
846 CSIDL_Type_Disallowed,
847 NULL,
848 NULL
849 },
850 { /* 0x33 - unassigned */
851 CSIDL_Type_Disallowed,
852 NULL,
853 NULL
854 },
855 { /* 0x34 - unassigned */
856 CSIDL_Type_Disallowed,
857 NULL,
858 NULL
859 },
860 { /* 0x35 - CSIDL_COMMON_MUSIC */
861 CSIDL_Type_AllUsers,
862 CommonMusicW,
863 MAKEINTRESOURCEW(IDS_COMMON_MUSIC)
864 },
865 { /* 0x36 - CSIDL_COMMON_PICTURES */
866 CSIDL_Type_AllUsers,
867 CommonPicturesW,
868 MAKEINTRESOURCEW(IDS_COMMON_PICTURES)
869 },
870 { /* 0x37 - CSIDL_COMMON_VIDEO */
871 CSIDL_Type_AllUsers,
872 CommonVideoW,
873 MAKEINTRESOURCEW(IDS_COMMON_VIDEO)
874 },
875 { /* 0x38 - CSIDL_RESOURCES */
876 CSIDL_Type_WindowsPath,
877 NULL,
878 ResourcesW
879 },
880 { /* 0x39 - CSIDL_RESOURCES_LOCALIZED */
881 CSIDL_Type_NonExistent,
882 NULL,
883 NULL
884 },
885 { /* 0x3a - CSIDL_COMMON_OEM_LINKS */
886 CSIDL_Type_NonExistent,
887 NULL,
888 NULL
889 },
890 { /* 0x3b - CSIDL_CDBURN_AREA */
891 CSIDL_Type_User,
892 CD_BurningW,
893 MAKEINTRESOURCEW(IDS_CDBURN_AREA)
894 },
895 { /* 0x3c unassigned */
896 CSIDL_Type_Disallowed,
897 NULL,
898 NULL
899 },
900 { /* 0x3d - CSIDL_COMPUTERSNEARME */
901 CSIDL_Type_Disallowed, /* FIXME */
902 NULL,
903 NULL
904 },
905 { /* 0x3e - CSIDL_PROFILES */
906 CSIDL_Type_Disallowed, /* oddly, this matches WinXP */
907 NULL,
908 NULL
909 }
910 };
911
912 /* Gets the value named value from the registry key
913 * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
914 * (or from rootKey\userPrefix\... if userPrefix is not NULL) into path, which
915 * is assumed to be MAX_PATH WCHARs in length.
916 * If it exists, expands the value and writes the expanded value to
917 * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
918 * Returns successful error code if the value was retrieved from the registry,
919 * and a failure otherwise.
920 */
921 static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix,
922 LPCWSTR value, LPWSTR path)
923 {
924 HRESULT hr;
925 WCHAR shellFolderPath[MAX_PATH], userShellFolderPath[MAX_PATH];
926 LPCWSTR pShellFolderPath, pUserShellFolderPath;
927 DWORD dwDisp, dwType, dwPathLen;
928 HKEY userShellFolderKey, shellFolderKey;
929
930 TRACE("%p,%s,%s,%p\n",rootKey, debugstr_w(userPrefix), debugstr_w(value),
931 path);
932
933 if (userPrefix)
934 {
935 wcscpy(shellFolderPath, userPrefix);
936 PathAddBackslashW(shellFolderPath);
937 wcscat(shellFolderPath, szSHFolders);
938 pShellFolderPath = shellFolderPath;
939 wcscpy(userShellFolderPath, userPrefix);
940 PathAddBackslashW(userShellFolderPath);
941 wcscat(userShellFolderPath, szSHUserFolders);
942 pUserShellFolderPath = userShellFolderPath;
943 }
944 else
945 {
946 pUserShellFolderPath = szSHUserFolders;
947 pShellFolderPath = szSHFolders;
948 }
949
950 if (RegCreateKeyExW(rootKey, pShellFolderPath, 0, NULL, 0, KEY_SET_VALUE,
951 NULL, &shellFolderKey, &dwDisp))
952 {
953 TRACE("Failed to create %s\n", debugstr_w(pShellFolderPath));
954 return E_FAIL;
955 }
956 if (RegCreateKeyExW(rootKey, pUserShellFolderPath, 0, NULL, 0,
957 KEY_QUERY_VALUE, NULL, &userShellFolderKey, &dwDisp))
958 {
959 TRACE("Failed to create %s\n",
960 debugstr_w(pUserShellFolderPath));
961 RegCloseKey(shellFolderKey);
962 return E_FAIL;
963 }
964
965 dwPathLen = MAX_PATH * sizeof(WCHAR);
966
967 if (!RegQueryValueExW(userShellFolderKey, value, NULL, &dwType,
968 (LPBYTE)path, &dwPathLen) && (dwType == REG_EXPAND_SZ || dwType == REG_SZ))
969 {
970 LONG ret;
971
972 dwPathLen /= sizeof(WCHAR);
973
974 path[dwPathLen] = '\0';
975 if (dwType == REG_EXPAND_SZ && path[0] == '%')
976 {
977 WCHAR szTemp[MAX_PATH];
978
979 dwPathLen = ExpandEnvironmentStringsW(path, szTemp, MAX_PATH);
980 lstrcpynW(path, szTemp, dwPathLen);
981 }
982
983 ret = RegSetValueExW(shellFolderKey, value, 0, REG_SZ, (LPBYTE)path, dwPathLen * sizeof(WCHAR));
984 if (ret != ERROR_SUCCESS)
985 hr = HRESULT_FROM_WIN32(ret);
986 else
987 hr = S_OK;
988 }
989 else
990 hr = E_FAIL;
991
992 RegCloseKey(shellFolderKey);
993 RegCloseKey(userShellFolderKey);
994 TRACE("returning 0x%08x\n", hr);
995 return hr;
996 }
997
998 /* Gets a 'semi-expanded' default value of the CSIDL with index folder into
999 * pszPath, based on the entries in CSIDL_Data. By semi-expanded, I mean:
1000 * - The entry's szDefaultPath may be either a string value or an integer
1001 * resource identifier. In the latter case, the string value of the resource
1002 * is written.
1003 * - Depending on the entry's type, the path may begin with an (unexpanded)
1004 * environment variable name. The caller is responsible for expanding
1005 * environment strings if so desired.
1006 * The types that are prepended with environment variables are:
1007 * CSIDL_Type_User: %USERPROFILE%
1008 * CSIDL_Type_AllUsers: %ALLUSERSPROFILE%
1009 * CSIDL_Type_CurrVer: %SystemDrive%
1010 * (Others might make sense too, but as yet are unneeded.)
1011 */
1012 static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath)
1013 {
1014 DWORD dwSize;
1015 HRESULT hr;
1016 HKEY hKey;
1017 WCHAR resourcePath[MAX_PATH];
1018 LPCWSTR pDefaultPath = NULL;
1019
1020 TRACE("0x%02x,%p\n", folder, pszPath);
1021
1022 if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0]))
1023 return E_INVALIDARG;
1024 if (!pszPath)
1025 return E_INVALIDARG;
1026
1027
1028 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
1029 {
1030 /* FIXME assume MAX_PATH size */
1031 dwSize = MAX_PATH * sizeof(WCHAR);
1032 if (RegQueryValueExW(hKey, CSIDL_Data[folder].szValueName, NULL, NULL, (LPBYTE)pszPath, &dwSize) == ERROR_SUCCESS)
1033 {
1034 RegCloseKey(hKey);
1035 return S_OK;
1036 }
1037 RegCloseKey(hKey);
1038 }
1039
1040 if (CSIDL_Data[folder].szDefaultPath &&
1041 IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath))
1042 {
1043 if (LoadStringW(shell32_hInstance,
1044 LOWORD(CSIDL_Data[folder].szDefaultPath), resourcePath, MAX_PATH))
1045 {
1046 hr = S_OK;
1047 pDefaultPath = resourcePath;
1048 }
1049 else
1050 {
1051 FIXME("(%d,%s), LoadString failed, missing translation?\n", folder,
1052 debugstr_w(pszPath));
1053 hr = E_FAIL;
1054 }
1055 }
1056 else
1057 {
1058 hr = S_OK;
1059 pDefaultPath = CSIDL_Data[folder].szDefaultPath;
1060 }
1061 if (SUCCEEDED(hr))
1062 {
1063 switch (CSIDL_Data[folder].type)
1064 {
1065 case CSIDL_Type_User:
1066 wcscpy(pszPath, UserProfileW);
1067 break;
1068 case CSIDL_Type_AllUsers:
1069 wcscpy(pszPath, AllUsersProfileW);
1070 break;
1071 case CSIDL_Type_CurrVer:
1072 wcscpy(pszPath, SystemDriveW);
1073 break;
1074 default:
1075 ; /* no corresponding env. var, do nothing */
1076 }
1077 if (pDefaultPath)
1078 {
1079 PathAddBackslashW(pszPath);
1080 wcscat(pszPath, pDefaultPath);
1081 }
1082 }
1083 TRACE("returning 0x%08x\n", hr);
1084 return hr;
1085 }
1086
1087 /* Gets the (unexpanded) value of the folder with index folder into pszPath.
1088 * The folder's type is assumed to be CSIDL_Type_CurrVer. Its default value
1089 * can be overridden in the HKLM\\szCurrentVersion key.
1090 * If dwFlags has SHGFP_TYPE_DEFAULT set or if the value isn't overridden in
1091 * the registry, uses _SHGetDefaultValue to get the value.
1092 */
1093 static HRESULT _SHGetCurrentVersionPath(DWORD dwFlags, BYTE folder,
1094 LPWSTR pszPath)
1095 {
1096 HRESULT hr;
1097
1098 TRACE("0x%08x,0x%02x,%p\n", dwFlags, folder, pszPath);
1099
1100 if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0]))
1101 return E_INVALIDARG;
1102 if (CSIDL_Data[folder].type != CSIDL_Type_CurrVer)
1103 return E_INVALIDARG;
1104 if (!pszPath)
1105 return E_INVALIDARG;
1106
1107 if (dwFlags & SHGFP_TYPE_DEFAULT)
1108 hr = _SHGetDefaultValue(folder, pszPath);
1109 else
1110 {
1111 HKEY hKey;
1112 DWORD dwDisp;
1113
1114 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szCurrentVersion, 0,
1115 NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, &dwDisp))
1116 hr = E_FAIL;
1117 else
1118 {
1119 DWORD dwType, dwPathLen = MAX_PATH * sizeof(WCHAR);
1120
1121 if (RegQueryValueExW(hKey, CSIDL_Data[folder].szValueName, NULL,
1122 &dwType, (LPBYTE)pszPath, &dwPathLen) ||
1123 (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1124 {
1125 hr = _SHGetDefaultValue(folder, pszPath);
1126 dwType = REG_EXPAND_SZ;
1127 RegSetValueExW(hKey, CSIDL_Data[folder].szValueName, 0, dwType,
1128 (LPBYTE)pszPath, (wcslen(pszPath)+1)*sizeof(WCHAR));
1129 }
1130 else
1131 {
1132 pszPath[dwPathLen / sizeof(WCHAR)] = '\0';
1133 hr = S_OK;
1134 }
1135 RegCloseKey(hKey);
1136 }
1137 }
1138 TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath));
1139 return hr;
1140 }
1141
1142 /* Gets the user's path (unexpanded) for the CSIDL with index folder:
1143 * If SHGFP_TYPE_DEFAULT is set, calls _SHGetDefaultValue for it. Otherwise
1144 * calls _SHGetUserShellFolderPath for it. Where it looks depends on hToken:
1145 * - if hToken is -1, looks in HKEY_USERS\.Default
1146 * - otherwise looks first in HKEY_CURRENT_USER, followed by HKEY_LOCAL_MACHINE
1147 * if HKEY_CURRENT_USER doesn't contain any entries. If both fail, finally
1148 * calls _SHGetDefaultValue for it.
1149 */
1150 static HRESULT _SHGetUserProfilePath(HANDLE hToken, DWORD dwFlags, BYTE folder,
1151 LPWSTR pszPath)
1152 {
1153 HRESULT hr;
1154
1155 TRACE("%p,0x%08x,0x%02x,%p\n", hToken, dwFlags, folder, pszPath);
1156
1157 if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0]))
1158 return E_INVALIDARG;
1159
1160 if (CSIDL_Data[folder].type != CSIDL_Type_User)
1161 return E_INVALIDARG;
1162
1163 if (!pszPath)
1164 return E_INVALIDARG;
1165
1166 if (dwFlags & SHGFP_TYPE_DEFAULT)
1167 {
1168 hr = _SHGetDefaultValue(folder, pszPath);
1169 }
1170 else
1171 {
1172 LPWSTR userPrefix;
1173 HKEY hRootKey;
1174
1175 if (hToken == (HANDLE)-1)
1176 {
1177 /* Get the folder of the default user */
1178 hRootKey = HKEY_USERS;
1179 userPrefix = (LPWSTR)DefaultW;
1180 }
1181 else if(!hToken)
1182 {
1183 /* Get the folder of the current user */
1184 hRootKey = HKEY_CURRENT_USER;
1185 userPrefix = NULL;
1186 }
1187 else
1188 {
1189 /* Get the folder of the specified user */
1190 DWORD InfoLength;
1191 PTOKEN_USER UserInfo;
1192
1193 hRootKey = HKEY_USERS;
1194
1195 GetTokenInformation(hToken, TokenUser, NULL, 0, &InfoLength);
1196 UserInfo = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, InfoLength);
1197
1198 if(!GetTokenInformation(hToken, TokenUser, UserInfo, InfoLength, &InfoLength))
1199 {
1200 WARN("GetTokenInformation failed for %x!\n", hToken);
1201 HeapFree(GetProcessHeap(), 0, UserInfo);
1202 return E_FAIL;
1203 }
1204
1205 if(!ConvertSidToStringSidW(UserInfo->User.Sid, &userPrefix))
1206 {
1207 WARN("ConvertSidToStringSidW failed for %x!\n", hToken);
1208 HeapFree(GetProcessHeap(), 0, UserInfo);
1209 return E_FAIL;
1210 }
1211
1212 HeapFree(GetProcessHeap(), 0, UserInfo);
1213 }
1214
1215 hr = _SHGetUserShellFolderPath(hRootKey, userPrefix, CSIDL_Data[folder].szValueName, pszPath);
1216
1217 /* Free the memory allocated by ConvertSidToStringSidW */
1218 if(hToken && hToken != (HANDLE)-1)
1219 LocalFree(userPrefix);
1220
1221 if (FAILED(hr) && hRootKey != HKEY_LOCAL_MACHINE)
1222 hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, CSIDL_Data[folder].szValueName, pszPath);
1223
1224 if (FAILED(hr))
1225 hr = _SHGetDefaultValue(folder, pszPath);
1226 }
1227
1228 TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath));
1229 return hr;
1230 }
1231
1232 /* Gets the (unexpanded) path for the CSIDL with index folder. If dwFlags has
1233 * SHGFP_TYPE_DEFAULT set, calls _SHGetDefaultValue. Otherwise calls
1234 * _SHGetUserShellFolderPath for it, looking only in HKEY_LOCAL_MACHINE.
1235 * If this fails, falls back to _SHGetDefaultValue.
1236 */
1237 static HRESULT _SHGetAllUsersProfilePath(DWORD dwFlags, BYTE folder,
1238 LPWSTR pszPath)
1239 {
1240 HRESULT hr;
1241
1242 TRACE("0x%08x,0x%02x,%p\n", dwFlags, folder, pszPath);
1243
1244 if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0]))
1245 return E_INVALIDARG;
1246 if (CSIDL_Data[folder].type != CSIDL_Type_AllUsers)
1247 return E_INVALIDARG;
1248 if (!pszPath)
1249 return E_INVALIDARG;
1250
1251 if (dwFlags & SHGFP_TYPE_DEFAULT)
1252 hr = _SHGetDefaultValue(folder, pszPath);
1253 else
1254 {
1255 hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL,
1256 CSIDL_Data[folder].szValueName, pszPath);
1257 if (FAILED(hr))
1258 hr = _SHGetDefaultValue(folder, pszPath);
1259 }
1260 TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath));
1261 return hr;
1262 }
1263
1264 /*************************************************************************
1265 * SHGetFolderPathW [SHELL32.@]
1266 *
1267 * Convert nFolder to path.
1268 *
1269 * RETURNS
1270 * Success: S_OK
1271 * Failure: standard HRESULT error codes.
1272 *
1273 * NOTES
1274 * Most values can be overridden in either
1275 * HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
1276 * or in the same location in HKLM.
1277 * The "Shell Folders" registry key was used in NT4 and earlier systems.
1278 * Beginning with Windows 2000, the "User Shell Folders" key is used, so
1279 * changes made to it are made to the former key too. This synchronization is
1280 * done on-demand: not until someone requests the value of one of these paths
1281 * (by calling one of the SHGet functions) is the value synchronized.
1282 * Furthermore, the HKCU paths take precedence over the HKLM paths.
1283 */
1284 HRESULT WINAPI SHGetFolderPathW(
1285 HWND hwndOwner, /* [I] owner window */
1286 int nFolder, /* [I] CSIDL identifying the folder */
1287 HANDLE hToken, /* [I] access token */
1288 DWORD dwFlags, /* [I] which path to return */
1289 LPWSTR pszPath) /* [O] converted path */
1290 {
1291 HRESULT hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, NULL, pszPath);
1292 if(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
1293 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
1294 return hr;
1295 }
1296
1297 HRESULT WINAPI SHGetFolderPathAndSubDirA(
1298 HWND hwndOwner, /* [I] owner window */
1299 int nFolder, /* [I] CSIDL identifying the folder */
1300 HANDLE hToken, /* [I] access token */
1301 DWORD dwFlags, /* [I] which path to return */
1302 LPCSTR pszSubPath, /* [I] sub directory of the specified folder */
1303 LPSTR pszPath) /* [O] converted path */
1304 {
1305 int length;
1306 HRESULT hr = S_OK;
1307 LPWSTR pszSubPathW = NULL;
1308 LPWSTR pszPathW = NULL;
1309 TRACE("%08x,%08x,%s\n",nFolder, dwFlags, debugstr_w(pszSubPathW));
1310
1311 if(pszPath) {
1312 pszPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
1313 if(!pszPathW) {
1314 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
1315 goto cleanup;
1316 }
1317 }
1318 TRACE("%08x,%08x,%s\n",nFolder, dwFlags, debugstr_w(pszSubPathW));
1319
1320 /* SHGetFolderPathAndSubDirW does not distinguish if pszSubPath isn't
1321 * set (null), or an empty string.therefore call it without the parameter set
1322 * if pszSubPath is an empty string
1323 */
1324 if (pszSubPath && pszSubPath[0]) {
1325 length = MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, NULL, 0);
1326 pszSubPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, length * sizeof(WCHAR));
1327 if(!pszSubPathW) {
1328 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
1329 goto cleanup;
1330 }
1331 MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, pszSubPathW, length);
1332 }
1333
1334 hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, pszSubPathW, pszPathW);
1335
1336 if (SUCCEEDED(hr) && pszPath)
1337 WideCharToMultiByte(CP_ACP, 0, pszPathW, -1, pszPath, MAX_PATH, NULL, NULL);
1338
1339 cleanup:
1340 HeapFree(GetProcessHeap(), 0, pszPathW);
1341 HeapFree(GetProcessHeap(), 0, pszSubPathW);
1342 return hr;
1343 }
1344
1345 HRESULT WINAPI SHGetFolderPathAndSubDirW(
1346 HWND hwndOwner, /* [I] owner window */
1347 int nFolder, /* [I] CSIDL identifying the folder */
1348 HANDLE hToken, /* [I] access token */
1349 DWORD dwFlags, /* [I] which path to return */
1350 LPCWSTR pszSubPath,/* [I] sub directory of the specified folder */
1351 LPWSTR pszPath) /* [O] converted path */
1352 {
1353 HRESULT hr;
1354 WCHAR szBuildPath[MAX_PATH], szTemp[MAX_PATH];
1355 DWORD folder = nFolder & CSIDL_FOLDER_MASK; //FIXME
1356 CSIDL_Type type;
1357 int ret;
1358
1359 TRACE("%p,%p,nFolder=0x%04x,%s\n", hwndOwner,pszPath,nFolder,debugstr_w(pszSubPath));
1360
1361 /* Windows always NULL-terminates the resulting path regardless of success
1362 * or failure, so do so first
1363 */
1364 if (pszPath)
1365 *pszPath = '\0';
1366
1367 if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0]))
1368 return E_INVALIDARG;
1369 if ((SHGFP_TYPE_CURRENT != dwFlags) && (SHGFP_TYPE_DEFAULT != dwFlags))
1370 return E_INVALIDARG;
1371 szTemp[0] = 0;
1372 type = CSIDL_Data[folder].type;
1373 switch (type)
1374 {
1375 case CSIDL_Type_Disallowed:
1376 hr = E_INVALIDARG;
1377 break;
1378 case CSIDL_Type_NonExistent:
1379 hr = S_FALSE;
1380 break;
1381 case CSIDL_Type_WindowsPath:
1382 GetWindowsDirectoryW(szTemp, MAX_PATH);
1383 if (CSIDL_Data[folder].szDefaultPath &&
1384 !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) &&
1385 *CSIDL_Data[folder].szDefaultPath)
1386 {
1387 PathAddBackslashW(szTemp);
1388 wcscat(szTemp, CSIDL_Data[folder].szDefaultPath);
1389 }
1390 hr = S_OK;
1391 break;
1392 case CSIDL_Type_SystemPath:
1393 GetSystemDirectoryW(szTemp, MAX_PATH);
1394 if (CSIDL_Data[folder].szDefaultPath &&
1395 !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) &&
1396 *CSIDL_Data[folder].szDefaultPath)
1397 {
1398 PathAddBackslashW(szTemp);
1399 wcscat(szTemp, CSIDL_Data[folder].szDefaultPath);
1400 }
1401 hr = S_OK;
1402 break;
1403 case CSIDL_Type_CurrVer:
1404 hr = _SHGetCurrentVersionPath(dwFlags, folder, szTemp);
1405 break;
1406 case CSIDL_Type_User:
1407 hr = _SHGetUserProfilePath(hToken, dwFlags, folder, szTemp);
1408 break;
1409 case CSIDL_Type_AllUsers:
1410 hr = _SHGetAllUsersProfilePath(dwFlags, folder, szTemp);
1411 break;
1412 default:
1413 FIXME("bogus type %d, please fix\n", type);
1414 hr = E_INVALIDARG;
1415 break;
1416 }
1417
1418 /* Expand environment strings if necessary */
1419 if (*szTemp == '%')
1420 {
1421 DWORD ExpandRet = ExpandEnvironmentStringsW(szTemp, szBuildPath, MAX_PATH);
1422
1423 if (ExpandRet > MAX_PATH)
1424 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1425 else if (ExpandRet == 0)
1426 hr = HRESULT_FROM_WIN32(GetLastError());
1427 else
1428 hr = S_OK;
1429 }
1430 else
1431 {
1432 wcscpy(szBuildPath, szTemp);
1433 }
1434
1435 if (FAILED(hr)) goto end;
1436
1437 if(pszSubPath) {
1438 /* make sure the new path does not exceed th bufferlength
1439 * rememebr to backslash and the termination */
1440 if(MAX_PATH < (wcslen(szBuildPath) + wcslen(pszSubPath) + 2)) {
1441 hr = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
1442 goto end;
1443 }
1444 PathAppendW(szBuildPath, pszSubPath);
1445 PathRemoveBackslashW(szBuildPath);
1446 }
1447 /* Copy the path if it's available before we might return */
1448 if (SUCCEEDED(hr) && pszPath)
1449 wcscpy(pszPath, szBuildPath);
1450
1451 /* if we don't care about existing directories we are ready */
1452 if(nFolder & CSIDL_FLAG_DONT_VERIFY) goto end;
1453
1454 if (PathFileExistsW(szBuildPath)) goto end;
1455
1456 /* not existing but we are not allowed to create it. The return value
1457 * is verified against shell32 version 6.0.
1458 */
1459 if (!(nFolder & CSIDL_FLAG_CREATE))
1460 {
1461 hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1462 goto end;
1463 }
1464
1465 /* create directory/directories */
1466 ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, NULL);
1467 if (ret && ret != ERROR_ALREADY_EXISTS)
1468 {
1469 WARN("Failed to create directory %s.\n", debugstr_w(szBuildPath));
1470 hr = E_FAIL;
1471 goto end;
1472 }
1473
1474 TRACE("Created missing system directory %s\n", debugstr_w(szBuildPath));
1475 end:
1476 TRACE("returning 0x%08x (final path is %s)\n", hr, debugstr_w(szBuildPath));
1477 return hr;
1478 }
1479
1480 /*************************************************************************
1481 * SHGetFolderPathA [SHELL32.@]
1482 *
1483 * See SHGetFolderPathW.
1484 */
1485 HRESULT WINAPI SHGetFolderPathA(
1486 HWND hwndOwner,
1487 int nFolder,
1488 HANDLE hToken,
1489 DWORD dwFlags,
1490 LPSTR pszPath)
1491 {
1492 WCHAR szTemp[MAX_PATH];
1493 HRESULT hr;
1494
1495 TRACE("%p,%p,nFolder=0x%04x\n",hwndOwner,pszPath,nFolder);
1496
1497 if (pszPath)
1498 *pszPath = '\0';
1499 hr = SHGetFolderPathW(hwndOwner, nFolder, hToken, dwFlags, szTemp);
1500 if (SUCCEEDED(hr) && pszPath)
1501 WideCharToMultiByte(CP_ACP, 0, szTemp, -1, pszPath, MAX_PATH, NULL,
1502 NULL);
1503
1504 return hr;
1505 }
1506
1507 /* For each folder in folders, if its value has not been set in the registry,
1508 * calls _SHGetUserProfilePath or _SHGetAllUsersProfilePath (depending on the
1509 * folder's type) to get the unexpanded value first.
1510 * Writes the unexpanded value to User Shell Folders, and queries it with
1511 * SHGetFolderPathW to force the creation of the directory if it doesn't
1512 * already exist. SHGetFolderPathW also returns the expanded value, which
1513 * this then writes to Shell Folders.
1514 */
1515 static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken,
1516 LPCWSTR szUserShellFolderPath, LPCWSTR szShellFolderPath, const UINT folders[],
1517 UINT foldersLen)
1518 {
1519 UINT i;
1520 WCHAR path[MAX_PATH];
1521 HRESULT hr = S_OK;
1522 HKEY hUserKey = NULL, hKey = NULL;
1523 DWORD dwDisp, dwType, dwPathLen;
1524 LONG ret;
1525
1526 TRACE("%p,%p,%s,%p,%u\n", hRootKey, hToken,
1527 debugstr_w(szUserShellFolderPath), folders, foldersLen);
1528
1529 ret = RegCreateKeyExW(hRootKey, szUserShellFolderPath, 0, NULL, 0,
1530 KEY_ALL_ACCESS, NULL, &hUserKey, &dwDisp);
1531 if (ret)
1532 hr = HRESULT_FROM_WIN32(ret);
1533 else
1534 {
1535 ret = RegCreateKeyExW(hRootKey, szShellFolderPath, 0, NULL, 0,
1536 KEY_ALL_ACCESS, NULL, &hKey, &dwDisp);
1537 if (ret)
1538 hr = HRESULT_FROM_WIN32(ret);
1539 }
1540 for (i = 0; SUCCEEDED(hr) && i < foldersLen; i++)
1541 {
1542 dwPathLen = MAX_PATH * sizeof(WCHAR);
1543 if (RegQueryValueExW(hUserKey, CSIDL_Data[folders[i]].szValueName, NULL,
1544 &dwType, (LPBYTE)path, &dwPathLen) || (dwType != REG_SZ &&
1545 dwType != REG_EXPAND_SZ))
1546 {
1547 *path = '\0';
1548 if (CSIDL_Data[folders[i]].type == CSIDL_Type_User)
1549 _SHGetUserProfilePath(hToken, SHGFP_TYPE_DEFAULT, folders[i],
1550 path);
1551 else if (CSIDL_Data[folders[i]].type == CSIDL_Type_AllUsers)
1552 _SHGetAllUsersProfilePath(SHGFP_TYPE_DEFAULT, folders[i], path);
1553 else if (CSIDL_Data[folders[i]].type == CSIDL_Type_WindowsPath)
1554 GetWindowsDirectoryW(path, MAX_PATH);
1555 else
1556 hr = E_FAIL;
1557 if (*path)
1558 {
1559 ret = RegSetValueExW(hUserKey,
1560 CSIDL_Data[folders[i]].szValueName, 0, REG_EXPAND_SZ,
1561 (LPBYTE)path, (wcslen(path) + 1) * sizeof(WCHAR));
1562 if (ret)
1563 hr = HRESULT_FROM_WIN32(ret);
1564 else
1565 {
1566 // Don't fail if folder can't be created
1567 if (SUCCEEDED(SHGetFolderPathW(NULL, folders[i] | CSIDL_FLAG_CREATE,
1568 hToken, SHGFP_TYPE_DEFAULT, path)))
1569 {
1570 ret = RegSetValueExW(hKey, CSIDL_Data[folders[i]].szValueName, 0, REG_SZ,
1571 (LPBYTE)path, (wcslen(path) + 1) * sizeof(WCHAR));
1572 if (ret)
1573 hr = HRESULT_FROM_WIN32(ret);
1574 }
1575 }
1576 }
1577 }
1578 }
1579 if (hUserKey)
1580 RegCloseKey(hUserKey);
1581 if (hKey)
1582 RegCloseKey(hKey);
1583
1584 TRACE("returning 0x%08x\n", hr);
1585 return hr;
1586 }
1587
1588 static HRESULT _SHRegisterUserShellFolders(BOOL bDefault)
1589 {
1590 static const UINT folders[] = {
1591 CSIDL_PROGRAMS,
1592 CSIDL_PERSONAL,
1593 CSIDL_FAVORITES,
1594 CSIDL_APPDATA,
1595 CSIDL_STARTUP,
1596 CSIDL_RECENT,
1597 CSIDL_SENDTO,
1598 CSIDL_STARTMENU,
1599 CSIDL_MYMUSIC,
1600 CSIDL_MYVIDEO,
1601 CSIDL_DESKTOPDIRECTORY,
1602 CSIDL_NETHOOD,
1603 CSIDL_TEMPLATES,
1604 CSIDL_PRINTHOOD,
1605 CSIDL_LOCAL_APPDATA,
1606 CSIDL_INTERNET_CACHE,
1607 CSIDL_COOKIES,
1608 CSIDL_HISTORY,
1609 CSIDL_MYPICTURES,
1610 CSIDL_FONTS
1611 };
1612 WCHAR userShellFolderPath[MAX_PATH], shellFolderPath[MAX_PATH];
1613 LPCWSTR pUserShellFolderPath, pShellFolderPath;
1614 HRESULT hr = S_OK;
1615 HKEY hRootKey;
1616 HANDLE hToken;
1617
1618 TRACE("%s\n", bDefault ? "TRUE" : "FALSE");
1619 if (bDefault)
1620 {
1621 hToken = (HANDLE)-1;
1622 hRootKey = HKEY_USERS;
1623 wcscpy(userShellFolderPath, DefaultW);
1624 PathAddBackslashW(userShellFolderPath);
1625 wcscat(userShellFolderPath, szSHUserFolders);
1626 pUserShellFolderPath = userShellFolderPath;
1627 wcscpy(shellFolderPath, DefaultW);
1628 PathAddBackslashW(shellFolderPath);
1629 wcscat(shellFolderPath, szSHFolders);
1630 pShellFolderPath = shellFolderPath;
1631 }
1632 else
1633 {
1634 hToken = NULL;
1635 hRootKey = HKEY_CURRENT_USER;
1636 pUserShellFolderPath = szSHUserFolders;
1637 pShellFolderPath = szSHFolders;
1638 }
1639
1640 hr = _SHRegisterFolders(hRootKey, hToken, pUserShellFolderPath,
1641 pShellFolderPath, folders, sizeof(folders) / sizeof(folders[0]));
1642 TRACE("returning 0x%08x\n", hr);
1643 return hr;
1644 }
1645
1646 static HRESULT _SHRegisterCommonShellFolders(void)
1647 {
1648 static const UINT folders[] = {
1649 CSIDL_COMMON_STARTMENU,
1650 CSIDL_COMMON_PROGRAMS,
1651 CSIDL_COMMON_STARTUP,
1652 CSIDL_COMMON_DESKTOPDIRECTORY,
1653 CSIDL_COMMON_FAVORITES,
1654 CSIDL_COMMON_APPDATA,
1655 CSIDL_COMMON_TEMPLATES,
1656 CSIDL_COMMON_DOCUMENTS,
1657 };
1658 HRESULT hr;
1659
1660 TRACE("\n");
1661 hr = _SHRegisterFolders(HKEY_LOCAL_MACHINE, NULL, szSHUserFolders,
1662 szSHFolders, folders, sizeof(folders) / sizeof(folders[0]));
1663 TRACE("returning 0x%08x\n", hr);
1664 return hr;
1665 }
1666
1667 /* Register the default values in the registry, as some apps seem to depend
1668 * on their presence. The set registered was taken from Windows XP.
1669 */
1670 EXTERN_C HRESULT SHELL_RegisterShellFolders(void)
1671 {
1672 HRESULT hr;
1673
1674 hr = _SHRegisterUserShellFolders(TRUE);
1675 if (SUCCEEDED(hr))
1676 hr = _SHRegisterUserShellFolders(FALSE);
1677 if (SUCCEEDED(hr))
1678 hr = _SHRegisterCommonShellFolders();
1679 return hr;
1680 }
1681
1682 /*************************************************************************
1683 * SHGetSpecialFolderPathA [SHELL32.@]
1684 */
1685 BOOL WINAPI SHGetSpecialFolderPathA (
1686 HWND hwndOwner,
1687 LPSTR szPath,
1688 int nFolder,
1689 BOOL bCreate)
1690 {
1691 return (SHGetFolderPathA(
1692 hwndOwner,
1693 nFolder + (bCreate ? CSIDL_FLAG_CREATE : 0),
1694 NULL,
1695 0,
1696 szPath)) == S_OK ? TRUE : FALSE;
1697 }
1698
1699 /*************************************************************************
1700 * SHGetSpecialFolderPathW
1701 */
1702 BOOL WINAPI SHGetSpecialFolderPathW (
1703 HWND hwndOwner,
1704 LPWSTR szPath,
1705 int nFolder,
1706 BOOL bCreate)
1707 {
1708 return (SHGetFolderPathW(
1709 hwndOwner,
1710 nFolder + (bCreate ? CSIDL_FLAG_CREATE : 0),
1711 NULL,
1712 0,
1713 szPath)) == S_OK ? TRUE : FALSE;
1714 }
1715
1716 /*************************************************************************
1717 * SHGetFolderLocation [SHELL32.@]
1718 *
1719 * Gets the folder locations from the registry and creates a pidl.
1720 *
1721 * PARAMS
1722 * hwndOwner [I]
1723 * nFolder [I] CSIDL_xxxxx
1724 * hToken [I] token representing user, or NULL for current user, or -1 for
1725 * default user
1726 * dwReserved [I] must be zero
1727 * ppidl [O] PIDL of a special folder
1728 *
1729 * RETURNS
1730 * Success: S_OK
1731 * Failure: Standard OLE-defined error result, S_FALSE or E_INVALIDARG
1732 *
1733 * NOTES
1734 * Creates missing reg keys and directories.
1735 * Mostly forwards to SHGetFolderPathW, but a few values of nFolder return
1736 * virtual folders that are handled here.
1737 */
1738 HRESULT WINAPI SHGetFolderLocation(
1739 HWND hwndOwner,
1740 int nFolder,
1741 HANDLE hToken,
1742 DWORD dwReserved,
1743 LPITEMIDLIST *ppidl)
1744 {
1745 HRESULT hr = E_INVALIDARG;
1746
1747 TRACE("%p 0x%08x %p 0x%08x %p\n",
1748 hwndOwner, nFolder, hToken, dwReserved, ppidl);
1749
1750 if (!ppidl)
1751 return E_INVALIDARG;
1752 if (dwReserved)
1753 return E_INVALIDARG;
1754
1755 /* The virtual folders' locations are not user-dependent */
1756 *ppidl = NULL;
1757 switch (nFolder)
1758 {
1759 case CSIDL_DESKTOP:
1760 *ppidl = _ILCreateDesktop();
1761 break;
1762
1763 case CSIDL_PERSONAL:
1764 *ppidl = _ILCreateMyDocuments();
1765 break;
1766
1767 case CSIDL_INTERNET:
1768 *ppidl = _ILCreateIExplore();
1769 break;
1770
1771 case CSIDL_CONTROLS:
1772 *ppidl = _ILCreateControlPanel();
1773 break;
1774
1775 case CSIDL_PRINTERS:
1776 *ppidl = _ILCreatePrinters();
1777 break;
1778
1779 case CSIDL_BITBUCKET:
1780 *ppidl = _ILCreateBitBucket();
1781 break;
1782
1783 case CSIDL_DRIVES:
1784 *ppidl = _ILCreateMyComputer();
1785 break;
1786
1787 case CSIDL_NETWORK:
1788 *ppidl = _ILCreateNetwork();
1789 break;
1790
1791 default:
1792 {
1793 WCHAR szPath[MAX_PATH];
1794
1795 hr = SHGetFolderPathW(hwndOwner, nFolder, hToken,
1796 SHGFP_TYPE_CURRENT, szPath);
1797 if (SUCCEEDED(hr))
1798 {
1799 DWORD attributes=0;
1800
1801 TRACE("Value=%s\n", debugstr_w(szPath));
1802 hr = SHILCreateFromPathW(szPath, ppidl, &attributes);
1803 }
1804 else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
1805 {
1806 /* unlike SHGetFolderPath, SHGetFolderLocation in shell32
1807 * version 6.0 returns E_FAIL for nonexistent paths
1808 */
1809 hr = E_FAIL;
1810 }
1811 }
1812 }
1813 if(*ppidl)
1814 hr = NOERROR;
1815
1816 TRACE("-- (new pidl %p)\n",*ppidl);
1817 return hr;
1818 }
1819
1820 /*************************************************************************
1821 * SHGetSpecialFolderLocation [SHELL32.@]
1822 *
1823 * NOTES
1824 * In NT5, SHGetSpecialFolderLocation needs the <winntdir>/Recent
1825 * directory.
1826 */
1827 HRESULT WINAPI SHGetSpecialFolderLocation(
1828 HWND hwndOwner,
1829 INT nFolder,
1830 LPITEMIDLIST * ppidl)
1831 {
1832 HRESULT hr = E_INVALIDARG;
1833
1834 TRACE("(%p,0x%x,%p)\n", hwndOwner,nFolder,ppidl);
1835
1836 if (!ppidl)
1837 return E_INVALIDARG;
1838
1839 hr = SHGetFolderLocation(hwndOwner, nFolder, NULL, 0, ppidl);
1840 return hr;
1841 }