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