1 /*
2 * Path Functions
3 *
4 * Copyright 1998, 1999, 2000 Juergen Schmied
5 * Copyright 2004 Juan Lang
6 * Copyright 2018-2022 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 #include <assert.h>
44
45 #include <shlwapi_undoc.h>
46 #include <shellutils.h>
47
48 #include <userenv.h>
49
50 #include "pidl.h"
51 #include "shell32_main.h"
52 #include "shresdef.h"
53
54 #undef _WIN32_WINNT
55 #define _WIN32_WINNT _WIN32_WINNT_WS03
56
57 WINE_DEFAULT_DEBUG_CHANNEL(shell);
58
59 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
60
61 /* FIXME: Remove this */
62 typedef enum _NT_PRODUCT_TYPE
63 {
64 NtProductWinNt = 1,
65 NtProductLanManNt,
66 NtProductServer
67 } NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE;
68
69 /* FIXME: We cannot refresh the RtlGetNtProductType value before reboot. */
70 static BOOL
DoGetProductType(PNT_PRODUCT_TYPE ProductType)71 DoGetProductType(PNT_PRODUCT_TYPE ProductType)
72 {
73 HKEY hKey;
74 LONG error;
75 WCHAR szValue[9];
76 DWORD cbValue;
77 static DWORD s_dwProductType = 0;
78
79 if (s_dwProductType != 0)
80 {
81 *ProductType = s_dwProductType;
82 return TRUE;
83 }
84
85 *ProductType = NtProductServer;
86
87 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_READ, &hKey);
88 if (error)
89 return FALSE;
90
91 cbValue = sizeof(szValue);
92 error = RegGetValueW(hKey, NULL, L"ProductType", RRF_RT_REG_SZ, NULL, (PVOID)szValue, &cbValue);
93 if (!error)
94 {
95 if (lstrcmpW(szValue, L"WinNT") == 0)
96 *ProductType = NtProductWinNt;
97 else if (lstrcmpW(szValue, L"LanmanNT") == 0)
98 *ProductType = NtProductLanManNt;
99 }
100
101 s_dwProductType = *ProductType;
102
103 RegCloseKey(hKey);
104 return TRUE;
105 }
106
IsRemovableDrive(DWORD iDrive)107 BOOL APIENTRY IsRemovableDrive(DWORD iDrive)
108 {
109 WCHAR szRoot[] = L"C:\\";
110 assert(L'A' + iDrive <= L'Z');
111 szRoot[0] = (WCHAR)(L'A' + iDrive);
112 return GetDriveTypeW(szRoot) == DRIVE_REMOVABLE;
113 }
114
115 /*
116 ########## Combining and Constructing paths ##########
117 */
118
119 static BOOL WINAPI
PathSearchOnExtensionsW(_Inout_ LPWSTR pszPath,_In_opt_ LPCWSTR * ppszDirs,_In_ BOOL bDoSearch,_In_ DWORD dwWhich)120 PathSearchOnExtensionsW(
121 _Inout_ LPWSTR pszPath,
122 _In_opt_ LPCWSTR *ppszDirs,
123 _In_ BOOL bDoSearch,
124 _In_ DWORD dwWhich)
125 {
126 if (*PathFindExtensionW(pszPath) != 0)
127 return FALSE;
128
129 if (bDoSearch)
130 return PathFindOnPathExW(pszPath, ppszDirs, dwWhich);
131 else
132 return PathFileExistsDefExtW(pszPath, dwWhich);
133 }
134
135 #if (_WIN32_WINNT >= _WIN32_WINNT_WS03)
PathIsAbsoluteW(_In_ LPCWSTR path)136 static BOOL WINAPI PathIsAbsoluteW(_In_ LPCWSTR path)
137 {
138 return PathIsUNCW(path) || (PathGetDriveNumberW(path) != -1 && path[2] == L'\\');
139 }
140
PathMakeAbsoluteW(_Inout_ LPWSTR path)141 static BOOL WINAPI PathMakeAbsoluteW(_Inout_ LPWSTR path)
142 {
143 WCHAR path1[MAX_PATH];
144 DWORD cch;
145
146 if (path == NULL)
147 return FALSE;
148 cch = GetCurrentDirectoryW(_countof(path1), path1);
149 if (!cch || cch > _countof(path1))
150 return FALSE;
151 return (PathCombineW(path, path1, path) != NULL);
152 }
153 #endif
154
155 BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath);
156
157 static VOID WINAPI
PathQualifyExW(_Inout_ LPWSTR pszPath,_Inout_opt_ LPCWSTR pszDir,_In_ DWORD dwFlags)158 PathQualifyExW(_Inout_ LPWSTR pszPath, _Inout_opt_ LPCWSTR pszDir, _In_ DWORD dwFlags)
159 {
160 INT iDrive, cchPathLeft;
161 WCHAR szTemp[MAX_PATH], szRoot[MAX_PATH];
162 PWCHAR pchTemp = szTemp, pchPath;
163 BOOL bLFN;
164
165 TRACE("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszDir), dwFlags);
166
167 /* Save pszPath path into szTemp for rebuilding the path later */
168 if (FAILED(StringCchCopyW(szTemp, _countof(szTemp), pszPath)))
169 return;
170
171 /* Replace every '/' by '\' */
172 FixSlashesAndColonW(szTemp);
173
174 cchPathLeft = MAX_PATH;
175
176 /* Build the root-like path on pszPath, and set pchTemp */
177 if (!PathIsUNCW(szTemp))
178 {
179 /*
180 * Non-UNC path.
181 * Determine and normalize the root drive.
182 */
183 iDrive = PathGetDriveNumberW(szTemp);
184 if (iDrive == -1)
185 {
186 /*
187 * No drive was specified in the path. Try to find one from the
188 * optional directory (if this fails, fall back to the one of the
189 * Windows directory).
190 */
191 if (!pszDir || FAILED(StringCchCopyW(szRoot, _countof(szRoot), pszDir)))
192 {
193 /* pszDir was invalid or NULL. Fall back to the
194 * Windows directory and find its root. */
195 szRoot[0] = UNICODE_NULL;
196 GetWindowsDirectoryW(szRoot, _countof(szRoot));
197 iDrive = PathGetDriveNumberW(szRoot);
198 if (iDrive != -1)
199 PathBuildRootW(szRoot, iDrive);
200 }
201
202 if (szTemp[0] == L'\\')
203 {
204 PathStripToRootW(szRoot);
205 }
206 }
207 else
208 {
209 /*
210 * A drive is specified in the path, that can be either of the
211 * form 'C:\xxx' or of the form 'C:xxx' (relative path). Isolate
212 * the root part 'C:' and the rest of the path 'xxx' in pchTemp.
213 */
214 PathBuildRootW(szRoot, iDrive);
215 pchTemp += 2;
216 if (*pchTemp == L'\\')
217 ++pchTemp;
218 }
219
220 bLFN = IsLFNDriveW(szRoot);
221 if (!bLFN)
222 {
223 PWCHAR pch;
224 for (pch = pchTemp; *pch != UNICODE_NULL; ++pch)
225 {
226 #define VALID_SHORT_PATH_CHAR_CLASSES ( \
227 PATH_CHAR_CLASS_DOT | \
228 PATH_CHAR_CLASS_BACKSLASH | \
229 PATH_CHAR_CLASS_COLON | \
230 PATH_CHAR_CLASS_OTHER_VALID \
231 )
232 if (!PathIsValidCharW(*pch, VALID_SHORT_PATH_CHAR_CLASSES))
233 {
234 *pch = L'_';
235 }
236 }
237 }
238
239 StringCchCopyW(pszPath, MAX_PATH, szRoot);
240 cchPathLeft -= lstrlenW(pszPath) + 1;
241 }
242 else /* UNC path: Begins with double backslash */
243 {
244 bLFN = IsLFNDriveW(pchTemp);
245 if (bLFN)
246 {
247 pszPath[2] = UNICODE_NULL; /* Cut off */
248 cchPathLeft -= (2 + 1);
249 pchTemp += 2;
250 }
251 else
252 {
253 PWCHAR pchSlash = StrChrW(pszPath + 2, L'\\');
254 if (pchSlash)
255 pchSlash = StrChrW(pchSlash + 1, L'\\');
256
257 if (pchSlash)
258 {
259 *(pchSlash + 1) = UNICODE_NULL; /* Cut off */
260 pchTemp += pchSlash - pszPath;
261 cchPathLeft -= (INT)(SIZE_T)(pchSlash - pszPath) + 1;
262 }
263 else
264 {
265 bLFN = TRUE;
266 pszPath[2] = UNICODE_NULL; /* Cut off */
267 cchPathLeft -= 2;
268 pchTemp += 2;
269 }
270 }
271 }
272 /* Now pszPath is a root-like path or an empty string. */
273
274 /* Start appending the path components of szTemp to pszPath. */
275 while (*pchTemp && cchPathLeft > 0)
276 {
277 /* Collapse any .\ and ..\ parts in the path */
278 if (*pchTemp == L'.')
279 {
280 BOOL bDots = FALSE; /* '.' or '..' ? */
281
282 if (pchTemp[1] == UNICODE_NULL || pchTemp[1] == L'\\')
283 {
284 /* Component '.' */
285 bDots = TRUE;
286 }
287 else if (pchTemp[1] == L'.' && (pchTemp[2] == UNICODE_NULL || pchTemp[2] == L'\\'))
288 {
289 /* Component '..' */
290 PathRemoveFileSpecW(pszPath); /* Remove the last component from pszPath */
291 bDots = TRUE;
292 }
293
294 /* If a '.' or '..' was encountered, skip to the next component */
295 if (bDots)
296 {
297 while (*pchTemp && *pchTemp != L'\\')
298 {
299 ++pchTemp;
300 }
301
302 while (*pchTemp == L'\\')
303 {
304 ++pchTemp;
305 }
306
307 continue;
308 }
309 }
310
311 /* Otherwise, copy the other path component */
312
313 if (!PathAddBackslashW(pszPath)) /* Append a backslash at the end */
314 break;
315
316 --cchPathLeft;
317
318 pchPath = &pszPath[lstrlenW(pszPath)];
319
320 if (!bLFN) /* Not LFN? */
321 {
322 /* Copy MS-DOS 8.3 filename */
323 PWCHAR pchDot = NULL;
324 INT ich;
325 WCHAR szTitle[8 + 1] = L"";
326 INT cchTitle = 0;
327 WCHAR szDotExtension[1 + 3 + 1] = L"";
328 INT cchDotExtension = 0;
329
330 /* Copy the component to szTitle and szDotExtension... */
331 while (*pchTemp && *pchTemp != L'\\')
332 {
333 if (*pchTemp == L'.')
334 {
335 pchDot = pchTemp; /* Remember the last position */
336
337 /* Clear szDotExtension */
338 cchDotExtension = 0;
339 ZeroMemory(szDotExtension, sizeof(szDotExtension));
340 }
341
342 if (pchDot)
343 {
344 if (cchDotExtension < 1 + 3)
345 szDotExtension[cchDotExtension++] = *pchTemp;
346 }
347 else
348 {
349 if (cchTitle < 8)
350 szTitle[cchTitle++] = *pchTemp;
351 }
352
353 ++pchTemp;
354 }
355
356 /* Add file title 'szTitle' to pchPath */
357 for (ich = 0; szTitle[ich] && cchPathLeft > 0; ++ich)
358 {
359 *pchPath++ = szTitle[ich];
360 --cchPathLeft;
361 }
362
363 /* Add file extension 'szDotExtension' to pchPath */
364 if (pchDot)
365 {
366 for (ich = 0; szDotExtension[ich] && cchPathLeft > 0; ++ich)
367 {
368 *pchPath++ = szDotExtension[ich];
369 --cchPathLeft;
370 }
371 }
372 }
373 else /* LFN */
374 {
375 /* Copy the component up to the next separator */
376 while (*pchTemp != UNICODE_NULL && *pchTemp != L'\\' && cchPathLeft > 0)
377 {
378 *pchPath++ = *pchTemp++;
379 --cchPathLeft;
380 }
381 }
382
383 /* Skip the backslashes */
384 while (*pchTemp == L'\\')
385 {
386 ++pchTemp;
387 }
388
389 /* Keep null-terminated */
390 *pchPath = UNICODE_NULL;
391 }
392
393 /* Remove any trailing backslash */
394 PathRemoveBackslashW(pszPath);
395
396 if (!(dwFlags & 1)) /* Remove the trailing dot? */
397 {
398 pchPath = CharPrevW(pszPath, pszPath + lstrlenW(pszPath));
399 if (*pchPath == L'.')
400 *pchPath = UNICODE_NULL;
401 }
402 }
403
404 /*************************************************************************
405 * PathAppend [SHELL32.36]
406 */
PathAppendAW(LPVOID lpszPath1,LPCVOID lpszPath2)407 BOOL WINAPI PathAppendAW(
408 LPVOID lpszPath1,
409 LPCVOID lpszPath2)
410 {
411 if (SHELL_OsIsUnicode())
412 return PathAppendW(lpszPath1, lpszPath2);
413 return PathAppendA(lpszPath1, lpszPath2);
414 }
415
416 /*************************************************************************
417 * PathGetExtensionA [internal]
418 *
419 * NOTES
420 * exported by ordinal
421 * return value points to the first char after the dot
422 */
PathGetExtensionA(LPCSTR lpszPath)423 static LPSTR PathGetExtensionA(LPCSTR lpszPath)
424 {
425 TRACE("(%s)\n",lpszPath);
426
427 lpszPath = PathFindExtensionA(lpszPath);
428 return (LPSTR)(*lpszPath?(lpszPath+1):lpszPath);
429 }
430
431 /*************************************************************************
432 * PathGetExtensionW [internal]
433 */
PathGetExtensionW(LPCWSTR lpszPath)434 static LPWSTR PathGetExtensionW(LPCWSTR lpszPath)
435 {
436 TRACE("(%s)\n",debugstr_w(lpszPath));
437
438 lpszPath = PathFindExtensionW(lpszPath);
439 return (LPWSTR)(*lpszPath?(lpszPath+1):lpszPath);
440 }
441
442 /*************************************************************************
443 * SHPathGetExtension [SHELL32.158]
444 */
SHPathGetExtensionW(LPCWSTR lpszPath,DWORD void1,DWORD void2)445 LPVOID WINAPI SHPathGetExtensionW(LPCWSTR lpszPath, DWORD void1, DWORD void2)
446 {
447 return PathGetExtensionW(lpszPath);
448 }
449
450 /*************************************************************************
451 * PathRemoveFileSpec [SHELL32.35]
452 */
PathRemoveFileSpecAW(LPVOID lpszPath)453 BOOL WINAPI PathRemoveFileSpecAW(LPVOID lpszPath)
454 {
455 if (SHELL_OsIsUnicode())
456 return PathRemoveFileSpecW(lpszPath);
457 return PathRemoveFileSpecA(lpszPath);
458 }
459
460 /*
461 Path Manipulations
462 */
463
464 /*************************************************************************
465 * PathGetShortPathA [internal]
466 */
PathGetShortPathA(LPSTR pszPath)467 static void PathGetShortPathA(LPSTR pszPath)
468 {
469 CHAR path[MAX_PATH];
470
471 TRACE("%s\n", pszPath);
472
473 if (GetShortPathNameA(pszPath, path, MAX_PATH))
474 {
475 lstrcpyA(pszPath, path);
476 }
477 }
478
479 /*************************************************************************
480 * PathGetShortPathW [internal]
481 */
PathGetShortPathW(LPWSTR pszPath)482 static void PathGetShortPathW(LPWSTR pszPath)
483 {
484 WCHAR path[MAX_PATH];
485
486 TRACE("%s\n", debugstr_w(pszPath));
487
488 if (GetShortPathNameW(pszPath, path, MAX_PATH))
489 {
490 lstrcpyW(pszPath, path);
491 }
492 }
493
494 /*************************************************************************
495 * PathGetShortPath [SHELL32.92]
496 */
PathGetShortPathAW(LPVOID pszPath)497 VOID WINAPI PathGetShortPathAW(LPVOID pszPath)
498 {
499 if(SHELL_OsIsUnicode())
500 PathGetShortPathW(pszPath);
501 PathGetShortPathA(pszPath);
502 }
503
504 /*
505 ########## Path Testing ##########
506 */
507
508 /*************************************************************************
509 * PathIsRoot [SHELL32.29]
510 */
PathIsRootAW(LPCVOID lpszPath)511 BOOL WINAPI PathIsRootAW(LPCVOID lpszPath)
512 {
513 if (SHELL_OsIsUnicode())
514 return PathIsRootW(lpszPath);
515 return PathIsRootA(lpszPath);
516 }
517
518 /*************************************************************************
519 * PathIsExeA [internal]
520 */
PathIsExeA(LPCSTR lpszPath)521 static BOOL PathIsExeA (LPCSTR lpszPath)
522 {
523 LPCSTR lpszExtension = PathGetExtensionA(lpszPath);
524 int i;
525 static const char * const lpszExtensions[] =
526 {"exe", "com", "pif", "cmd", "bat", "scf", "scr", NULL };
527
528 TRACE("path=%s\n",lpszPath);
529
530 for(i=0; lpszExtensions[i]; i++)
531 if (!lstrcmpiA(lpszExtension,lpszExtensions[i])) return TRUE;
532
533 return FALSE;
534 }
535
536 /*************************************************************************
537 * PathIsExeW [internal]
538 */
PathIsExeW(LPCWSTR lpszPath)539 BOOL PathIsExeW (LPCWSTR lpszPath)
540 {
541 LPCWSTR lpszExtension = PathGetExtensionW(lpszPath);
542 int i;
543 static const WCHAR lpszExtensions[][4] =
544 {L"exe", L"com", L"pif", L"cmd", L"bat", L"scf", L"scr", L"" };
545
546 TRACE("path=%s\n",debugstr_w(lpszPath));
547
548 for(i=0; lpszExtensions[i][0]; i++)
549 if (!wcsicmp(lpszExtension,lpszExtensions[i])) return TRUE;
550
551 return FALSE;
552 }
553
554 /*************************************************************************
555 * PathIsExe [SHELL32.43]
556 */
PathIsExeAW(LPCVOID path)557 BOOL WINAPI PathIsExeAW (LPCVOID path)
558 {
559 if (SHELL_OsIsUnicode())
560 return PathIsExeW (path);
561 return PathIsExeA(path);
562 }
563
564 /*************************************************************************
565 * PathFileExists [SHELL32.45]
566 */
PathFileExistsAW(LPCVOID lpszPath)567 BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath)
568 {
569 if (SHELL_OsIsUnicode())
570 return PathFileExistsW (lpszPath);
571 return PathFileExistsA (lpszPath);
572 }
573
574 /*************************************************************************
575 * IsLFNDriveA [SHELL32.41]
576 */
IsLFNDriveA(LPCSTR lpszPath)577 BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath)
578 {
579 WCHAR szBuffW[MAX_PATH], *pszW = NULL;
580 if (lpszPath)
581 {
582 SHAnsiToUnicode(lpszPath, szBuffW, _countof(szBuffW));
583 pszW = szBuffW;
584 }
585 return IsLFNDriveW(pszW);
586 }
587
588 /*************************************************************************
589 * IsLFNDriveW [SHELL32.42]
590 */
IsLFNDriveW(LPCWSTR lpszPath)591 BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath)
592 {
593 DWORD cchMaxFileName, iDrive;
594 WCHAR szRoot[MAX_PATH];
595
596 if (lpszPath == NULL || lpszPath[0] == UNICODE_NULL)
597 {
598 szRoot[0] = 0;
599 GetWindowsDirectoryW(szRoot, _countof(szRoot));
600 lpszPath = szRoot;
601 }
602
603 if (PathIsUNCW(lpszPath))
604 {
605 StringCchCopyW(szRoot, _countof(szRoot), lpszPath);
606 PathStripToRootW(szRoot);
607
608 if (StrChrW(szRoot + 2, L'\\') == NULL)
609 return TRUE; /* LFN */
610
611 StringCchCatW(szRoot, _countof(szRoot), L"\\"); /* Add a backslash */
612 }
613 else
614 {
615 iDrive = ((lpszPath[0] - L'A') & 0x1F);
616 PathBuildRootW(szRoot, iDrive);
617
618 if (!IsRemovableDrive(iDrive))
619 {
620 /* FIXME: Cache correctly */
621 }
622 }
623
624 #define MSDOS_8DOT3_LEN 12 /* MS-DOS 8.3 filename == length 12 */
625
626 /* GetVolumeInformation requires a root path */
627 if (!GetVolumeInformationW(szRoot, NULL, 0, NULL, &cchMaxFileName, NULL, NULL, 0))
628 {
629 /* Don't return FALSE when GetVolumeInformationW fails. */
630 return TRUE;
631 }
632
633 return cchMaxFileName > MSDOS_8DOT3_LEN;
634 }
635
636 /*************************************************************************
637 * IsLFNDrive [SHELL32.119]
638 */
IsLFNDriveAW(LPCVOID lpszPath)639 BOOL WINAPI IsLFNDriveAW(LPCVOID lpszPath)
640 {
641 if (SHELL_OsIsUnicode())
642 return IsLFNDriveW(lpszPath);
643 return IsLFNDriveA(lpszPath);
644 }
645
646 /*
647 ########## Creating Something Unique ##########
648 */
649 /*************************************************************************
650 * PathMakeUniqueNameA [internal]
651 */
PathMakeUniqueNameA(LPSTR lpszBuffer,DWORD dwBuffSize,LPCSTR lpszShortName,LPCSTR lpszLongName,LPCSTR lpszPathName)652 static BOOL PathMakeUniqueNameA(
653 LPSTR lpszBuffer,
654 DWORD dwBuffSize,
655 LPCSTR lpszShortName,
656 LPCSTR lpszLongName,
657 LPCSTR lpszPathName)
658 {
659 FIXME("%p %u %s %s %s stub\n",
660 lpszBuffer, dwBuffSize, debugstr_a(lpszShortName),
661 debugstr_a(lpszLongName), debugstr_a(lpszPathName));
662 return TRUE;
663 }
664
665 /*************************************************************************
666 * PathMakeUniqueNameW [internal]
667 */
PathMakeUniqueNameW(LPWSTR lpszBuffer,DWORD dwBuffSize,LPCWSTR lpszShortName,LPCWSTR lpszLongName,LPCWSTR lpszPathName)668 static BOOL PathMakeUniqueNameW(
669 LPWSTR lpszBuffer,
670 DWORD dwBuffSize,
671 LPCWSTR lpszShortName,
672 LPCWSTR lpszLongName,
673 LPCWSTR lpszPathName)
674 {
675 FIXME("%p %u %s %s %s stub\n",
676 lpszBuffer, dwBuffSize, debugstr_w(lpszShortName),
677 debugstr_w(lpszLongName), debugstr_w(lpszPathName));
678 return TRUE;
679 }
680
681 /*************************************************************************
682 * PathMakeUniqueName [SHELL32.47]
683 */
PathMakeUniqueNameAW(LPVOID lpszBuffer,DWORD dwBuffSize,LPCVOID lpszShortName,LPCVOID lpszLongName,LPCVOID lpszPathName)684 BOOL WINAPI PathMakeUniqueNameAW(
685 LPVOID lpszBuffer,
686 DWORD dwBuffSize,
687 LPCVOID lpszShortName,
688 LPCVOID lpszLongName,
689 LPCVOID lpszPathName)
690 {
691 if (SHELL_OsIsUnicode())
692 return PathMakeUniqueNameW(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
693 return PathMakeUniqueNameA(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
694 }
695
696 /*************************************************************************
697 * PathYetAnotherMakeUniqueName [SHELL32.75]
698 */
PathYetAnotherMakeUniqueName(LPWSTR buffer,LPCWSTR path,LPCWSTR shortname,LPCWSTR longname)699 BOOL WINAPI PathYetAnotherMakeUniqueName(LPWSTR buffer, LPCWSTR path, LPCWSTR shortname, LPCWSTR longname)
700 {
701 WCHAR pathW[MAX_PATH], retW[MAX_PATH];
702 const WCHAR *file, *ext;
703 int i = 2;
704
705 TRACE("(%p, %s, %s, %s)\n", buffer, debugstr_w(path), debugstr_w(shortname), debugstr_w(longname));
706
707 file = longname ? longname : shortname;
708 PathCombineW(pathW, path, file);
709 strcpyW(retW, pathW);
710 PathRemoveExtensionW(pathW);
711
712 ext = PathFindExtensionW(file);
713
714 /* now try to make it unique */
715 while (PathFileExistsW(retW))
716 {
717 sprintfW(retW, L"%s (%d)%s", pathW, i, ext);
718 i++;
719 }
720
721 strcpyW(buffer, retW);
722 TRACE("ret - %s\n", debugstr_w(buffer));
723
724 return TRUE;
725 }
726
727 /*
728 ########## cleaning and resolving paths ##########
729 */
730
731 /*************************************************************************
732 * PathCleanupSpec [SHELL32.171]
733 *
734 * lpszFile is changed in place.
735 */
PathCleanupSpec(LPCWSTR lpszPathW,LPWSTR lpszFileW)736 int WINAPI PathCleanupSpec( LPCWSTR lpszPathW, LPWSTR lpszFileW )
737 {
738 int i = 0;
739 DWORD rc = 0;
740 int length = 0;
741
742 if (SHELL_OsIsUnicode())
743 {
744 LPWSTR p = lpszFileW;
745
746 TRACE("Cleanup %s\n",debugstr_w(lpszFileW));
747
748 if (lpszPathW)
749 length = strlenW(lpszPathW);
750
751 while (*p)
752 {
753 int gct = PathGetCharTypeW(*p);
754 if (gct == GCT_INVALID || gct == GCT_WILD || gct == GCT_SEPARATOR)
755 {
756 lpszFileW[i]='-';
757 rc |= PCS_REPLACEDCHAR;
758 }
759 else
760 lpszFileW[i]=*p;
761 i++;
762 p++;
763 if (length + i == MAX_PATH)
764 {
765 rc |= PCS_FATAL | PCS_PATHTOOLONG;
766 break;
767 }
768 }
769 lpszFileW[i]=0;
770 }
771 else
772 {
773 LPSTR lpszFileA = (LPSTR)lpszFileW;
774 LPCSTR lpszPathA = (LPCSTR)lpszPathW;
775 LPSTR p = lpszFileA;
776
777 TRACE("Cleanup %s\n",debugstr_a(lpszFileA));
778
779 if (lpszPathA)
780 length = strlen(lpszPathA);
781
782 while (*p)
783 {
784 int gct = PathGetCharTypeA(*p);
785 if (gct == GCT_INVALID || gct == GCT_WILD || gct == GCT_SEPARATOR)
786 {
787 lpszFileA[i]='-';
788 rc |= PCS_REPLACEDCHAR;
789 }
790 else
791 lpszFileA[i]=*p;
792 i++;
793 p++;
794 if (length + i == MAX_PATH)
795 {
796 rc |= PCS_FATAL | PCS_PATHTOOLONG;
797 break;
798 }
799 }
800 lpszFileA[i]=0;
801 }
802 return rc;
803 }
804
805 /*************************************************************************
806 * PathQualifyA [SHELL32]
807 */
PathQualifyA(LPSTR pszPath)808 VOID WINAPI PathQualifyA(LPSTR pszPath)
809 {
810 WCHAR szPath[MAX_PATH];
811 TRACE("%s\n",pszPath);
812 SHAnsiToUnicode(pszPath, szPath, _countof(szPath));
813 PathQualifyW(szPath);
814 SHUnicodeToAnsi(szPath, pszPath, MAX_PATH);
815 }
816
817 /*************************************************************************
818 * PathQualifyW [SHELL32]
819 */
PathQualifyW(LPWSTR pszPath)820 VOID WINAPI PathQualifyW(LPWSTR pszPath)
821 {
822 TRACE("%s\n",debugstr_w(pszPath));
823 PathQualifyExW(pszPath, NULL, 0);
824 }
825
826 /*************************************************************************
827 * PathQualify [SHELL32.49]
828 */
PathQualifyAW(LPVOID pszPath)829 VOID WINAPI PathQualifyAW(LPVOID pszPath)
830 {
831 if (SHELL_OsIsUnicode())
832 PathQualifyW(pszPath);
833 else
834 PathQualifyA(pszPath);
835 }
836
PathResolveA(LPSTR path,LPCSTR * dirs,DWORD flags)837 BOOL WINAPI PathResolveA(LPSTR path, LPCSTR *dirs, DWORD flags)
838 {
839 BOOL ret = FALSE;
840 LPWSTR *dirsW = NULL;
841 DWORD iDir, cDirs, cbDirs;
842 WCHAR pathW[MAX_PATH];
843
844 TRACE("(%s,%p,0x%08x)\n", debugstr_a(path), dirs, flags);
845
846 if (dirs)
847 {
848 for (cDirs = 0; dirs[cDirs]; ++cDirs)
849 ;
850
851 cbDirs = (cDirs + 1) * sizeof(LPWSTR);
852 dirsW = SHAlloc(cbDirs);
853 if (!dirsW)
854 goto Cleanup;
855
856 ZeroMemory(dirsW, cbDirs);
857 for (iDir = 0; iDir < cDirs; ++iDir)
858 {
859 __SHCloneStrAtoW(&dirsW[iDir], dirs[iDir]);
860 if (dirsW[iDir] == NULL)
861 goto Cleanup;
862 }
863 }
864
865 SHAnsiToUnicode(path, pathW, _countof(pathW));
866
867 ret = PathResolveW(pathW, (LPCWSTR*)dirsW, flags);
868 if (ret)
869 SHUnicodeToAnsi(pathW, path, MAX_PATH);
870
871 Cleanup:
872 if (dirsW)
873 {
874 for (iDir = 0; iDir < cDirs; ++iDir)
875 {
876 SHFree(dirsW[iDir]);
877 }
878 SHFree(dirsW);
879 }
880 return ret;
881 }
882
PathResolveW(_Inout_ LPWSTR path,_Inout_opt_ LPCWSTR * dirs,_In_ DWORD flags)883 BOOL WINAPI PathResolveW(_Inout_ LPWSTR path, _Inout_opt_ LPCWSTR *dirs, _In_ DWORD flags)
884 {
885 DWORD dwWhich = WHICH_DEFAULT; /* The extensions to be searched */
886
887 TRACE("(%s,%p,0x%08x)\n", debugstr_w(path), dirs, flags);
888
889 if (flags & PRF_DONTFINDLNK)
890 dwWhich &= ~WHICH_LNK; /* Don't search '.LNK' (shortcut) */
891
892 if (flags & PRF_VERIFYEXISTS)
893 SetLastError(ERROR_FILE_NOT_FOUND); /* We set this error code at first in verification */
894
895 PathUnquoteSpacesW(path);
896
897 if (PathIsRootW(path)) /* Root path */
898 {
899 if (path[0] == L'\\' && path[1] == UNICODE_NULL) /* '\' only? */
900 PathQualifyExW(path, ((flags & PRF_FIRSTDIRDEF) ? *dirs : NULL), 0); /* Qualify */
901
902 if (flags & PRF_VERIFYEXISTS)
903 return PathFileExistsAndAttributesW(path, NULL); /* Check the existence */
904
905 return TRUE;
906 }
907
908 if (PathIsFileSpecW(path)) /* Filename only */
909 {
910 /* Try to find the path with program extensions applied? */
911 if ((flags & PRF_TRYPROGRAMEXTENSIONS) &&
912 PathSearchOnExtensionsW(path, dirs, TRUE, dwWhich))
913 {
914 return TRUE; /* Found */
915 }
916
917 /* Try to find the filename in the directories */
918 if (PathFindOnPathW(path, dirs))
919 goto CheckAbsoluteAndFinish;
920
921 return FALSE; /* Not found */
922 }
923
924 if (PathIsURLW(path)) /* URL? */
925 return FALSE;
926
927 /* Qualify the path */
928 PathQualifyExW(path, ((flags & PRF_FIRSTDIRDEF) ? *dirs : NULL), 1);
929
930 TRACE("(%s)\n", debugstr_w(path));
931
932 if (!(flags & PRF_VERIFYEXISTS)) /* Don't verify the existence? */
933 return TRUE;
934
935 /* Try to find the path with program extensions applied? */
936 if (!(flags & PRF_TRYPROGRAMEXTENSIONS) ||
937 !PathSearchOnExtensionsW(path, dirs, FALSE, dwWhich))
938 {
939 if (!PathFileExistsAndAttributesW(path, NULL))
940 return FALSE; /* Not found */
941 }
942
943 CheckAbsoluteAndFinish:
944 #if (_WIN32_WINNT >= _WIN32_WINNT_WS03)
945 if (!(flags & PRF_REQUIREABSOLUTE) || PathIsAbsoluteW(path))
946 return TRUE;
947
948 if (!PathMakeAbsoluteW(path))
949 return FALSE;
950
951 return PathFileExistsAndAttributesW(path, NULL);
952 #else
953 return TRUE; /* Found */
954 #endif
955 }
956
957 /*************************************************************************
958 * PathResolve [SHELL32.51]
959 */
PathResolveAW(LPVOID path,LPCVOID * paths,DWORD flags)960 BOOL WINAPI PathResolveAW(LPVOID path, LPCVOID *paths, DWORD flags)
961 {
962 if (SHELL_OsIsUnicode())
963 return PathResolveW(path, (LPCWSTR*)paths, flags);
964 else
965 return PathResolveA(path, (LPCSTR*)paths, flags);
966 }
967
968 /*************************************************************************
969 * PathProcessCommandA
970 */
PathProcessCommandA(LPCSTR lpszPath,LPSTR lpszBuff,DWORD dwBuffSize,DWORD dwFlags)971 static LONG PathProcessCommandA (
972 LPCSTR lpszPath,
973 LPSTR lpszBuff,
974 DWORD dwBuffSize,
975 DWORD dwFlags)
976 {
977 FIXME("%s %p 0x%04x 0x%04x stub\n",
978 lpszPath, lpszBuff, dwBuffSize, dwFlags);
979 if(!lpszPath) return -1;
980 if(lpszBuff) strcpy(lpszBuff, lpszPath);
981 return strlen(lpszPath);
982 }
983
984 /*************************************************************************
985 * PathProcessCommandW
986 */
PathProcessCommandW(LPCWSTR lpszPath,LPWSTR lpszBuff,DWORD dwBuffSize,DWORD dwFlags)987 static LONG PathProcessCommandW (
988 LPCWSTR lpszPath,
989 LPWSTR lpszBuff,
990 DWORD dwBuffSize,
991 DWORD dwFlags)
992 {
993 FIXME("(%s, %p, 0x%04x, 0x%04x) stub\n",
994 debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags);
995 if(!lpszPath) return -1;
996 if(lpszBuff) strcpyW(lpszBuff, lpszPath);
997 return strlenW(lpszPath);
998 }
999
1000 /*************************************************************************
1001 * PathProcessCommand (SHELL32.653)
1002 */
PathProcessCommandAW(LPCVOID lpszPath,LPVOID lpszBuff,DWORD dwBuffSize,DWORD dwFlags)1003 LONG WINAPI PathProcessCommandAW (
1004 LPCVOID lpszPath,
1005 LPVOID lpszBuff,
1006 DWORD dwBuffSize,
1007 DWORD dwFlags)
1008 {
1009 if (SHELL_OsIsUnicode())
1010 return PathProcessCommandW(lpszPath, lpszBuff, dwBuffSize, dwFlags);
1011 return PathProcessCommandA(lpszPath, lpszBuff, dwBuffSize, dwFlags);
1012 }
1013
1014 /*
1015 ########## special ##########
1016 */
1017
1018 /* !! MISSING Win2k3-compatible paths from the list below; absent from Wine !! */
1019 #ifndef __REACTOS__
1020 static const WCHAR Application_DataW[] = L"Application Data";
1021 static const WCHAR Local_Settings_Application_DataW[] = L"Local Settings\\Application Data";
1022 static const WCHAR Local_Settings_HistoryW[] = L"Local Settings\\History";
1023 static const WCHAR Local_Settings_Temporary_Internet_FilesW[] = L"Local Settings\\Temporary Internet Files";
1024 static const WCHAR MusicW[] = L"Music";
1025 static const WCHAR PicturesW[] = L"Pictures";
1026 static const WCHAR Program_FilesW[] = L"Program Files";
1027 static const WCHAR Program_Files_Common_FilesW[] = L"Program Files\\Common Files";
1028 static const WCHAR Start_Menu_ProgramsW[] = L"Start Menu\\Programs";
1029 static const WCHAR Start_Menu_Admin_ToolsW[] = L"Start Menu\\Programs\\Administrative Tools";
1030 static const WCHAR Start_Menu_StartupW[] = L"Start Menu\\Programs\\StartUp";
1031 #endif
1032
1033 /* Long strings that are repeated many times: keep them here */
1034 static const WCHAR szSHFolders[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
1035 static const WCHAR szSHUserFolders[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
1036 #ifndef __REACTOS__
1037 static const WCHAR szKnownFolderDescriptions[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FolderDescriptions";
1038 static const WCHAR szKnownFolderRedirections[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
1039 #endif
1040
1041 typedef enum _CSIDL_Type {
1042 CSIDL_Type_User,
1043 #ifdef __REACTOS__
1044 CSIDL_Type_InMyDocuments,
1045 #endif
1046 CSIDL_Type_AllUsers,
1047 CSIDL_Type_CurrVer,
1048 CSIDL_Type_Disallowed,
1049 CSIDL_Type_NonExistent,
1050 CSIDL_Type_WindowsPath,
1051 CSIDL_Type_SystemPath,
1052 CSIDL_Type_SystemX86Path,
1053 } CSIDL_Type;
1054
1055 /* Cannot use #if _WIN32_WINNT >= 0x0600 because _WIN32_WINNT == 0x0600 here. */
1056 #ifndef __REACTOS__
1057 #define CSIDL_CONTACTS 0x0043
1058 #define CSIDL_DOWNLOADS 0x0047
1059 #define CSIDL_LINKS 0x004d
1060 #define CSIDL_APPDATA_LOCALLOW 0x004e
1061 #define CSIDL_SAVED_GAMES 0x0062
1062 #define CSIDL_SEARCHES 0x0063
1063 #endif
1064
1065 typedef struct
1066 {
1067 const KNOWNFOLDERID *id;
1068 CSIDL_Type type;
1069 LPCWSTR szValueName;
1070 LPCWSTR szDefaultPath; /* fallback string or resource ID */
1071 INT nShell32IconIndex;
1072 } CSIDL_DATA;
1073
1074 static const CSIDL_DATA CSIDL_Data[] =
1075 {
1076 { /* 0x00 - CSIDL_DESKTOP */
1077 &FOLDERID_Desktop,
1078 CSIDL_Type_User,
1079 L"Desktop",
1080 MAKEINTRESOURCEW(IDS_DESKTOPDIRECTORY),
1081 #ifdef __REACTOS__
1082 0
1083 #else
1084 -IDI_SHELL_DESKTOP
1085 #endif
1086 },
1087 { /* 0x01 - CSIDL_INTERNET */
1088 &FOLDERID_InternetFolder,
1089 CSIDL_Type_Disallowed,
1090 NULL,
1091 NULL
1092 },
1093 { /* 0x02 - CSIDL_PROGRAMS */
1094 &FOLDERID_Programs,
1095 CSIDL_Type_User,
1096 L"Programs",
1097 MAKEINTRESOURCEW(IDS_PROGRAMS),
1098 #ifdef __REACTOS__
1099 0
1100 #else
1101 -IDI_SHELL_PROGRAMS_FOLDER
1102 #endif
1103 },
1104 { /* 0x03 - CSIDL_CONTROLS (.CPL files) */
1105 &FOLDERID_ControlPanelFolder,
1106 CSIDL_Type_SystemPath,
1107 L"ControlPanelFolder",
1108 NULL,
1109 -IDI_SHELL_CONTROL_PANEL
1110 },
1111 { /* 0x04 - CSIDL_PRINTERS */
1112 &FOLDERID_PrintersFolder,
1113 CSIDL_Type_SystemPath,
1114 L"PrintersFolder",
1115 NULL,
1116 -IDI_SHELL_PRINTERS_FOLDER
1117 },
1118 { /* 0x05 - CSIDL_PERSONAL */
1119 &FOLDERID_Documents,
1120 CSIDL_Type_User,
1121 L"Personal",
1122 MAKEINTRESOURCEW(IDS_PERSONAL),
1123 -IDI_SHELL_MY_DOCUMENTS
1124 },
1125 { /* 0x06 - CSIDL_FAVORITES */
1126 &FOLDERID_Favorites,
1127 CSIDL_Type_User,
1128 L"Favorites",
1129 MAKEINTRESOURCEW(IDS_FAVORITES),
1130 -IDI_SHELL_FAVORITES
1131 },
1132 { /* 0x07 - CSIDL_STARTUP */
1133 &FOLDERID_Startup,
1134 CSIDL_Type_User,
1135 L"StartUp",
1136 MAKEINTRESOURCEW(IDS_STARTUP)
1137 },
1138 { /* 0x08 - CSIDL_RECENT */
1139 &FOLDERID_Recent,
1140 CSIDL_Type_User,
1141 L"Recent",
1142 MAKEINTRESOURCEW(IDS_RECENT),
1143 -IDI_SHELL_RECENT_DOCUMENTS
1144 },
1145 { /* 0x09 - CSIDL_SENDTO */
1146 &FOLDERID_SendTo,
1147 CSIDL_Type_User,
1148 L"SendTo",
1149 MAKEINTRESOURCEW(IDS_SENDTO)
1150 },
1151 { /* 0x0a - CSIDL_BITBUCKET - Recycle Bin */
1152 &FOLDERID_RecycleBinFolder,
1153 CSIDL_Type_Disallowed,
1154 L"RecycleBinFolder",
1155 NULL
1156 },
1157 { /* 0x0b - CSIDL_STARTMENU */
1158 &FOLDERID_StartMenu,
1159 CSIDL_Type_User,
1160 L"Start Menu",
1161 MAKEINTRESOURCEW(IDS_STARTMENU),
1162 -IDI_SHELL_TSKBAR_STARTMENU
1163 },
1164 { /* 0x0c - CSIDL_MYDOCUMENTS */
1165 &GUID_NULL,
1166 CSIDL_Type_Disallowed, /* matches WinXP--can't get its path */
1167 NULL,
1168 NULL,
1169 -IDI_SHELL_MY_DOCUMENTS
1170 },
1171 { /* 0x0d - CSIDL_MYMUSIC */
1172 &FOLDERID_Music,
1173 #ifdef __REACTOS__
1174 CSIDL_Type_InMyDocuments,
1175 #else
1176 CSIDL_Type_User,
1177 #endif
1178 L"My Music",
1179 MAKEINTRESOURCEW(IDS_MYMUSIC),
1180 -IDI_SHELL_MY_MUSIC
1181 },
1182 { /* 0x0e - CSIDL_MYVIDEO */
1183 &FOLDERID_Videos,
1184 #ifdef __REACTOS__
1185 CSIDL_Type_InMyDocuments,
1186 #else
1187 CSIDL_Type_User,
1188 #endif
1189 L"My Video",
1190 MAKEINTRESOURCEW(IDS_MYVIDEO),
1191 -IDI_SHELL_MY_MOVIES
1192 },
1193 { /* 0x0f - unassigned */
1194 &GUID_NULL,
1195 CSIDL_Type_Disallowed,
1196 NULL,
1197 NULL,
1198 },
1199 { /* 0x10 - CSIDL_DESKTOPDIRECTORY */
1200 &FOLDERID_Desktop,
1201 CSIDL_Type_User,
1202 L"Desktop",
1203 MAKEINTRESOURCEW(IDS_DESKTOPDIRECTORY),
1204 #ifdef __REACTOS__
1205 0
1206 #else
1207 -IDI_SHELL_DESKTOP
1208 #endif
1209 },
1210 { /* 0x11 - CSIDL_DRIVES */
1211 &FOLDERID_ComputerFolder,
1212 CSIDL_Type_Disallowed,
1213 L"MyComputerFolder",
1214 NULL,
1215 -IDI_SHELL_COMPUTER_FOLDER
1216 },
1217 { /* 0x12 - CSIDL_NETWORK */
1218 &FOLDERID_NetworkFolder,
1219 CSIDL_Type_Disallowed,
1220 L"NetworkPlacesFolder",
1221 NULL,
1222 -IDI_SHELL_NETWORK_FOLDER
1223 },
1224 { /* 0x13 - CSIDL_NETHOOD */
1225 &FOLDERID_NetHood,
1226 CSIDL_Type_User,
1227 L"NetHood",
1228 MAKEINTRESOURCEW(IDS_NETHOOD),
1229 -IDI_SHELL_NETWORK
1230 },
1231 { /* 0x14 - CSIDL_FONTS */
1232 &FOLDERID_Fonts,
1233 CSIDL_Type_WindowsPath,
1234 L"Fonts",
1235 L"Fonts",
1236 -IDI_SHELL_FONTS_FOLDER
1237 },
1238 { /* 0x15 - CSIDL_TEMPLATES */
1239 &FOLDERID_Templates,
1240 CSIDL_Type_User,
1241 L"Templates",
1242 MAKEINTRESOURCEW(IDS_TEMPLATES)
1243 },
1244 { /* 0x16 - CSIDL_COMMON_STARTMENU */
1245 &FOLDERID_CommonStartMenu,
1246 CSIDL_Type_AllUsers,
1247 L"Common Start Menu",
1248 MAKEINTRESOURCEW(IDS_STARTMENU),
1249 -IDI_SHELL_TSKBAR_STARTMENU
1250 },
1251 { /* 0x17 - CSIDL_COMMON_PROGRAMS */
1252 &FOLDERID_CommonPrograms,
1253 CSIDL_Type_AllUsers,
1254 L"Common Programs",
1255 MAKEINTRESOURCEW(IDS_PROGRAMS),
1256 #ifdef __REACTOS__
1257 0
1258 #else
1259 -IDI_SHELL_PROGRAMS_FOLDER
1260 #endif
1261 },
1262 { /* 0x18 - CSIDL_COMMON_STARTUP */
1263 &FOLDERID_CommonStartup,
1264 CSIDL_Type_AllUsers,
1265 L"Common StartUp",
1266 MAKEINTRESOURCEW(IDS_STARTUP)
1267 },
1268 { /* 0x19 - CSIDL_COMMON_DESKTOPDIRECTORY */
1269 &FOLDERID_PublicDesktop,
1270 CSIDL_Type_AllUsers,
1271 L"Common Desktop",
1272 MAKEINTRESOURCEW(IDS_DESKTOPDIRECTORY),
1273 #ifdef __REACTOS__
1274 0
1275 #else
1276 -IDI_SHELL_DESKTOP
1277 #endif
1278 },
1279 { /* 0x1a - CSIDL_APPDATA */
1280 &FOLDERID_RoamingAppData,
1281 CSIDL_Type_User,
1282 L"AppData",
1283 MAKEINTRESOURCEW(IDS_APPDATA)
1284 },
1285 { /* 0x1b - CSIDL_PRINTHOOD */
1286 &FOLDERID_PrintHood,
1287 CSIDL_Type_User,
1288 L"PrintHood",
1289 MAKEINTRESOURCEW(IDS_PRINTHOOD),
1290 -IDI_SHELL_PRINTERS_FOLDER
1291 },
1292 { /* 0x1c - CSIDL_LOCAL_APPDATA */
1293 &FOLDERID_LocalAppData,
1294 CSIDL_Type_User,
1295 L"Local AppData",
1296 MAKEINTRESOURCEW(IDS_LOCAL_APPDATA)
1297 },
1298 { /* 0x1d - CSIDL_ALTSTARTUP */
1299 &GUID_NULL,
1300 CSIDL_Type_NonExistent,
1301 NULL,
1302 NULL
1303 },
1304 { /* 0x1e - CSIDL_COMMON_ALTSTARTUP */
1305 &GUID_NULL,
1306 CSIDL_Type_NonExistent,
1307 NULL,
1308 NULL
1309 },
1310 { /* 0x1f - CSIDL_COMMON_FAVORITES */
1311 &FOLDERID_Favorites,
1312 CSIDL_Type_AllUsers,
1313 L"Common Favorites",
1314 MAKEINTRESOURCEW(IDS_FAVORITES),
1315 -IDI_SHELL_FAVORITES
1316 },
1317 { /* 0x20 - CSIDL_INTERNET_CACHE */
1318 &FOLDERID_InternetCache,
1319 CSIDL_Type_User,
1320 L"Cache",
1321 MAKEINTRESOURCEW(IDS_INTERNET_CACHE)
1322 },
1323 { /* 0x21 - CSIDL_COOKIES */
1324 &FOLDERID_Cookies,
1325 CSIDL_Type_User,
1326 L"Cookies",
1327 MAKEINTRESOURCEW(IDS_COOKIES)
1328 },
1329 { /* 0x22 - CSIDL_HISTORY */
1330 &FOLDERID_History,
1331 CSIDL_Type_User,
1332 L"History",
1333 MAKEINTRESOURCEW(IDS_HISTORY)
1334 },
1335 { /* 0x23 - CSIDL_COMMON_APPDATA */
1336 &FOLDERID_ProgramData,
1337 CSIDL_Type_AllUsers,
1338 L"Common AppData",
1339 MAKEINTRESOURCEW(IDS_APPDATA)
1340 },
1341 { /* 0x24 - CSIDL_WINDOWS */
1342 &FOLDERID_Windows,
1343 CSIDL_Type_WindowsPath,
1344 L"Windows",
1345 NULL,
1346 -IDI_SHELL_SYSTEM_GEAR
1347 },
1348 { /* 0x25 - CSIDL_SYSTEM */
1349 &FOLDERID_System,
1350 CSIDL_Type_SystemPath,
1351 L"System",
1352 NULL,
1353 -IDI_SHELL_SYSTEM_GEAR
1354 },
1355 { /* 0x26 - CSIDL_PROGRAM_FILES */
1356 &FOLDERID_ProgramFiles,
1357 CSIDL_Type_CurrVer,
1358 L"ProgramFiles",
1359 MAKEINTRESOURCEW(IDS_PROGRAM_FILES),
1360 #ifdef __REACTOS__
1361 0
1362 #else
1363 -IDI_SHELL_PROGRAMS_FOLDER
1364 #endif
1365 },
1366 { /* 0x27 - CSIDL_MYPICTURES */
1367 &FOLDERID_Pictures,
1368 #ifdef __REACTOS__
1369 CSIDL_Type_InMyDocuments,
1370 #else
1371 CSIDL_Type_User,
1372 #endif
1373 L"My Pictures",
1374 MAKEINTRESOURCEW(IDS_MYPICTURES),
1375 -IDI_SHELL_MY_PICTURES
1376 },
1377 { /* 0x28 - CSIDL_PROFILE */
1378 &FOLDERID_Profile,
1379 CSIDL_Type_User,
1380 NULL,
1381 NULL
1382 },
1383 { /* 0x29 - CSIDL_SYSTEMX86 */
1384 &FOLDERID_SystemX86,
1385 CSIDL_Type_SystemX86Path,
1386 NULL,
1387 NULL,
1388 -IDI_SHELL_SYSTEM_GEAR
1389 },
1390 { /* 0x2a - CSIDL_PROGRAM_FILESX86 */
1391 &FOLDERID_ProgramFilesX86,
1392 CSIDL_Type_CurrVer,
1393 L"ProgramFilesX86",
1394 L"Program Files (x86)",
1395 -IDI_SHELL_PROGRAMS_FOLDER
1396 },
1397 { /* 0x2b - CSIDL_PROGRAM_FILES_COMMON */
1398 &FOLDERID_ProgramFilesCommon,
1399 CSIDL_Type_CurrVer,
1400 L"ProgramFilesCommon",
1401 MAKEINTRESOURCEW(IDS_PROGRAM_FILES_COMMON),
1402 -IDI_SHELL_PROGRAMS_FOLDER
1403 },
1404 { /* 0x2c - CSIDL_PROGRAM_FILES_COMMONX86 */
1405 &FOLDERID_ProgramFilesCommonX86,
1406 CSIDL_Type_CurrVer,
1407 L"ProgramFilesCommonX86",
1408 L"Program Files (x86)\\Common Files",
1409 -IDI_SHELL_PROGRAMS_FOLDER
1410 },
1411 { /* 0x2d - CSIDL_COMMON_TEMPLATES */
1412 &FOLDERID_CommonTemplates,
1413 CSIDL_Type_AllUsers,
1414 L"Common Templates",
1415 MAKEINTRESOURCEW(IDS_TEMPLATES)
1416 },
1417 { /* 0x2e - CSIDL_COMMON_DOCUMENTS */
1418 &FOLDERID_PublicDocuments,
1419 CSIDL_Type_AllUsers,
1420 L"Common Documents",
1421 MAKEINTRESOURCEW(IDS_PERSONAL),
1422 -IDI_SHELL_MY_DOCUMENTS
1423 },
1424 { /* 0x2f - CSIDL_COMMON_ADMINTOOLS */
1425 &FOLDERID_CommonAdminTools,
1426 CSIDL_Type_AllUsers,
1427 L"Common Administrative Tools",
1428 MAKEINTRESOURCEW(IDS_ADMINTOOLS)
1429 },
1430 { /* 0x30 - CSIDL_ADMINTOOLS */
1431 &FOLDERID_AdminTools,
1432 CSIDL_Type_User,
1433 L"Administrative Tools",
1434 MAKEINTRESOURCEW(IDS_ADMINTOOLS)
1435 },
1436 { /* 0x31 - CSIDL_CONNECTIONS */
1437 &FOLDERID_ConnectionsFolder,
1438 CSIDL_Type_Disallowed,
1439 L"ConnectionsFolder",
1440 NULL,
1441 -IDI_SHELL_NETWORK_CONNECTIONS
1442 },
1443 { /* 0x32 - unassigned */
1444 &GUID_NULL,
1445 CSIDL_Type_Disallowed,
1446 NULL,
1447 NULL
1448 },
1449 { /* 0x33 - unassigned */
1450 &GUID_NULL,
1451 CSIDL_Type_Disallowed,
1452 NULL,
1453 NULL
1454 },
1455 { /* 0x34 - unassigned */
1456 &GUID_NULL,
1457 CSIDL_Type_Disallowed,
1458 NULL,
1459 NULL
1460 },
1461 { /* 0x35 - CSIDL_COMMON_MUSIC */
1462 &FOLDERID_PublicMusic,
1463 CSIDL_Type_AllUsers,
1464 L"CommonMusic",
1465 MAKEINTRESOURCEW(IDS_COMMON_MUSIC),
1466 -IDI_SHELL_MY_MUSIC
1467 },
1468 { /* 0x36 - CSIDL_COMMON_PICTURES */
1469 &FOLDERID_PublicPictures,
1470 CSIDL_Type_AllUsers,
1471 L"CommonPictures",
1472 MAKEINTRESOURCEW(IDS_COMMON_PICTURES),
1473 -IDI_SHELL_MY_PICTURES
1474 },
1475 { /* 0x37 - CSIDL_COMMON_VIDEO */
1476 &FOLDERID_PublicVideos,
1477 CSIDL_Type_AllUsers,
1478 L"CommonVideo",
1479 MAKEINTRESOURCEW(IDS_COMMON_VIDEO),
1480 -IDI_SHELL_MY_MOVIES
1481 },
1482 { /* 0x38 - CSIDL_RESOURCES */
1483 &FOLDERID_ResourceDir,
1484 CSIDL_Type_WindowsPath,
1485 NULL,
1486 L"Resources"
1487 },
1488 { /* 0x39 - CSIDL_RESOURCES_LOCALIZED */
1489 &FOLDERID_LocalizedResourcesDir,
1490 CSIDL_Type_NonExistent,
1491 NULL,
1492 NULL
1493 },
1494 { /* 0x3a - CSIDL_COMMON_OEM_LINKS */
1495 &FOLDERID_CommonOEMLinks,
1496 CSIDL_Type_AllUsers,
1497 NULL,
1498 L"OEM Links"
1499 },
1500 { /* 0x3b - CSIDL_CDBURN_AREA */
1501 &FOLDERID_CDBurning,
1502 CSIDL_Type_User,
1503 L"CD Burning",
1504 L"Local Settings\\Application Data\\Microsoft\\CD Burning"
1505 },
1506 { /* 0x3c unassigned */
1507 &GUID_NULL,
1508 CSIDL_Type_Disallowed,
1509 NULL,
1510 NULL
1511 },
1512 { /* 0x3d - CSIDL_COMPUTERSNEARME */
1513 &GUID_NULL,
1514 CSIDL_Type_Disallowed, /* FIXME */
1515 NULL,
1516 NULL
1517 },
1518 { /* 0x3e - CSIDL_PROFILES */
1519 &GUID_NULL,
1520 CSIDL_Type_Disallowed, /* oddly, this matches WinXP */
1521 NULL,
1522 NULL
1523 },
1524 /* Cannot use #if _WIN32_WINNT >= 0x0600 because _WIN32_WINNT == 0x0600 here. */
1525 #ifndef __REACTOS__
1526 { /* 0x3f */
1527 &FOLDERID_AddNewPrograms,
1528 CSIDL_Type_Disallowed,
1529 NULL,
1530 NULL
1531 },
1532 { /* 0x40 */
1533 &FOLDERID_AppUpdates,
1534 CSIDL_Type_Disallowed,
1535 NULL,
1536 NULL
1537 },
1538 { /* 0x41 */
1539 &FOLDERID_ChangeRemovePrograms,
1540 CSIDL_Type_Disallowed,
1541 NULL,
1542 NULL
1543 },
1544 { /* 0x42 */
1545 &FOLDERID_ConflictFolder,
1546 CSIDL_Type_Disallowed,
1547 NULL,
1548 NULL
1549 },
1550 { /* 0x43 - CSIDL_CONTACTS */
1551 &FOLDERID_Contacts,
1552 CSIDL_Type_User,
1553 NULL,
1554 L"Contacts"
1555 },
1556 { /* 0x44 */
1557 &FOLDERID_DeviceMetadataStore,
1558 CSIDL_Type_Disallowed, /* FIXME */
1559 NULL,
1560 NULL
1561 },
1562 { /* 0x45 */
1563 &GUID_NULL,
1564 CSIDL_Type_User,
1565 NULL,
1566 L"Documents"
1567 },
1568 { /* 0x46 */
1569 &FOLDERID_DocumentsLibrary,
1570 CSIDL_Type_Disallowed, /* FIXME */
1571 NULL,
1572 NULL
1573 },
1574 { /* 0x47 - CSIDL_DOWNLOADS */
1575 &FOLDERID_Downloads,
1576 #ifdef __REACTOS__
1577 CSIDL_Type_InMyDocuments,
1578 #else
1579 CSIDL_Type_User,
1580 #endif
1581 NULL,
1582 L"Downloads"
1583 },
1584 { /* 0x48 */
1585 &FOLDERID_Games,
1586 CSIDL_Type_Disallowed,
1587 NULL,
1588 NULL
1589 },
1590 { /* 0x49 */
1591 &FOLDERID_GameTasks,
1592 CSIDL_Type_Disallowed, /* FIXME */
1593 NULL,
1594 NULL
1595 },
1596 { /* 0x4a */
1597 &FOLDERID_HomeGroup,
1598 CSIDL_Type_Disallowed,
1599 NULL,
1600 NULL
1601 },
1602 { /* 0x4b */
1603 &FOLDERID_ImplicitAppShortcuts,
1604 CSIDL_Type_Disallowed, /* FIXME */
1605 NULL,
1606 NULL
1607 },
1608 { /* 0x4c */
1609 &FOLDERID_Libraries,
1610 CSIDL_Type_Disallowed, /* FIXME */
1611 NULL,
1612 NULL
1613 },
1614 { /* 0x4d - CSIDL_LINKS */
1615 &FOLDERID_Links,
1616 CSIDL_Type_User,
1617 NULL,
1618 L"Links"
1619 },
1620 { /* 0x4e - CSIDL_APPDATA_LOCALLOW */
1621 &FOLDERID_LocalAppDataLow,
1622 CSIDL_Type_User,
1623 NULL,
1624 L"AppData\\LocalLow"
1625 },
1626 { /* 0x4f */
1627 &FOLDERID_MusicLibrary,
1628 CSIDL_Type_Disallowed, /* FIXME */
1629 NULL,
1630 NULL
1631 },
1632 { /* 0x50 */
1633 &FOLDERID_OriginalImages,
1634 CSIDL_Type_Disallowed, /* FIXME */
1635 NULL,
1636 NULL
1637 },
1638 { /* 0x51 */
1639 &FOLDERID_PhotoAlbums,
1640 CSIDL_Type_User,
1641 NULL,
1642 L"Pictures\\Slide Shows"
1643 },
1644 { /* 0x52 */
1645 &FOLDERID_PicturesLibrary,
1646 CSIDL_Type_Disallowed, /* FIXME */
1647 NULL,
1648 NULL
1649 },
1650 { /* 0x53 */
1651 &FOLDERID_Playlists,
1652 CSIDL_Type_User,
1653 NULL,
1654 L"Music\\Playlists"
1655 },
1656 { /* 0x54 */
1657 &FOLDERID_ProgramFilesX64,
1658 CSIDL_Type_NonExistent,
1659 NULL,
1660 NULL
1661 },
1662 { /* 0x55 */
1663 &FOLDERID_ProgramFilesCommonX64,
1664 CSIDL_Type_NonExistent,
1665 NULL,
1666 NULL
1667 },
1668 { /* 0x56 */
1669 &FOLDERID_Public,
1670 CSIDL_Type_CurrVer, /* FIXME */
1671 NULL,
1672 L"Users\\Public"
1673 },
1674 { /* 0x57 */
1675 &FOLDERID_PublicDownloads,
1676 CSIDL_Type_AllUsers,
1677 NULL,
1678 L"Downloads"
1679 },
1680 { /* 0x58 */
1681 &FOLDERID_PublicGameTasks,
1682 CSIDL_Type_AllUsers,
1683 NULL,
1684 L"Microsoft\\Windows\\GameExplorer"
1685 },
1686 { /* 0x59 */
1687 &FOLDERID_PublicLibraries,
1688 CSIDL_Type_AllUsers,
1689 NULL,
1690 L"Microsoft\\Windows\\Libraries"
1691 },
1692 { /* 0x5a */
1693 &FOLDERID_PublicRingtones,
1694 CSIDL_Type_AllUsers,
1695 NULL,
1696 L"Microsoft\\Windows\\Ringtones"
1697 },
1698 { /* 0x5b */
1699 &FOLDERID_QuickLaunch,
1700 CSIDL_Type_Disallowed, /* FIXME */
1701 NULL,
1702 NULL
1703 },
1704 { /* 0x5c */
1705 &FOLDERID_RecordedTVLibrary,
1706 CSIDL_Type_Disallowed, /* FIXME */
1707 NULL,
1708 NULL
1709 },
1710 { /* 0x5d */
1711 &FOLDERID_Ringtones,
1712 CSIDL_Type_Disallowed, /* FIXME */
1713 NULL,
1714 NULL
1715 },
1716 { /* 0x5e */
1717 &FOLDERID_SampleMusic,
1718 CSIDL_Type_AllUsers,
1719 NULL,
1720 L"Music\\Sample Music"
1721 },
1722 { /* 0x5f */
1723 &FOLDERID_SamplePictures,
1724 CSIDL_Type_AllUsers,
1725 NULL,
1726 L"Pictures\\Sample Pictures"
1727 },
1728 { /* 0x60 */
1729 &FOLDERID_SamplePlaylists,
1730 CSIDL_Type_AllUsers,
1731 NULL,
1732 L"Music\\Sample Playlists"
1733 },
1734 { /* 0x61 */
1735 &FOLDERID_SampleVideos,
1736 CSIDL_Type_AllUsers,
1737 NULL,
1738 L"Videos\\Sample Videos"
1739 },
1740 { /* 0x62 - CSIDL_SAVED_GAMES */
1741 &FOLDERID_SavedGames,
1742 CSIDL_Type_User,
1743 NULL,
1744 L"Saved Games"
1745 },
1746 { /* 0x63 - CSIDL_SEARCHES */
1747 &FOLDERID_SavedSearches,
1748 CSIDL_Type_User,
1749 NULL,
1750 L"Searches"
1751 },
1752 { /* 0x64 */
1753 &FOLDERID_SEARCH_CSC,
1754 CSIDL_Type_Disallowed,
1755 NULL,
1756 NULL
1757 },
1758 { /* 0x65 */
1759 &FOLDERID_SEARCH_MAPI,
1760 CSIDL_Type_Disallowed,
1761 NULL,
1762 NULL
1763 },
1764 { /* 0x66 */
1765 &FOLDERID_SearchHome,
1766 CSIDL_Type_Disallowed,
1767 NULL,
1768 NULL
1769 },
1770 { /* 0x67 */
1771 &FOLDERID_SidebarDefaultParts,
1772 CSIDL_Type_Disallowed, /* FIXME */
1773 NULL,
1774 NULL
1775 },
1776 { /* 0x68 */
1777 &FOLDERID_SidebarParts,
1778 CSIDL_Type_Disallowed, /* FIXME */
1779 NULL,
1780 NULL
1781 },
1782 { /* 0x69 */
1783 &FOLDERID_SyncManagerFolder,
1784 CSIDL_Type_Disallowed,
1785 NULL,
1786 NULL
1787 },
1788 { /* 0x6a */
1789 &FOLDERID_SyncResultsFolder,
1790 CSIDL_Type_Disallowed,
1791 NULL,
1792 NULL
1793 },
1794 { /* 0x6b */
1795 &FOLDERID_SyncSetupFolder,
1796 CSIDL_Type_Disallowed,
1797 NULL,
1798 NULL
1799 },
1800 { /* 0x6c */
1801 &FOLDERID_UserPinned,
1802 CSIDL_Type_Disallowed, /* FIXME */
1803 NULL,
1804 NULL
1805 },
1806 { /* 0x6d */
1807 &FOLDERID_UserProfiles,
1808 CSIDL_Type_CurrVer,
1809 L"Users",
1810 L"Users"
1811 },
1812 { /* 0x6e */
1813 &FOLDERID_UserProgramFiles,
1814 CSIDL_Type_Disallowed, /* FIXME */
1815 NULL,
1816 NULL
1817 },
1818 { /* 0x6f */
1819 &FOLDERID_UserProgramFilesCommon,
1820 CSIDL_Type_Disallowed, /* FIXME */
1821 NULL,
1822 NULL
1823 },
1824 { /* 0x70 */
1825 &FOLDERID_UsersFiles,
1826 CSIDL_Type_Disallowed,
1827 NULL,
1828 NULL
1829 },
1830 { /* 0x71 */
1831 &FOLDERID_UsersLibraries,
1832 CSIDL_Type_Disallowed,
1833 NULL,
1834 NULL
1835 },
1836 { /* 0x72 */
1837 &FOLDERID_VideosLibrary,
1838 CSIDL_Type_Disallowed, /* FIXME */
1839 NULL,
1840 NULL
1841 }
1842 #endif
1843 };
1844
SHGetSpecialFolderID(_In_ LPCWSTR pszName)1845 INT SHGetSpecialFolderID(_In_ LPCWSTR pszName)
1846 {
1847 UINT csidl;
1848
1849 for (csidl = 0; csidl < _countof(CSIDL_Data); ++csidl)
1850 {
1851 const CSIDL_DATA *pData = &CSIDL_Data[csidl];
1852 if (pData->szValueName && lstrcmpiW(pszName, pData->szValueName) == 0)
1853 return csidl;
1854 }
1855
1856 return -1;
1857 }
1858
Shell_ParseSpecialFolder(_In_ LPCWSTR pszStart,_Out_ LPWSTR * ppch,_Out_ INT * pcch)1859 INT Shell_ParseSpecialFolder(_In_ LPCWSTR pszStart, _Out_ LPWSTR *ppch, _Out_ INT *pcch)
1860 {
1861 LPCWSTR pszPath, pchBackslash;
1862 WCHAR szPath[MAX_PATH];
1863
1864 pchBackslash = StrChrW(pszStart, L'\\');
1865 if (pchBackslash)
1866 {
1867 *ppch = (LPWSTR)(pchBackslash + 1);
1868 *pcch = (pchBackslash - pszStart) + 1;
1869 StrCpyNW(szPath, pszStart, min(*pcch, _countof(szPath)));
1870 pszPath = szPath;
1871 }
1872 else
1873 {
1874 *ppch = NULL;
1875 *pcch = lstrlenW(pszStart);
1876 pszPath = pszStart;
1877 }
1878
1879 return SHGetSpecialFolderID(pszPath);
1880 }
1881
1882 #ifndef __REACTOS__
1883 static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest);
1884 #else
1885 static HRESULT _SHExpandEnvironmentStrings(HANDLE hToken, LPCWSTR szSrc, LPWSTR szDest, DWORD cchDest);
1886 #endif
1887
1888 /* Gets the value named value from the registry key
1889 * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
1890 * (or from rootKey\userPrefix\... if userPrefix is not NULL) into path, which
1891 * is assumed to be MAX_PATH WCHARs in length.
1892 * If it exists, expands the value and writes the expanded value to
1893 * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
1894 * Returns successful error code if the value was retrieved from the registry,
1895 * and a failure otherwise.
1896 */
1897 #ifndef __REACTOS__
_SHGetUserShellFolderPath(HKEY rootKey,LPCWSTR userPrefix,LPCWSTR value,LPWSTR path)1898 static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix,
1899 #else
1900 static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, HANDLE hToken, LPCWSTR userPrefix,
1901 #endif
1902 LPCWSTR value, LPWSTR path)
1903 {
1904 HRESULT hr;
1905 WCHAR shellFolderPath[MAX_PATH], userShellFolderPath[MAX_PATH];
1906 LPCWSTR pShellFolderPath, pUserShellFolderPath;
1907 HKEY userShellFolderKey, shellFolderKey;
1908 DWORD dwType, dwPathLen;
1909
1910 TRACE("%p,%s,%s,%p\n",rootKey, debugstr_w(userPrefix), debugstr_w(value),
1911 path);
1912
1913 if (userPrefix)
1914 {
1915 strcpyW(shellFolderPath, userPrefix);
1916 PathAddBackslashW(shellFolderPath);
1917 strcatW(shellFolderPath, szSHFolders);
1918 pShellFolderPath = shellFolderPath;
1919 strcpyW(userShellFolderPath, userPrefix);
1920 PathAddBackslashW(userShellFolderPath);
1921 strcatW(userShellFolderPath, szSHUserFolders);
1922 pUserShellFolderPath = userShellFolderPath;
1923 }
1924 else
1925 {
1926 pUserShellFolderPath = szSHUserFolders;
1927 pShellFolderPath = szSHFolders;
1928 }
1929
1930 if (RegCreateKeyW(rootKey, pShellFolderPath, &shellFolderKey))
1931 {
1932 TRACE("Failed to create %s\n", debugstr_w(pShellFolderPath));
1933 return E_FAIL;
1934 }
1935 if (RegCreateKeyW(rootKey, pUserShellFolderPath, &userShellFolderKey))
1936 {
1937 TRACE("Failed to create %s\n",
1938 debugstr_w(pUserShellFolderPath));
1939 RegCloseKey(shellFolderKey);
1940 return E_FAIL;
1941 }
1942
1943 dwPathLen = MAX_PATH * sizeof(WCHAR);
1944 if (!RegQueryValueExW(userShellFolderKey, value, NULL, &dwType,
1945 (LPBYTE)path, &dwPathLen) && (dwType == REG_EXPAND_SZ || dwType == REG_SZ))
1946 {
1947 LONG ret;
1948
1949 path[dwPathLen / sizeof(WCHAR)] = '\0';
1950 if (dwType == REG_EXPAND_SZ && path[0] == '%')
1951 {
1952 WCHAR szTemp[MAX_PATH];
1953
1954 #ifndef __REACTOS__
1955 _SHExpandEnvironmentStrings(path, szTemp);
1956 #else
1957 hr = _SHExpandEnvironmentStrings(hToken, path, szTemp, _countof(szTemp));
1958 if (FAILED(hr))
1959 goto end;
1960 #endif
1961 lstrcpynW(path, szTemp, MAX_PATH);
1962 }
1963 ret = RegSetValueExW(shellFolderKey, value, 0, REG_SZ, (LPBYTE)path,
1964 (strlenW(path) + 1) * sizeof(WCHAR));
1965 if (ret != ERROR_SUCCESS)
1966 hr = HRESULT_FROM_WIN32(ret);
1967 else
1968 hr = S_OK;
1969 }
1970 else
1971 hr = E_FAIL;
1972 #ifdef __REACTOS__
1973 end:
1974 #endif
1975 RegCloseKey(shellFolderKey);
1976 RegCloseKey(userShellFolderKey);
1977 TRACE("returning 0x%08x\n", hr);
1978 return hr;
1979 }
1980
_SHGetUserProfileDirectoryW(HANDLE hToken,LPWSTR szPath,LPDWORD lpcchPath)1981 BOOL _SHGetUserProfileDirectoryW(HANDLE hToken, LPWSTR szPath, LPDWORD lpcchPath)
1982 {
1983 BOOL result;
1984 if (!hToken)
1985 {
1986 OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
1987 result = GetUserProfileDirectoryW(hToken, szPath, lpcchPath);
1988 CloseHandle(hToken);
1989 }
1990 else if ((INT) hToken == -1)
1991 {
1992 result = GetDefaultUserProfileDirectoryW(szPath, lpcchPath);
1993 }
1994 else
1995 {
1996 result = GetUserProfileDirectoryW(hToken, szPath, lpcchPath);
1997 }
1998 TRACE("_SHGetUserProfileDirectoryW returning %S\n", szPath);
1999 return result;
2000 }
2001
2002 /* Gets a 'semi-expanded' default value of the CSIDL with index folder into
2003 * pszPath, based on the entries in CSIDL_Data. By semi-expanded, I mean:
2004 * - The entry's szDefaultPath may be either a string value or an integer
2005 * resource identifier. In the latter case, the string value of the resource
2006 * is written.
2007 * - Depending on the entry's type, the path may begin with an (unexpanded)
2008 * environment variable name. The caller is responsible for expanding
2009 * environment strings if so desired.
2010 * The types that are prepended with environment variables are:
2011 * CSIDL_Type_User: %USERPROFILE%
2012 * CSIDL_Type_AllUsers: %ALLUSERSPROFILE%
2013 * CSIDL_Type_CurrVer: %SystemDrive%
2014 * (Others might make sense too, but as yet are unneeded.)
2015 */
2016 #ifndef __REACTOS__
_SHGetDefaultValue(BYTE folder,LPWSTR pszPath)2017 static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath)
2018 #else
2019 static HRESULT _SHGetDefaultValue(HANDLE hToken, BYTE folder, LPWSTR pszPath)
2020 #endif
2021 {
2022 HRESULT hr;
2023 WCHAR resourcePath[MAX_PATH];
2024 #ifdef __REACTOS__
2025 NT_PRODUCT_TYPE ProductType;
2026 #endif
2027
2028 TRACE("0x%02x,%p\n", folder, pszPath);
2029
2030 if (folder >= ARRAY_SIZE(CSIDL_Data))
2031 return E_INVALIDARG;
2032
2033 if (!pszPath)
2034 return E_INVALIDARG;
2035
2036 #ifdef __REACTOS__
2037 if (hToken != NULL && hToken != (HANDLE)-1)
2038 {
2039 FIXME("unsupported for user other than current or default\n");
2040 }
2041 #endif
2042
2043 if (!is_win64)
2044 {
2045 BOOL is_wow64;
2046
2047 switch (folder)
2048 {
2049 case CSIDL_PROGRAM_FILES:
2050 case CSIDL_PROGRAM_FILESX86:
2051 IsWow64Process( GetCurrentProcess(), &is_wow64 );
2052 folder = is_wow64 ? CSIDL_PROGRAM_FILESX86 : CSIDL_PROGRAM_FILES;
2053 break;
2054 case CSIDL_PROGRAM_FILES_COMMON:
2055 case CSIDL_PROGRAM_FILES_COMMONX86:
2056 IsWow64Process( GetCurrentProcess(), &is_wow64 );
2057 folder = is_wow64 ? CSIDL_PROGRAM_FILES_COMMONX86 : CSIDL_PROGRAM_FILES_COMMON;
2058 break;
2059 }
2060 }
2061
2062 switch (CSIDL_Data[folder].type)
2063 {
2064 case CSIDL_Type_User:
2065 strcpyW(pszPath, L"%USERPROFILE%");
2066 break;
2067 #ifdef __REACTOS__
2068 case CSIDL_Type_InMyDocuments:
2069 strcpyW(pszPath, L"%USERPROFILE%");
2070 if (DoGetProductType(&ProductType) && ProductType == NtProductWinNt)
2071 {
2072 if (IS_INTRESOURCE(CSIDL_Data[CSIDL_MYDOCUMENTS].szDefaultPath))
2073 {
2074 WCHAR szItem[MAX_PATH];
2075 LoadStringW(shell32_hInstance,
2076 LOWORD(CSIDL_Data[CSIDL_MYDOCUMENTS].szDefaultPath),
2077 szItem, ARRAY_SIZE(szItem));
2078 PathAppendW(pszPath, szItem);
2079 }
2080 else
2081 {
2082 PathAppendW(pszPath, CSIDL_Data[CSIDL_MYDOCUMENTS].szDefaultPath);
2083 }
2084 }
2085 break;
2086 #endif
2087 case CSIDL_Type_AllUsers:
2088 #ifndef __REACTOS__
2089 strcpyW(pszPath, L"%PUBLIC%");
2090 #else
2091 strcpyW(pszPath, L"%ALLUSERSPROFILE%");
2092 #endif
2093 break;
2094 case CSIDL_Type_CurrVer:
2095 strcpyW(pszPath, L"%SystemDrive%");
2096 break;
2097 default:
2098 ; /* no corresponding env. var, do nothing */
2099 }
2100
2101 hr = S_OK;
2102 if (CSIDL_Data[folder].szDefaultPath)
2103 {
2104 if (IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath))
2105 {
2106 if (LoadStringW(shell32_hInstance,
2107 LOWORD(CSIDL_Data[folder].szDefaultPath), resourcePath, MAX_PATH))
2108 {
2109 PathAppendW(pszPath, resourcePath);
2110 }
2111 else
2112 {
2113 ERR("(%d,%s), LoadString failed, missing translation?\n", folder,
2114 debugstr_w(pszPath));
2115 hr = E_FAIL;
2116 }
2117 }
2118 else
2119 {
2120 PathAppendW(pszPath, CSIDL_Data[folder].szDefaultPath);
2121 }
2122 }
2123 TRACE("returning 0x%08x\n", hr);
2124 return hr;
2125 }
2126
2127 /* Gets the (unexpanded) value of the folder with index folder into pszPath.
2128 * The folder's type is assumed to be CSIDL_Type_CurrVer. Its default value
2129 * can be overridden in the HKLM\\Software\\Microsoft\\Windows\\CurrentVersion key.
2130 * If dwFlags has SHGFP_TYPE_DEFAULT set or if the value isn't overridden in
2131 * the registry, uses _SHGetDefaultValue to get the value.
2132 */
_SHGetCurrentVersionPath(DWORD dwFlags,BYTE folder,LPWSTR pszPath)2133 static HRESULT _SHGetCurrentVersionPath(DWORD dwFlags, BYTE folder,
2134 LPWSTR pszPath)
2135 {
2136 HRESULT hr;
2137
2138 TRACE("0x%08x,0x%02x,%p\n", dwFlags, folder, pszPath);
2139
2140 if (folder >= ARRAY_SIZE(CSIDL_Data))
2141 return E_INVALIDARG;
2142 if (CSIDL_Data[folder].type != CSIDL_Type_CurrVer)
2143 return E_INVALIDARG;
2144 if (!pszPath)
2145 return E_INVALIDARG;
2146
2147 if (dwFlags & SHGFP_TYPE_DEFAULT)
2148 #ifndef __REACTOS__
2149 hr = _SHGetDefaultValue(folder, pszPath);
2150 #else
2151 hr = _SHGetDefaultValue(NULL, folder, pszPath);
2152 #endif
2153 else
2154 {
2155 HKEY hKey;
2156
2157 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", &hKey))
2158 hr = E_FAIL;
2159 else
2160 {
2161 DWORD dwType, dwPathLen = MAX_PATH * sizeof(WCHAR);
2162
2163 if (RegQueryValueExW(hKey, CSIDL_Data[folder].szValueName, NULL,
2164 &dwType, (LPBYTE)pszPath, &dwPathLen) ||
2165 (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
2166 {
2167 #ifndef __REACTOS__
2168 hr = _SHGetDefaultValue(folder, pszPath);
2169 #else
2170 hr = _SHGetDefaultValue(NULL, folder, pszPath);
2171 #endif
2172 dwType = REG_EXPAND_SZ;
2173 switch (folder)
2174 {
2175 case CSIDL_PROGRAM_FILESX86:
2176 case CSIDL_PROGRAM_FILES_COMMONX86:
2177 /* these two should never be set on 32-bit setups */
2178 if (!is_win64)
2179 {
2180 BOOL is_wow64;
2181 IsWow64Process( GetCurrentProcess(), &is_wow64 );
2182 if (!is_wow64) break;
2183 }
2184 /* fall through */
2185 default:
2186 RegSetValueExW(hKey, CSIDL_Data[folder].szValueName, 0, dwType,
2187 (LPBYTE)pszPath, (strlenW(pszPath)+1)*sizeof(WCHAR));
2188 }
2189 }
2190 else
2191 {
2192 pszPath[dwPathLen / sizeof(WCHAR)] = '\0';
2193 hr = S_OK;
2194 }
2195 RegCloseKey(hKey);
2196 }
2197 }
2198 TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath));
2199 return hr;
2200 }
2201
_GetUserSidStringFromToken(HANDLE Token)2202 static LPWSTR _GetUserSidStringFromToken(HANDLE Token)
2203 {
2204 char InfoBuffer[64];
2205 PTOKEN_USER UserInfo;
2206 DWORD InfoSize;
2207 LPWSTR SidStr;
2208
2209 UserInfo = (PTOKEN_USER) InfoBuffer;
2210 if (! GetTokenInformation(Token, TokenUser, InfoBuffer, sizeof(InfoBuffer),
2211 &InfoSize))
2212 {
2213 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2214 return NULL;
2215 UserInfo = HeapAlloc(GetProcessHeap(), 0, InfoSize);
2216 if (UserInfo == NULL)
2217 return NULL;
2218 if (! GetTokenInformation(Token, TokenUser, UserInfo, InfoSize,
2219 &InfoSize))
2220 {
2221 HeapFree(GetProcessHeap(), 0, UserInfo);
2222 return NULL;
2223 }
2224 }
2225
2226 if (! ConvertSidToStringSidW(UserInfo->User.Sid, &SidStr))
2227 SidStr = NULL;
2228
2229 if (UserInfo != (PTOKEN_USER) InfoBuffer)
2230 HeapFree(GetProcessHeap(), 0, UserInfo);
2231
2232 return SidStr;
2233 }
2234
2235 /* Gets the user's path (unexpanded) for the CSIDL with index folder:
2236 * If SHGFP_TYPE_DEFAULT is set, calls _SHGetDefaultValue for it. Otherwise
2237 * calls _SHGetUserShellFolderPath for it. Where it looks depends on hToken:
2238 * - if hToken is -1, looks in HKEY_USERS\.Default
2239 * - otherwise looks first in HKEY_CURRENT_USER, followed by HKEY_LOCAL_MACHINE
2240 * if HKEY_CURRENT_USER doesn't contain any entries. If both fail, finally
2241 * calls _SHGetDefaultValue for it.
2242 */
_SHGetUserProfilePath(HANDLE hToken,DWORD dwFlags,BYTE folder,LPWSTR pszPath)2243 static HRESULT _SHGetUserProfilePath(HANDLE hToken, DWORD dwFlags, BYTE folder,
2244 LPWSTR pszPath)
2245 {
2246 const WCHAR *szValueName;
2247 WCHAR buffer[40];
2248 HRESULT hr;
2249
2250 TRACE("%p,0x%08x,0x%02x,%p\n", hToken, dwFlags, folder, pszPath);
2251
2252 if (folder >= ARRAY_SIZE(CSIDL_Data))
2253 return E_INVALIDARG;
2254 #ifdef __REACTOS__
2255 if (CSIDL_Data[folder].type != CSIDL_Type_User &&
2256 CSIDL_Data[folder].type != CSIDL_Type_InMyDocuments)
2257 #else
2258 if (CSIDL_Data[folder].type != CSIDL_Type_User)
2259 #endif
2260 {
2261 return E_INVALIDARG;
2262 }
2263 if (!pszPath)
2264 return E_INVALIDARG;
2265
2266 if (dwFlags & SHGFP_TYPE_DEFAULT)
2267 {
2268 #ifndef __REACTOS__
2269 hr = _SHGetDefaultValue(folder, pszPath);
2270 #else
2271 hr = _SHGetDefaultValue(hToken, folder, pszPath);
2272 #endif
2273 }
2274 else
2275 {
2276 static const WCHAR DefaultW[] = L".Default";
2277 LPCWSTR userPrefix = NULL;
2278 HKEY hRootKey;
2279
2280 if (hToken == (HANDLE)-1)
2281 {
2282 hRootKey = HKEY_USERS;
2283 userPrefix = DefaultW;
2284 }
2285 else if (hToken == NULL)
2286 hRootKey = HKEY_CURRENT_USER;
2287 else
2288 {
2289 hRootKey = HKEY_USERS;
2290 userPrefix = _GetUserSidStringFromToken(hToken);
2291 if (userPrefix == NULL)
2292 {
2293 hr = E_FAIL;
2294 goto error;
2295 }
2296 }
2297
2298 /* For CSIDL_Type_User we also use the GUID if no szValueName is provided */
2299 szValueName = CSIDL_Data[folder].szValueName;
2300 if (!szValueName)
2301 {
2302 StringFromGUID2( CSIDL_Data[folder].id, buffer, 39 );
2303 szValueName = &buffer[0];
2304 }
2305
2306 #ifndef __REACTOS__
2307 hr = _SHGetUserShellFolderPath(hRootKey, userPrefix, szValueName, pszPath);
2308 if (FAILED(hr) && hRootKey != HKEY_LOCAL_MACHINE)
2309 hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, szValueName, pszPath);
2310 if (FAILED(hr))
2311 hr = _SHGetDefaultValue(folder, pszPath);
2312 #else
2313 hr = _SHGetUserShellFolderPath(hRootKey, hToken, userPrefix, szValueName, pszPath);
2314 if (FAILED(hr) && hRootKey != HKEY_LOCAL_MACHINE)
2315 hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, hToken, NULL, szValueName, pszPath);
2316 if (FAILED(hr))
2317 hr = _SHGetDefaultValue(hToken, folder, pszPath);
2318 #endif
2319 if (userPrefix != NULL && userPrefix != DefaultW)
2320 LocalFree((HLOCAL) userPrefix);
2321 }
2322 error:
2323 TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath));
2324 return hr;
2325 }
2326
2327 /* Gets the (unexpanded) path for the CSIDL with index folder. If dwFlags has
2328 * SHGFP_TYPE_DEFAULT set, calls _SHGetDefaultValue. Otherwise calls
2329 * _SHGetUserShellFolderPath for it, looking only in HKEY_LOCAL_MACHINE.
2330 * If this fails, falls back to _SHGetDefaultValue.
2331 */
_SHGetAllUsersProfilePath(DWORD dwFlags,BYTE folder,LPWSTR pszPath)2332 static HRESULT _SHGetAllUsersProfilePath(DWORD dwFlags, BYTE folder,
2333 LPWSTR pszPath)
2334 {
2335 HRESULT hr;
2336
2337 TRACE("0x%08x,0x%02x,%p\n", dwFlags, folder, pszPath);
2338
2339 if (folder >= ARRAY_SIZE(CSIDL_Data))
2340 return E_INVALIDARG;
2341 if (CSIDL_Data[folder].type != CSIDL_Type_AllUsers)
2342 return E_INVALIDARG;
2343 if (!pszPath)
2344 return E_INVALIDARG;
2345
2346 if (dwFlags & SHGFP_TYPE_DEFAULT)
2347 #ifndef __REACTOS__
2348 hr = _SHGetDefaultValue(folder, pszPath);
2349 #else
2350 hr = _SHGetDefaultValue(NULL, folder, pszPath);
2351 #endif
2352 else
2353 {
2354 #ifndef __REACTOS__
2355 hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL,
2356 #else
2357 hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, NULL,
2358 #endif
2359 CSIDL_Data[folder].szValueName, pszPath);
2360 if (FAILED(hr))
2361 #ifndef __REACTOS__
2362 hr = _SHGetDefaultValue(folder, pszPath);
2363 #else
2364 hr = _SHGetDefaultValue(NULL, folder, pszPath);
2365 #endif
2366 }
2367 TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath));
2368 return hr;
2369 }
2370
2371 #ifndef __REACTOS__
_SHOpenProfilesKey(PHKEY pKey)2372 static HRESULT _SHOpenProfilesKey(PHKEY pKey)
2373 {
2374 LONG lRet;
2375 DWORD disp;
2376
2377 lRet = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList", 0, NULL, 0,
2378 KEY_ALL_ACCESS, NULL, pKey, &disp);
2379 return HRESULT_FROM_WIN32(lRet);
2380 }
2381
2382 /* Reads the value named szValueName from the key profilesKey (assumed to be
2383 * opened by _SHOpenProfilesKey) into szValue, which is assumed to be MAX_PATH
2384 * WCHARs in length. If it doesn't exist, returns szDefault (and saves
2385 * szDefault to the registry).
2386 */
_SHGetProfilesValue(HKEY profilesKey,LPCWSTR szValueName,LPWSTR szValue,LPCWSTR szDefault)2387 static HRESULT _SHGetProfilesValue(HKEY profilesKey, LPCWSTR szValueName,
2388 LPWSTR szValue, LPCWSTR szDefault)
2389 {
2390 HRESULT hr;
2391 DWORD type, dwPathLen = MAX_PATH * sizeof(WCHAR);
2392 LONG lRet;
2393
2394 TRACE("%p,%s,%p,%s\n", profilesKey, debugstr_w(szValueName), szValue,
2395 debugstr_w(szDefault));
2396 lRet = RegQueryValueExW(profilesKey, szValueName, NULL, &type,
2397 (LPBYTE)szValue, &dwPathLen);
2398 if (!lRet && (type == REG_SZ || type == REG_EXPAND_SZ) && dwPathLen
2399 && *szValue)
2400 {
2401 dwPathLen /= sizeof(WCHAR);
2402 szValue[dwPathLen] = '\0';
2403 hr = S_OK;
2404 }
2405 else
2406 {
2407 /* Missing or invalid value, set a default */
2408 lstrcpynW(szValue, szDefault, MAX_PATH);
2409 TRACE("Setting missing value %s to %s\n", debugstr_w(szValueName),
2410 debugstr_w(szValue));
2411 lRet = RegSetValueExW(profilesKey, szValueName, 0, REG_EXPAND_SZ,
2412 (LPBYTE)szValue,
2413 (strlenW(szValue) + 1) * sizeof(WCHAR));
2414 if (lRet)
2415 hr = HRESULT_FROM_WIN32(lRet);
2416 else
2417 hr = S_OK;
2418 }
2419 TRACE("returning 0x%08x (output value is %s)\n", hr, debugstr_w(szValue));
2420 return hr;
2421 }
2422 #endif
2423
2424 /* Attempts to expand environment variables from szSrc into szDest, which is
2425 * assumed to be MAX_PATH characters in length. Before referring to the
2426 * environment, handles a few variables directly, because the environment
2427 * variables may not be set when this is called (as during Wine's installation
2428 * when default values are being written to the registry).
2429 * The directly handled environment variables, and their source, are:
2430 * - ALLUSERSPROFILE, USERPROFILE: reads from the registry
2431 * - SystemDrive: uses GetSystemDirectoryW and uses the drive portion of its
2432 * path
2433 * If one of the directly handled environment variables is expanded, only
2434 * expands a single variable, and only in the beginning of szSrc.
2435 */
2436 #ifndef __REACTOS__
_SHExpandEnvironmentStrings(LPCWSTR szSrc,LPWSTR szDest)2437 static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest)
2438 #else
2439 static HRESULT _SHExpandEnvironmentStrings(HANDLE hToken, LPCWSTR szSrc, LPWSTR szDest, DWORD cchDest)
2440 #endif
2441 {
2442 HRESULT hr;
2443 #ifndef __REACTOS__
2444 WCHAR szTemp[MAX_PATH], szProfilesPrefix[MAX_PATH] = { 0 };
2445 HKEY key = NULL;
2446 #else
2447 WCHAR szTemp[MAX_PATH];
2448 #endif
2449
2450 TRACE("%s, %p\n", debugstr_w(szSrc), szDest);
2451
2452 if (!szSrc || !szDest) return E_INVALIDARG;
2453
2454 /* short-circuit if there's nothing to expand */
2455 if (szSrc[0] != '%')
2456 {
2457 strcpyW(szDest, szSrc);
2458 hr = S_OK;
2459 goto end;
2460 }
2461 #ifndef __REACTOS__
2462 /* Get the profile prefix, we'll probably be needing it */
2463 hr = _SHOpenProfilesKey(&key);
2464 if (SUCCEEDED(hr))
2465 {
2466 WCHAR def_val[MAX_PATH];
2467
2468 /* get the system drive */
2469 GetSystemDirectoryW(def_val, MAX_PATH);
2470 strcpyW( def_val + 3, L"Users" );
2471
2472 hr = _SHGetProfilesValue(key, L"ProfilesDirectory", szProfilesPrefix, def_val );
2473 }
2474 #else
2475 hr = S_OK;
2476 #endif
2477
2478 *szDest = 0;
2479 strcpyW(szTemp, szSrc);
2480 while (SUCCEEDED(hr) && szTemp[0] == '%')
2481 {
2482 if (!strncmpiW(szTemp, L"%ALLUSERSPROFILE%", ARRAY_SIZE(L"%ALLUSERSPROFILE%")-1))
2483 {
2484 #ifndef __REACTOS__
2485 WCHAR szAllUsers[MAX_PATH];
2486
2487 strcpyW(szDest, szProfilesPrefix);
2488 hr = _SHGetProfilesValue(key, L"AllUsersProfile", szAllUsers, L"Public");
2489 PathAppendW(szDest, szAllUsers);
2490 #else
2491 DWORD cchSize = cchDest;
2492 if (!GetAllUsersProfileDirectoryW(szDest, &cchSize))
2493 goto fallback_expand;
2494 #endif
2495 PathAppendW(szDest, szTemp + ARRAY_SIZE(L"%ALLUSERSPROFILE%")-1);
2496 }
2497 #ifndef __REACTOS__
2498 else if (!strncmpiW(szTemp, L"%PUBLIC%", ARRAY_SIZE(L"%PUBLIC%")-1))
2499 {
2500 WCHAR szAllUsers[MAX_PATH], def_val[MAX_PATH];
2501
2502 GetSystemDirectoryW(def_val, MAX_PATH);
2503 strcpyW( def_val + 3, L"Users\\Public" );
2504
2505 hr = _SHGetProfilesValue(key, L"Public", szAllUsers, def_val);
2506 PathAppendW(szDest, szAllUsers);
2507 PathAppendW(szDest, szTemp + ARRAY_SIZE(L"%PUBLIC%")-1);
2508 }
2509 #endif
2510 else if (!strncmpiW(szTemp, L"%USERPROFILE%", ARRAY_SIZE(L"%USERPROFILE%")-1))
2511 {
2512 #ifndef __REACTOS__
2513 WCHAR userName[MAX_PATH];
2514 DWORD userLen = MAX_PATH;
2515
2516 strcpyW(szDest, szProfilesPrefix);
2517 GetUserNameW(userName, &userLen);
2518 PathAppendW(szDest, userName);
2519 #else
2520 DWORD cchSize = cchDest;
2521 if (!_SHGetUserProfileDirectoryW(hToken, szDest, &cchSize))
2522 goto fallback_expand;
2523 #endif
2524 PathAppendW(szDest, szTemp + ARRAY_SIZE(L"%USERPROFILE%")-1);
2525 }
2526 else if (!strncmpiW(szTemp, L"%SystemDrive%", ARRAY_SIZE(L"%SystemDrive%")-1))
2527 {
2528 #ifndef __REACTOS__
2529 GetSystemDirectoryW(szDest, MAX_PATH);
2530 #else
2531 if (!GetSystemDirectoryW(szDest, cchDest))
2532 goto fallback_expand;
2533 #endif
2534 strcpyW(szDest + 3, szTemp + ARRAY_SIZE(L"%SystemDrive%")-1 + 1);
2535 }
2536 else
2537 #ifdef __REACTOS__
2538 fallback_expand:
2539 #endif
2540 {
2541 #ifndef __REACTOS__
2542 DWORD ret = ExpandEnvironmentStringsW(szTemp, szDest, MAX_PATH);
2543 #else
2544 DWORD ret = SHExpandEnvironmentStringsForUserW(hToken, szTemp, szDest, cchDest);
2545 #endif
2546
2547 #ifndef __REACTOS__
2548 if (ret > MAX_PATH)
2549 #else
2550 if (ret > cchDest)
2551 #endif
2552 hr = E_NOT_SUFFICIENT_BUFFER;
2553 else if (ret == 0)
2554 hr = HRESULT_FROM_WIN32(GetLastError());
2555 else if (!strcmpW( szTemp, szDest )) break; /* nothing expanded */
2556 }
2557 if (SUCCEEDED(hr)) strcpyW(szTemp, szDest);
2558 }
2559 end:
2560 #ifndef __REACTOS__
2561 if (key)
2562 RegCloseKey(key);
2563 #endif
2564 TRACE("returning 0x%08x (input was %s, output is %s)\n", hr,
2565 debugstr_w(szSrc), debugstr_w(szDest));
2566 return hr;
2567 }
2568
2569 /*************************************************************************
2570 * SHGetFolderPathW [SHELL32.@]
2571 *
2572 * Convert nFolder to path.
2573 *
2574 * RETURNS
2575 * Success: S_OK
2576 * Failure: standard HRESULT error codes.
2577 *
2578 * NOTES
2579 * Most values can be overridden in either
2580 * HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
2581 * or in the same location in HKLM.
2582 * The "Shell Folders" registry key was used in NT4 and earlier systems.
2583 * Beginning with Windows 2000, the "User Shell Folders" key is used, so
2584 * changes made to it are made to the former key too. This synchronization is
2585 * done on-demand: not until someone requests the value of one of these paths
2586 * (by calling one of the SHGet functions) is the value synchronized.
2587 * Furthermore, the HKCU paths take precedence over the HKLM paths.
2588 */
SHGetFolderPathW(HWND hwndOwner,int nFolder,HANDLE hToken,DWORD dwFlags,LPWSTR pszPath)2589 HRESULT WINAPI SHGetFolderPathW(
2590 HWND hwndOwner, /* [I] owner window */
2591 int nFolder, /* [I] CSIDL identifying the folder */
2592 HANDLE hToken, /* [I] access token */
2593 DWORD dwFlags, /* [I] which path to return */
2594 LPWSTR pszPath) /* [O] converted path */
2595 {
2596 HRESULT hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, NULL, pszPath);
2597 if(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
2598 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
2599 return hr;
2600 }
2601
SHGetFolderPathAndSubDirA(HWND hwndOwner,int nFolder,HANDLE hToken,DWORD dwFlags,LPCSTR pszSubPath,LPSTR pszPath)2602 HRESULT WINAPI SHGetFolderPathAndSubDirA(
2603 HWND hwndOwner, /* [I] owner window */
2604 int nFolder, /* [I] CSIDL identifying the folder */
2605 HANDLE hToken, /* [I] access token */
2606 DWORD dwFlags, /* [I] which path to return */
2607 LPCSTR pszSubPath, /* [I] sub directory of the specified folder */
2608 LPSTR pszPath) /* [O] converted path */
2609 {
2610 int length;
2611 HRESULT hr = S_OK;
2612 LPWSTR pszSubPathW = NULL;
2613 LPWSTR pszPathW = NULL;
2614
2615 TRACE("%p,%#x,%p,%#x,%s,%p\n", hwndOwner, nFolder, hToken, dwFlags, debugstr_a(pszSubPath), pszPath);
2616
2617 if(pszPath) {
2618 pszPathW = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
2619 if(!pszPathW) {
2620 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
2621 goto cleanup;
2622 }
2623 }
2624 TRACE("%08x,%08x,%s\n",nFolder, dwFlags, debugstr_w(pszSubPathW));
2625
2626 /* SHGetFolderPathAndSubDirW does not distinguish if pszSubPath isn't
2627 * set (null), or an empty string.therefore call it without the parameter set
2628 * if pszSubPath is an empty string
2629 */
2630 if (pszSubPath && pszSubPath[0]) {
2631 length = MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, NULL, 0);
2632 pszSubPathW = HeapAlloc(GetProcessHeap(), 0, length * sizeof(WCHAR));
2633 if(!pszSubPathW) {
2634 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
2635 goto cleanup;
2636 }
2637 MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, pszSubPathW, length);
2638 }
2639
2640 hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, pszSubPathW, pszPathW);
2641
2642 if (SUCCEEDED(hr) && pszPath)
2643 WideCharToMultiByte(CP_ACP, 0, pszPathW, -1, pszPath, MAX_PATH, NULL, NULL);
2644
2645 cleanup:
2646 HeapFree(GetProcessHeap(), 0, pszPathW);
2647 HeapFree(GetProcessHeap(), 0, pszSubPathW);
2648 return hr;
2649 }
2650
2651 /*************************************************************************
2652 * SHGetFolderPathAndSubDirW [SHELL32.@]
2653 */
SHGetFolderPathAndSubDirW(HWND hwndOwner,int nFolder,HANDLE hToken,DWORD dwFlags,LPCWSTR pszSubPath,LPWSTR pszPath)2654 HRESULT WINAPI SHGetFolderPathAndSubDirW(
2655 HWND hwndOwner, /* [I] owner window */
2656 int nFolder, /* [I] CSIDL identifying the folder */
2657 HANDLE hToken, /* [I] access token */
2658 DWORD dwFlags, /* [I] which path to return */
2659 LPCWSTR pszSubPath,/* [I] sub directory of the specified folder */
2660 LPWSTR pszPath) /* [O] converted path */
2661 {
2662 HRESULT hr;
2663 WCHAR szBuildPath[MAX_PATH], szTemp[MAX_PATH];
2664 DWORD folder = nFolder & CSIDL_FOLDER_MASK;
2665 CSIDL_Type type;
2666 int ret;
2667
2668 TRACE("%p,%#x,%p,%#x,%s,%p\n", hwndOwner, nFolder, hToken, dwFlags, debugstr_w(pszSubPath), pszPath);
2669
2670 /* Windows always NULL-terminates the resulting path regardless of success
2671 * or failure, so do so first
2672 */
2673 if (pszPath)
2674 *pszPath = '\0';
2675
2676 if (folder >= ARRAY_SIZE(CSIDL_Data))
2677 return E_INVALIDARG;
2678 if ((SHGFP_TYPE_CURRENT != dwFlags) && (SHGFP_TYPE_DEFAULT != dwFlags))
2679 return E_INVALIDARG;
2680 szTemp[0] = 0;
2681 type = CSIDL_Data[folder].type;
2682 switch (type)
2683 {
2684 case CSIDL_Type_Disallowed:
2685 hr = E_INVALIDARG;
2686 break;
2687 case CSIDL_Type_NonExistent:
2688 hr = S_FALSE;
2689 break;
2690 case CSIDL_Type_WindowsPath:
2691 GetWindowsDirectoryW(szTemp, MAX_PATH);
2692 if (CSIDL_Data[folder].szDefaultPath &&
2693 !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) &&
2694 *CSIDL_Data[folder].szDefaultPath)
2695 {
2696 PathAddBackslashW(szTemp);
2697 strcatW(szTemp, CSIDL_Data[folder].szDefaultPath);
2698 }
2699 hr = S_OK;
2700 break;
2701 case CSIDL_Type_SystemPath:
2702 GetSystemDirectoryW(szTemp, MAX_PATH);
2703 if (CSIDL_Data[folder].szDefaultPath &&
2704 !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) &&
2705 *CSIDL_Data[folder].szDefaultPath)
2706 {
2707 PathAddBackslashW(szTemp);
2708 strcatW(szTemp, CSIDL_Data[folder].szDefaultPath);
2709 }
2710 hr = S_OK;
2711 break;
2712 case CSIDL_Type_SystemX86Path:
2713 if (!GetSystemWow64DirectoryW(szTemp, MAX_PATH)) GetSystemDirectoryW(szTemp, MAX_PATH);
2714 if (CSIDL_Data[folder].szDefaultPath &&
2715 !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) &&
2716 *CSIDL_Data[folder].szDefaultPath)
2717 {
2718 PathAddBackslashW(szTemp);
2719 strcatW(szTemp, CSIDL_Data[folder].szDefaultPath);
2720 }
2721 hr = S_OK;
2722 break;
2723 case CSIDL_Type_CurrVer:
2724 hr = _SHGetCurrentVersionPath(dwFlags, folder, szTemp);
2725 break;
2726 case CSIDL_Type_User:
2727 #ifdef __REACTOS__
2728 case CSIDL_Type_InMyDocuments:
2729 #endif
2730 hr = _SHGetUserProfilePath(hToken, dwFlags, folder, szTemp);
2731 break;
2732 case CSIDL_Type_AllUsers:
2733 hr = _SHGetAllUsersProfilePath(dwFlags, folder, szTemp);
2734 break;
2735 default:
2736 FIXME("bogus type %d, please fix\n", type);
2737 hr = E_INVALIDARG;
2738 break;
2739 }
2740
2741 /* Expand environment strings if necessary */
2742 if (*szTemp == '%')
2743 #ifndef __REACTOS__
2744 hr = _SHExpandEnvironmentStrings(szTemp, szBuildPath);
2745 #else
2746 hr = _SHExpandEnvironmentStrings(hToken, szTemp, szBuildPath, _countof(szBuildPath));
2747 #endif
2748 else
2749 strcpyW(szBuildPath, szTemp);
2750
2751 if (FAILED(hr)) goto end;
2752
2753 if(pszSubPath) {
2754 /* make sure the new path does not exceed the buffer length
2755 * and remember to backslash and terminate it */
2756 if(MAX_PATH < (lstrlenW(szBuildPath) + lstrlenW(pszSubPath) + 2)) {
2757 hr = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
2758 goto end;
2759 }
2760 PathAppendW(szBuildPath, pszSubPath);
2761 PathRemoveBackslashW(szBuildPath);
2762 }
2763 /* Copy the path if it's available before we might return */
2764 if (SUCCEEDED(hr) && pszPath)
2765 strcpyW(pszPath, szBuildPath);
2766
2767 /* if we don't care about existing directories we are ready */
2768 if(nFolder & CSIDL_FLAG_DONT_VERIFY) goto end;
2769
2770 if (PathFileExistsW(szBuildPath)) goto end;
2771
2772 /* not existing but we are not allowed to create it. The return value
2773 * is verified against shell32 version 6.0.
2774 */
2775 if (!(nFolder & CSIDL_FLAG_CREATE))
2776 {
2777 hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
2778 goto end;
2779 }
2780
2781 /* create directory/directories */
2782 ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, NULL);
2783 if (ret && ret != ERROR_ALREADY_EXISTS)
2784 {
2785 ERR("Failed to create directory %s.\n", debugstr_w(szBuildPath));
2786 hr = E_FAIL;
2787 goto end;
2788 }
2789
2790 TRACE("Created missing system directory %s\n", debugstr_w(szBuildPath));
2791
2792 end:
2793 #ifdef __REACTOS__
2794 /* create desktop.ini for custom icon */
2795 if ((nFolder & CSIDL_FLAG_CREATE) &&
2796 CSIDL_Data[folder].nShell32IconIndex)
2797 {
2798 WCHAR szIconLocation[MAX_PATH];
2799 DWORD dwAttributes;
2800
2801 /* make the directory a read-only folder */
2802 dwAttributes = GetFileAttributesW(szBuildPath);
2803 dwAttributes |= FILE_ATTRIBUTE_READONLY;
2804 SetFileAttributesW(szBuildPath, dwAttributes);
2805
2806 /* build the desktop.ini file path */
2807 PathAppendW(szBuildPath, L"desktop.ini");
2808
2809 /* build the icon location */
2810 StringCchPrintfW(szIconLocation, _countof(szIconLocation),
2811 L"%%SystemRoot%%\\system32\\shell32.dll,%d",
2812 CSIDL_Data[folder].nShell32IconIndex);
2813
2814 /* write desktop.ini */
2815 WritePrivateProfileStringW(L".ShellClassInfo", L"IconResource", szIconLocation, szBuildPath);
2816
2817 /* flush! */
2818 WritePrivateProfileStringW(NULL, NULL, NULL, szBuildPath);
2819
2820 /* make the desktop.ini a system and hidden file */
2821 dwAttributes = GetFileAttributesW(szBuildPath);
2822 dwAttributes |= FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
2823 SetFileAttributesW(szBuildPath, dwAttributes);
2824 }
2825 #endif
2826
2827 TRACE("returning 0x%08x (final path is %s)\n", hr, debugstr_w(szBuildPath));
2828 return hr;
2829 }
2830
2831 /*************************************************************************
2832 * SHGetFolderPathA [SHELL32.@]
2833 *
2834 * See SHGetFolderPathW.
2835 */
SHGetFolderPathA(HWND hwndOwner,int nFolder,HANDLE hToken,DWORD dwFlags,LPSTR pszPath)2836 HRESULT WINAPI SHGetFolderPathA(
2837 HWND hwndOwner,
2838 int nFolder,
2839 HANDLE hToken,
2840 DWORD dwFlags,
2841 LPSTR pszPath)
2842 {
2843 WCHAR szTemp[MAX_PATH];
2844 HRESULT hr;
2845
2846 TRACE("%p,%d,%p,%#x,%p\n", hwndOwner, nFolder, hToken, dwFlags, pszPath);
2847
2848 if (pszPath)
2849 *pszPath = '\0';
2850 hr = SHGetFolderPathW(hwndOwner, nFolder, hToken, dwFlags, szTemp);
2851 if (SUCCEEDED(hr) && pszPath)
2852 WideCharToMultiByte(CP_ACP, 0, szTemp, -1, pszPath, MAX_PATH, NULL,
2853 NULL);
2854
2855 return hr;
2856 }
2857
2858 /* For each folder in folders, if its value has not been set in the registry,
2859 * calls _SHGetUserProfilePath or _SHGetAllUsersProfilePath (depending on the
2860 * folder's type) to get the unexpanded value first.
2861 * Writes the unexpanded value to User Shell Folders, and queries it with
2862 * SHGetFolderPathW to force the creation of the directory if it doesn't
2863 * already exist. SHGetFolderPathW also returns the expanded value, which
2864 * this then writes to Shell Folders.
2865 */
_SHRegisterFolders(HKEY hRootKey,HANDLE hToken,LPCWSTR szUserShellFolderPath,LPCWSTR szShellFolderPath,const UINT folders[],UINT foldersLen)2866 static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken,
2867 LPCWSTR szUserShellFolderPath, LPCWSTR szShellFolderPath, const UINT folders[],
2868 UINT foldersLen)
2869 {
2870 const WCHAR *szValueName;
2871 WCHAR buffer[40];
2872 UINT i;
2873 WCHAR path[MAX_PATH];
2874 HRESULT hr = S_OK;
2875 HKEY hUserKey = NULL, hKey = NULL;
2876 DWORD dwType, dwPathLen;
2877 LONG ret;
2878
2879 TRACE("%p,%p,%s,%p,%u\n", hRootKey, hToken,
2880 debugstr_w(szUserShellFolderPath), folders, foldersLen);
2881
2882 ret = RegCreateKeyW(hRootKey, szUserShellFolderPath, &hUserKey);
2883 if (ret)
2884 hr = HRESULT_FROM_WIN32(ret);
2885 else
2886 {
2887 ret = RegCreateKeyW(hRootKey, szShellFolderPath, &hKey);
2888 if (ret)
2889 hr = HRESULT_FROM_WIN32(ret);
2890 }
2891 for (i = 0; SUCCEEDED(hr) && i < foldersLen; i++)
2892 {
2893 dwPathLen = MAX_PATH * sizeof(WCHAR);
2894
2895 /* For CSIDL_Type_User we also use the GUID if no szValueName is provided */
2896 szValueName = CSIDL_Data[folders[i]].szValueName;
2897 #ifdef __REACTOS__
2898 if (!szValueName &&
2899 (CSIDL_Data[folders[i]].type == CSIDL_Type_User ||
2900 CSIDL_Data[folders[i]].type == CSIDL_Type_InMyDocuments))
2901 #else
2902 if (!szValueName && CSIDL_Data[folders[i]].type == CSIDL_Type_User)
2903 #endif
2904 {
2905 StringFromGUID2( CSIDL_Data[folders[i]].id, buffer, 39 );
2906 szValueName = &buffer[0];
2907 }
2908
2909 if (!RegQueryValueExW(hUserKey, szValueName, NULL,
2910 &dwType, (LPBYTE)path, &dwPathLen) &&
2911 (dwType == REG_SZ || dwType == REG_EXPAND_SZ))
2912 {
2913 hr = SHGetFolderPathW(NULL, folders[i] | CSIDL_FLAG_CREATE,
2914 hToken, SHGFP_TYPE_CURRENT, path);
2915 }
2916 else
2917 {
2918 *path = '\0';
2919 #ifdef __REACTOS__
2920 if (CSIDL_Data[folders[i]].type == CSIDL_Type_User ||
2921 CSIDL_Data[folders[i]].type == CSIDL_Type_InMyDocuments)
2922 #else
2923 if (CSIDL_Data[folders[i]].type == CSIDL_Type_User)
2924 #endif
2925 _SHGetUserProfilePath(hToken, SHGFP_TYPE_CURRENT, folders[i],
2926 path);
2927 else if (CSIDL_Data[folders[i]].type == CSIDL_Type_AllUsers)
2928 _SHGetAllUsersProfilePath(SHGFP_TYPE_CURRENT, folders[i], path);
2929 else if (CSIDL_Data[folders[i]].type == CSIDL_Type_WindowsPath)
2930 {
2931 GetWindowsDirectoryW(path, MAX_PATH);
2932 if (CSIDL_Data[folders[i]].szDefaultPath &&
2933 !IS_INTRESOURCE(CSIDL_Data[folders[i]].szDefaultPath))
2934 {
2935 PathAddBackslashW(path);
2936 strcatW(path, CSIDL_Data[folders[i]].szDefaultPath);
2937 }
2938 }
2939 else
2940 hr = E_FAIL;
2941 if (*path)
2942 {
2943 ret = RegSetValueExW(hUserKey, szValueName, 0, REG_EXPAND_SZ,
2944 (LPBYTE)path, (strlenW(path) + 1) * sizeof(WCHAR));
2945 if (ret)
2946 hr = HRESULT_FROM_WIN32(ret);
2947 else
2948 {
2949 hr = SHGetFolderPathW(NULL, folders[i] | CSIDL_FLAG_CREATE,
2950 hToken, SHGFP_TYPE_CURRENT, path);
2951 ret = RegSetValueExW(hKey, szValueName, 0, REG_SZ,
2952 (LPBYTE)path, (strlenW(path) + 1) * sizeof(WCHAR));
2953 if (ret)
2954 hr = HRESULT_FROM_WIN32(ret);
2955 }
2956 }
2957 }
2958 }
2959 if (hUserKey)
2960 RegCloseKey(hUserKey);
2961 if (hKey)
2962 RegCloseKey(hKey);
2963
2964 TRACE("returning 0x%08x\n", hr);
2965 return hr;
2966 }
2967
_SHRegisterUserShellFolders(BOOL bDefault)2968 static HRESULT _SHRegisterUserShellFolders(BOOL bDefault)
2969 {
2970 static const UINT folders[] = {
2971 CSIDL_PROGRAMS,
2972 CSIDL_PERSONAL,
2973 CSIDL_FAVORITES,
2974 CSIDL_APPDATA,
2975 CSIDL_STARTUP,
2976 CSIDL_RECENT,
2977 CSIDL_SENDTO,
2978 CSIDL_STARTMENU,
2979 CSIDL_MYMUSIC,
2980 CSIDL_MYVIDEO,
2981 CSIDL_DESKTOPDIRECTORY,
2982 CSIDL_NETHOOD,
2983 CSIDL_TEMPLATES,
2984 CSIDL_PRINTHOOD,
2985 CSIDL_LOCAL_APPDATA,
2986 CSIDL_INTERNET_CACHE,
2987 CSIDL_COOKIES,
2988 CSIDL_HISTORY,
2989 CSIDL_MYPICTURES,
2990 CSIDL_FONTS,
2991 CSIDL_ADMINTOOLS,
2992 /* Cannot use #if _WIN32_WINNT >= 0x0600 because _WIN32_WINNT == 0x0600 here. */
2993 #ifndef __REACTOS__
2994 CSIDL_CONTACTS,
2995 CSIDL_DOWNLOADS,
2996 CSIDL_LINKS,
2997 CSIDL_APPDATA_LOCALLOW,
2998 CSIDL_SAVED_GAMES,
2999 CSIDL_SEARCHES
3000 #endif
3001 };
3002 WCHAR userShellFolderPath[MAX_PATH], shellFolderPath[MAX_PATH];
3003 LPCWSTR pUserShellFolderPath, pShellFolderPath;
3004 HRESULT hr = S_OK;
3005 HKEY hRootKey;
3006 HANDLE hToken;
3007
3008 TRACE("%s\n", bDefault ? "TRUE" : "FALSE");
3009 if (bDefault)
3010 {
3011 hToken = (HANDLE)-1;
3012 hRootKey = HKEY_USERS;
3013 strcpyW(userShellFolderPath, L".Default");
3014 PathAddBackslashW(userShellFolderPath);
3015 strcatW(userShellFolderPath, szSHUserFolders);
3016 pUserShellFolderPath = userShellFolderPath;
3017 strcpyW(shellFolderPath, L".Default");
3018 PathAddBackslashW(shellFolderPath);
3019 strcatW(shellFolderPath, szSHFolders);
3020 pShellFolderPath = shellFolderPath;
3021 }
3022 else
3023 {
3024 hToken = NULL;
3025 hRootKey = HKEY_CURRENT_USER;
3026 pUserShellFolderPath = szSHUserFolders;
3027 pShellFolderPath = szSHFolders;
3028 }
3029
3030 hr = _SHRegisterFolders(hRootKey, hToken, pUserShellFolderPath,
3031 pShellFolderPath, folders, ARRAY_SIZE(folders));
3032 TRACE("returning 0x%08x\n", hr);
3033 return hr;
3034 }
3035
_SHRegisterCommonShellFolders(void)3036 static HRESULT _SHRegisterCommonShellFolders(void)
3037 {
3038 static const UINT folders[] = {
3039 CSIDL_COMMON_STARTMENU,
3040 CSIDL_COMMON_PROGRAMS,
3041 CSIDL_COMMON_STARTUP,
3042 CSIDL_COMMON_DESKTOPDIRECTORY,
3043 CSIDL_COMMON_FAVORITES,
3044 CSIDL_COMMON_APPDATA,
3045 CSIDL_COMMON_TEMPLATES,
3046 CSIDL_COMMON_DOCUMENTS,
3047 CSIDL_COMMON_ADMINTOOLS,
3048 CSIDL_COMMON_MUSIC,
3049 CSIDL_COMMON_PICTURES,
3050 CSIDL_COMMON_VIDEO,
3051 };
3052 HRESULT hr;
3053
3054 TRACE("\n");
3055 hr = _SHRegisterFolders(HKEY_LOCAL_MACHINE, NULL, szSHUserFolders,
3056 szSHFolders, folders, ARRAY_SIZE(folders));
3057 TRACE("returning 0x%08x\n", hr);
3058 return hr;
3059 }
3060
3061 /* Register the default values in the registry, as some apps seem to depend
3062 * on their presence. The set registered was taken from Windows XP.
3063 */
SHELL_RegisterShellFolders(void)3064 HRESULT SHELL_RegisterShellFolders(void)
3065 {
3066 HRESULT hr;
3067
3068 hr = _SHRegisterUserShellFolders(TRUE);
3069 if (SUCCEEDED(hr))
3070 hr = _SHRegisterUserShellFolders(FALSE);
3071 if (SUCCEEDED(hr))
3072 hr = _SHRegisterCommonShellFolders();
3073 return hr;
3074 }
3075
3076 /*************************************************************************
3077 * SHGetSpecialFolderPathA [SHELL32.@]
3078 */
SHGetSpecialFolderPathA(HWND hwndOwner,LPSTR szPath,int nFolder,BOOL bCreate)3079 BOOL WINAPI SHGetSpecialFolderPathA (
3080 HWND hwndOwner,
3081 LPSTR szPath,
3082 int nFolder,
3083 BOOL bCreate)
3084 {
3085 return SHGetFolderPathA(hwndOwner, nFolder + (bCreate ? CSIDL_FLAG_CREATE : 0), NULL, 0,
3086 szPath) == S_OK;
3087 }
3088
3089 /*************************************************************************
3090 * SHGetSpecialFolderPathW
3091 */
SHGetSpecialFolderPathW(HWND hwndOwner,LPWSTR szPath,int nFolder,BOOL bCreate)3092 BOOL WINAPI SHGetSpecialFolderPathW (
3093 HWND hwndOwner,
3094 LPWSTR szPath,
3095 int nFolder,
3096 BOOL bCreate)
3097 {
3098 return SHGetFolderPathW(hwndOwner, nFolder + (bCreate ? CSIDL_FLAG_CREATE : 0), NULL, 0,
3099 szPath) == S_OK;
3100 }
3101
3102 #ifdef __REACTOS__
SHGetFolderLocationHelper(HWND hwnd,int nFolder,REFCLSID clsid,LPITEMIDLIST * ppidl)3103 HRESULT SHGetFolderLocationHelper(HWND hwnd, int nFolder, REFCLSID clsid, LPITEMIDLIST *ppidl)
3104 {
3105 HRESULT hr;
3106 IShellFolder *psf;
3107 LPITEMIDLIST parent, child;
3108 EXTERN_C HRESULT SHBindToObject(IShellFolder *psf, LPCITEMIDLIST pidl, REFIID riid, void **ppvObj);
3109 *ppidl = NULL;
3110 if (FAILED(hr = SHGetFolderLocation(hwnd, nFolder, NULL, 0, &parent)))
3111 return hr;
3112 if (SUCCEEDED(hr = SHBindToObject(NULL, parent, &IID_IShellFolder, (void**)&psf)))
3113 {
3114 WCHAR clsidstr[2 + 38 + 1];
3115 clsidstr[0] = clsidstr[1] = L':';
3116 StringFromGUID2(clsid, clsidstr + 2, 38 + 1);
3117 hr = IShellFolder_ParseDisplayName(psf, hwnd, NULL, clsidstr, NULL, &child, NULL);
3118 if (SUCCEEDED(hr))
3119 *ppidl = ILCombine(parent, child);
3120 IShellFolder_Release(psf);
3121 ILFree(child);
3122 }
3123 ILFree(parent);
3124 return hr;
3125 }
3126 #endif
3127
3128 /*************************************************************************
3129 * SHGetFolderLocation [SHELL32.@]
3130 *
3131 * Gets the folder locations from the registry and creates a pidl.
3132 *
3133 * PARAMS
3134 * hwndOwner [I]
3135 * nFolder [I] CSIDL_xxxxx
3136 * hToken [I] token representing user, or NULL for current user, or -1 for
3137 * default user
3138 * dwReserved [I] must be zero
3139 * ppidl [O] PIDL of a special folder
3140 *
3141 * RETURNS
3142 * Success: S_OK
3143 * Failure: Standard OLE-defined error result, S_FALSE or E_INVALIDARG
3144 *
3145 * NOTES
3146 * Creates missing reg keys and directories.
3147 * Mostly forwards to SHGetFolderPathW, but a few values of nFolder return
3148 * virtual folders that are handled here.
3149 */
SHGetFolderLocation(HWND hwndOwner,int nFolder,HANDLE hToken,DWORD dwReserved,LPITEMIDLIST * ppidl)3150 HRESULT WINAPI SHGetFolderLocation(
3151 HWND hwndOwner,
3152 int nFolder,
3153 HANDLE hToken,
3154 DWORD dwReserved,
3155 LPITEMIDLIST *ppidl)
3156 {
3157 HRESULT hr = E_INVALIDARG;
3158 #ifdef __REACTOS__
3159 WCHAR szPath[MAX_PATH];
3160 #endif
3161
3162 TRACE("%p 0x%08x %p 0x%08x %p\n",
3163 hwndOwner, nFolder, hToken, dwReserved, ppidl);
3164
3165 if (!ppidl)
3166 return E_INVALIDARG;
3167 if (dwReserved)
3168 return E_INVALIDARG;
3169
3170 #ifdef __REACTOS__
3171 if ((nFolder & CSIDL_FLAG_NO_ALIAS) &&
3172 SHGetSpecialFolderPathW(hwndOwner, szPath, (nFolder & CSIDL_FOLDER_MASK), FALSE))
3173 {
3174 *ppidl = ILCreateFromPathW(szPath);
3175 if (*ppidl)
3176 return S_OK;
3177 }
3178 #endif
3179 /* The virtual folders' locations are not user-dependent */
3180 *ppidl = NULL;
3181 switch (nFolder & CSIDL_FOLDER_MASK)
3182 {
3183 case CSIDL_DESKTOP:
3184 *ppidl = _ILCreateDesktop();
3185 break;
3186
3187 case CSIDL_PERSONAL:
3188 *ppidl = _ILCreateMyDocuments();
3189 break;
3190
3191 case CSIDL_INTERNET:
3192 *ppidl = _ILCreateIExplore();
3193 break;
3194
3195 case CSIDL_CONTROLS:
3196 *ppidl = _ILCreateControlPanel();
3197 break;
3198
3199 case CSIDL_PRINTERS:
3200 *ppidl = _ILCreatePrinters();
3201 break;
3202
3203 case CSIDL_BITBUCKET:
3204 *ppidl = _ILCreateBitBucket();
3205 break;
3206
3207 case CSIDL_DRIVES:
3208 *ppidl = _ILCreateMyComputer();
3209 break;
3210
3211 case CSIDL_NETWORK:
3212 *ppidl = _ILCreateNetwork();
3213 break;
3214
3215 #ifdef __REACTOS__
3216 case CSIDL_CONNECTIONS:
3217 hr = SHGetFolderLocationHelper(hwndOwner, CSIDL_CONTROLS, &CLSID_NetworkConnections, ppidl);
3218 break;
3219 #endif
3220
3221 default:
3222 {
3223 WCHAR szPath[MAX_PATH];
3224
3225 hr = SHGetFolderPathW(hwndOwner, nFolder, hToken,
3226 SHGFP_TYPE_CURRENT, szPath);
3227 if (SUCCEEDED(hr))
3228 {
3229 DWORD attributes=0;
3230
3231 TRACE("Value=%s\n", debugstr_w(szPath));
3232 hr = SHILCreateFromPathW(szPath, ppidl, &attributes);
3233 }
3234 else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
3235 {
3236 /* unlike SHGetFolderPath, SHGetFolderLocation in shell32
3237 * version 6.0 returns E_FAIL for nonexistent paths
3238 */
3239 hr = E_FAIL;
3240 }
3241 }
3242 }
3243 if(*ppidl)
3244 hr = S_OK;
3245
3246 TRACE("-- (new pidl %p)\n",*ppidl);
3247 return hr;
3248 }
3249
3250 /*************************************************************************
3251 * SHGetSpecialFolderLocation [SHELL32.@]
3252 *
3253 * NOTES
3254 * In NT5, SHGetSpecialFolderLocation needs the <winntdir>/Recent
3255 * directory.
3256 */
SHGetSpecialFolderLocation(HWND hwndOwner,INT nFolder,LPITEMIDLIST * ppidl)3257 HRESULT WINAPI SHGetSpecialFolderLocation(
3258 HWND hwndOwner,
3259 INT nFolder,
3260 LPITEMIDLIST * ppidl)
3261 {
3262 HRESULT hr = E_INVALIDARG;
3263
3264 TRACE("(%p,0x%x,%p)\n", hwndOwner,nFolder,ppidl);
3265
3266 if (!ppidl)
3267 return E_INVALIDARG;
3268
3269 hr = SHGetFolderLocation(hwndOwner, nFolder, NULL, 0, ppidl);
3270 return hr;
3271 }
3272