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