4 * Copyright 1998, 1999, 2000 Juergen Schmied
5 * Copyright 2004 Juan Lang
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * Many of these functions are in SHLWAPI.DLL also
42 #define WINE_MOUNTMGR_EXTENSIONS
43 #include "ddk/mountmgr.h"
48 #include "shell32_main.h"
49 #include "undocshell.h"
53 #include "knownfolders.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
60 static const BOOL is_win64
= sizeof(void *) > sizeof(int);
63 ########## Combining and Constructing paths ##########
66 /*************************************************************************
67 * PathAppend [SHELL32.36]
69 BOOL WINAPI
PathAppendAW(
73 if (SHELL_OsIsUnicode())
74 return PathAppendW(lpszPath1
, lpszPath2
);
75 return PathAppendA(lpszPath1
, lpszPath2
);
78 /*************************************************************************
79 * PathCombine [SHELL32.37]
81 LPVOID WINAPI
PathCombineAW(
86 if (SHELL_OsIsUnicode())
87 return PathCombineW( szDest
, lpszDir
, lpszFile
);
88 return PathCombineA( szDest
, lpszDir
, lpszFile
);
91 /*************************************************************************
92 * PathAddBackslash [SHELL32.32]
94 LPVOID WINAPI
PathAddBackslashAW(LPVOID lpszPath
)
96 if(SHELL_OsIsUnicode())
97 return PathAddBackslashW(lpszPath
);
98 return PathAddBackslashA(lpszPath
);
101 /*************************************************************************
102 * PathBuildRoot [SHELL32.30]
104 LPVOID WINAPI
PathBuildRootAW(LPVOID lpszPath
, int drive
)
106 if(SHELL_OsIsUnicode())
107 return PathBuildRootW(lpszPath
, drive
);
108 return PathBuildRootA(lpszPath
, drive
);
112 Extracting Component Parts
115 /*************************************************************************
116 * PathFindFileName [SHELL32.34]
118 LPVOID WINAPI
PathFindFileNameAW(LPCVOID lpszPath
)
120 if(SHELL_OsIsUnicode())
121 return PathFindFileNameW(lpszPath
);
122 return PathFindFileNameA(lpszPath
);
125 /*************************************************************************
126 * PathFindExtension [SHELL32.31]
128 LPVOID WINAPI
PathFindExtensionAW(LPCVOID lpszPath
)
130 if (SHELL_OsIsUnicode())
131 return PathFindExtensionW(lpszPath
);
132 return PathFindExtensionA(lpszPath
);
136 /*************************************************************************
137 * PathGetExtensionA [internal]
140 * exported by ordinal
141 * return value points to the first char after the dot
143 static LPSTR
PathGetExtensionA(LPCSTR lpszPath
)
145 TRACE("(%s)\n",lpszPath
);
147 lpszPath
= PathFindExtensionA(lpszPath
);
148 return (LPSTR
)(*lpszPath
?(lpszPath
+1):lpszPath
);
151 /*************************************************************************
152 * PathGetExtensionW [internal]
154 static LPWSTR
PathGetExtensionW(LPCWSTR lpszPath
)
156 TRACE("(%s)\n",debugstr_w(lpszPath
));
158 lpszPath
= PathFindExtensionW(lpszPath
);
159 return (LPWSTR
)(*lpszPath
?(lpszPath
+1):lpszPath
);
162 /*************************************************************************
163 * PathGetExtension [SHELL32.158]
165 LPVOID WINAPI
PathGetExtensionAW(LPCVOID lpszPath
,DWORD void1
, DWORD void2
)
167 if (SHELL_OsIsUnicode())
168 return PathGetExtensionW(lpszPath
);
169 return PathGetExtensionA(lpszPath
);
172 /*************************************************************************
173 * PathGetArgs [SHELL32.52]
175 LPVOID WINAPI
PathGetArgsAW(LPVOID lpszPath
)
177 if (SHELL_OsIsUnicode())
178 return PathGetArgsW(lpszPath
);
179 return PathGetArgsA(lpszPath
);
182 /*************************************************************************
183 * PathGetDriveNumber [SHELL32.57]
185 int WINAPI
PathGetDriveNumberAW(LPVOID lpszPath
)
187 if (SHELL_OsIsUnicode())
188 return PathGetDriveNumberW(lpszPath
);
189 return PathGetDriveNumberA(lpszPath
);
192 /*************************************************************************
193 * PathRemoveFileSpec [SHELL32.35]
195 BOOL WINAPI
PathRemoveFileSpecAW(LPVOID lpszPath
)
197 if (SHELL_OsIsUnicode())
198 return PathRemoveFileSpecW(lpszPath
);
199 return PathRemoveFileSpecA(lpszPath
);
202 /*************************************************************************
203 * PathStripPath [SHELL32.38]
205 void WINAPI
PathStripPathAW(LPVOID lpszPath
)
207 if (SHELL_OsIsUnicode())
208 PathStripPathW(lpszPath
);
210 PathStripPathA(lpszPath
);
213 /*************************************************************************
214 * PathStripToRoot [SHELL32.50]
216 BOOL WINAPI
PathStripToRootAW(LPVOID lpszPath
)
218 if (SHELL_OsIsUnicode())
219 return PathStripToRootW(lpszPath
);
220 return PathStripToRootA(lpszPath
);
223 /*************************************************************************
224 * PathRemoveArgs [SHELL32.251]
226 void WINAPI
PathRemoveArgsAW(LPVOID lpszPath
)
228 if (SHELL_OsIsUnicode())
229 PathRemoveArgsW(lpszPath
);
231 PathRemoveArgsA(lpszPath
);
234 /*************************************************************************
235 * PathRemoveExtension [SHELL32.250]
237 void WINAPI
PathRemoveExtensionAW(LPVOID lpszPath
)
239 if (SHELL_OsIsUnicode())
240 PathRemoveExtensionW(lpszPath
);
242 PathRemoveExtensionA(lpszPath
);
250 /*************************************************************************
251 * PathGetShortPathA [internal]
253 static void PathGetShortPathA(LPSTR pszPath
)
257 TRACE("%s\n", pszPath
);
259 if (GetShortPathNameA(pszPath
, path
, MAX_PATH
))
261 lstrcpyA(pszPath
, path
);
265 /*************************************************************************
266 * PathGetShortPathW [internal]
268 static void PathGetShortPathW(LPWSTR pszPath
)
270 WCHAR path
[MAX_PATH
];
272 TRACE("%s\n", debugstr_w(pszPath
));
274 if (GetShortPathNameW(pszPath
, path
, MAX_PATH
))
276 lstrcpyW(pszPath
, path
);
280 /*************************************************************************
281 * PathGetShortPath [SHELL32.92]
283 VOID WINAPI
PathGetShortPathAW(LPVOID pszPath
)
285 if(SHELL_OsIsUnicode())
286 PathGetShortPathW(pszPath
);
287 PathGetShortPathA(pszPath
);
290 /*************************************************************************
291 * PathRemoveBlanks [SHELL32.33]
293 void WINAPI
PathRemoveBlanksAW(LPVOID str
)
295 if(SHELL_OsIsUnicode())
296 PathRemoveBlanksW(str
);
298 PathRemoveBlanksA(str
);
301 /*************************************************************************
302 * PathQuoteSpaces [SHELL32.55]
304 VOID WINAPI
PathQuoteSpacesAW (LPVOID lpszPath
)
306 if(SHELL_OsIsUnicode())
307 PathQuoteSpacesW(lpszPath
);
309 PathQuoteSpacesA(lpszPath
);
312 /*************************************************************************
313 * PathUnquoteSpaces [SHELL32.56]
315 VOID WINAPI
PathUnquoteSpacesAW(LPVOID str
)
317 if(SHELL_OsIsUnicode())
318 PathUnquoteSpacesW(str
);
320 PathUnquoteSpacesA(str
);
323 /*************************************************************************
324 * PathParseIconLocation [SHELL32.249]
326 int WINAPI
PathParseIconLocationAW (LPVOID lpszPath
)
328 if(SHELL_OsIsUnicode())
329 return PathParseIconLocationW(lpszPath
);
330 return PathParseIconLocationA(lpszPath
);
334 ########## Path Testing ##########
336 /*************************************************************************
337 * PathIsUNC [SHELL32.39]
339 BOOL WINAPI
PathIsUNCAW (LPCVOID lpszPath
)
341 if (SHELL_OsIsUnicode())
342 return PathIsUNCW( lpszPath
);
343 return PathIsUNCA( lpszPath
);
346 /*************************************************************************
347 * PathIsRelative [SHELL32.40]
349 BOOL WINAPI
PathIsRelativeAW (LPCVOID lpszPath
)
351 if (SHELL_OsIsUnicode())
352 return PathIsRelativeW( lpszPath
);
353 return PathIsRelativeA( lpszPath
);
356 /*************************************************************************
357 * PathIsRoot [SHELL32.29]
359 BOOL WINAPI
PathIsRootAW(LPCVOID lpszPath
)
361 if (SHELL_OsIsUnicode())
362 return PathIsRootW(lpszPath
);
363 return PathIsRootA(lpszPath
);
366 /*************************************************************************
367 * PathIsExeA [internal]
369 static BOOL
PathIsExeA (LPCSTR lpszPath
)
371 LPCSTR lpszExtension
= PathGetExtensionA(lpszPath
);
373 static const char * const lpszExtensions
[] =
374 {"exe", "com", "pif", "cmd", "bat", "scf", "scr", NULL
};
376 TRACE("path=%s\n",lpszPath
);
378 for(i
=0; lpszExtensions
[i
]; i
++)
379 if (!lstrcmpiA(lpszExtension
,lpszExtensions
[i
])) return TRUE
;
384 /*************************************************************************
385 * PathIsExeW [internal]
387 static BOOL
PathIsExeW (LPCWSTR lpszPath
)
389 LPCWSTR lpszExtension
= PathGetExtensionW(lpszPath
);
391 static const WCHAR lpszExtensions
[][4] =
392 {L
"exe", L
"com", L
"pif",L
"cmd", L
"bat", L
"scf",L
"scr",L
"" };
394 TRACE("path=%s\n",debugstr_w(lpszPath
));
396 for(i
=0; lpszExtensions
[i
][0]; i
++)
397 if (!wcsicmp(lpszExtension
,lpszExtensions
[i
])) return TRUE
;
402 /*************************************************************************
403 * PathIsExe [SHELL32.43]
405 BOOL WINAPI
PathIsExeAW (LPCVOID path
)
407 if (SHELL_OsIsUnicode())
408 return PathIsExeW (path
);
409 return PathIsExeA(path
);
412 /*************************************************************************
413 * PathIsDirectory [SHELL32.159]
415 BOOL WINAPI
PathIsDirectoryAW (LPCVOID lpszPath
)
417 if (SHELL_OsIsUnicode())
418 return PathIsDirectoryW (lpszPath
);
419 return PathIsDirectoryA (lpszPath
);
422 /*************************************************************************
423 * PathFileExists [SHELL32.45]
425 BOOL WINAPI
PathFileExistsAW (LPCVOID lpszPath
)
427 if (SHELL_OsIsUnicode())
428 return PathFileExistsW (lpszPath
);
429 return PathFileExistsA (lpszPath
);
432 /*************************************************************************
433 * PathMatchSpec [SHELL32.46]
435 BOOL WINAPI
PathMatchSpecAW(LPVOID name
, LPVOID mask
)
437 if (SHELL_OsIsUnicode())
438 return PathMatchSpecW( name
, mask
);
439 return PathMatchSpecA( name
, mask
);
442 /*************************************************************************
443 * PathIsSameRoot [SHELL32.650]
445 BOOL WINAPI
PathIsSameRootAW(LPCVOID lpszPath1
, LPCVOID lpszPath2
)
447 if (SHELL_OsIsUnicode())
448 return PathIsSameRootW(lpszPath1
, lpszPath2
);
449 return PathIsSameRootA(lpszPath1
, lpszPath2
);
452 /*************************************************************************
453 * IsLFNDriveA [SHELL32.41]
455 BOOL WINAPI
IsLFNDriveA(LPCSTR lpszPath
)
459 if (!GetVolumeInformationA(lpszPath
, NULL
, 0, NULL
, &fnlen
, NULL
, NULL
, 0))
464 /*************************************************************************
465 * IsLFNDriveW [SHELL32.42]
467 BOOL WINAPI
IsLFNDriveW(LPCWSTR lpszPath
)
471 if (!GetVolumeInformationW(lpszPath
, NULL
, 0, NULL
, &fnlen
, NULL
, NULL
, 0))
476 /*************************************************************************
477 * IsLFNDrive [SHELL32.119]
479 BOOL WINAPI
IsLFNDriveAW(LPCVOID lpszPath
)
481 if (SHELL_OsIsUnicode())
482 return IsLFNDriveW(lpszPath
);
483 return IsLFNDriveA(lpszPath
);
487 ########## Creating Something Unique ##########
489 /*************************************************************************
490 * PathMakeUniqueNameA [internal]
492 static BOOL
PathMakeUniqueNameA(
495 LPCSTR lpszShortName
,
499 FIXME("%p %u %s %s %s stub\n",
500 lpszBuffer
, dwBuffSize
, debugstr_a(lpszShortName
),
501 debugstr_a(lpszLongName
), debugstr_a(lpszPathName
));
505 /*************************************************************************
506 * PathMakeUniqueNameW [internal]
508 static BOOL
PathMakeUniqueNameW(
511 LPCWSTR lpszShortName
,
512 LPCWSTR lpszLongName
,
513 LPCWSTR lpszPathName
)
515 FIXME("%p %u %s %s %s stub\n",
516 lpszBuffer
, dwBuffSize
, debugstr_w(lpszShortName
),
517 debugstr_w(lpszLongName
), debugstr_w(lpszPathName
));
521 /*************************************************************************
522 * PathMakeUniqueName [SHELL32.47]
524 BOOL WINAPI
PathMakeUniqueNameAW(
527 LPCVOID lpszShortName
,
528 LPCVOID lpszLongName
,
529 LPCVOID lpszPathName
)
531 if (SHELL_OsIsUnicode())
532 return PathMakeUniqueNameW(lpszBuffer
,dwBuffSize
, lpszShortName
,lpszLongName
,lpszPathName
);
533 return PathMakeUniqueNameA(lpszBuffer
,dwBuffSize
, lpszShortName
,lpszLongName
,lpszPathName
);
536 /*************************************************************************
537 * PathYetAnotherMakeUniqueName [SHELL32.75]
539 BOOL WINAPI
PathYetAnotherMakeUniqueName(LPWSTR buffer
, LPCWSTR path
, LPCWSTR shortname
, LPCWSTR longname
)
541 WCHAR pathW
[MAX_PATH
], retW
[MAX_PATH
];
542 const WCHAR
*file
, *ext
;
545 TRACE("(%p, %s, %s, %s)\n", buffer
, debugstr_w(path
), debugstr_w(shortname
), debugstr_w(longname
));
547 file
= longname
? longname
: shortname
;
548 PathCombineW(pathW
, path
, file
);
549 lstrcpyW(retW
, pathW
);
550 PathRemoveExtensionW(pathW
);
552 ext
= PathFindExtensionW(file
);
554 /* now try to make it unique */
555 while (PathFileExistsW(retW
))
557 swprintf(retW
, ARRAY_SIZE(retW
), L
"%s (%d)%s", pathW
, i
, ext
);
561 lstrcpyW(buffer
, retW
);
562 TRACE("ret - %s\n", debugstr_w(buffer
));
568 ########## cleaning and resolving paths ##########
571 /*************************************************************************
572 * PathFindOnPath [SHELL32.145]
574 BOOL WINAPI
PathFindOnPathAW(LPVOID sFile
, LPCVOID
*sOtherDirs
)
576 if (SHELL_OsIsUnicode())
577 return PathFindOnPathW(sFile
, (LPCWSTR
*)sOtherDirs
);
578 return PathFindOnPathA(sFile
, (LPCSTR
*)sOtherDirs
);
581 /*************************************************************************
582 * PathCleanupSpec [SHELL32.171]
584 * lpszFile is changed in place.
586 int WINAPI
PathCleanupSpec( LPCWSTR lpszPathW
, LPWSTR lpszFileW
)
592 if (SHELL_OsIsUnicode())
594 LPWSTR p
= lpszFileW
;
596 TRACE("Cleanup %s\n",debugstr_w(lpszFileW
));
599 length
= lstrlenW(lpszPathW
);
603 int gct
= PathGetCharTypeW(*p
);
604 if (gct
== GCT_INVALID
|| gct
== GCT_WILD
|| gct
== GCT_SEPARATOR
)
607 rc
|= PCS_REPLACEDCHAR
;
613 if (length
+ i
== MAX_PATH
)
615 rc
|= PCS_FATAL
| PCS_PATHTOOLONG
;
623 LPSTR lpszFileA
= (LPSTR
)lpszFileW
;
624 LPCSTR lpszPathA
= (LPCSTR
)lpszPathW
;
627 TRACE("Cleanup %s\n",debugstr_a(lpszFileA
));
630 length
= strlen(lpszPathA
);
634 int gct
= PathGetCharTypeA(*p
);
635 if (gct
== GCT_INVALID
|| gct
== GCT_WILD
|| gct
== GCT_SEPARATOR
)
638 rc
|= PCS_REPLACEDCHAR
;
644 if (length
+ i
== MAX_PATH
)
646 rc
|= PCS_FATAL
| PCS_PATHTOOLONG
;
655 /*************************************************************************
656 * PathQualifyA [SHELL32]
658 static BOOL
PathQualifyA(LPCSTR pszPath
)
660 FIXME("%s\n",pszPath
);
664 /*************************************************************************
665 * PathQualifyW [SHELL32]
667 static BOOL
PathQualifyW(LPCWSTR pszPath
)
669 FIXME("%s\n",debugstr_w(pszPath
));
673 /*************************************************************************
674 * PathQualify [SHELL32.49]
676 BOOL WINAPI
PathQualifyAW(LPCVOID pszPath
)
678 if (SHELL_OsIsUnicode())
679 return PathQualifyW(pszPath
);
680 return PathQualifyA(pszPath
);
683 BOOL WINAPI
PathFindOnPathExA(LPSTR
,LPCSTR
*,DWORD
);
684 BOOL WINAPI
PathFindOnPathExW(LPWSTR
,LPCWSTR
*,DWORD
);
685 BOOL WINAPI
PathFileExistsDefExtA(LPSTR
,DWORD
);
686 BOOL WINAPI
PathFileExistsDefExtW(LPWSTR
,DWORD
);
688 static BOOL
PathResolveA(char *path
, const char **dirs
, DWORD flags
)
690 BOOL is_file_spec
= PathIsFileSpecA(path
);
691 DWORD dwWhich
= flags
& PRF_DONTFINDLNK
? 0xf : 0xff;
693 TRACE("(%s,%p,0x%08x)\n", debugstr_a(path
), dirs
, flags
);
695 if (flags
& PRF_VERIFYEXISTS
&& !PathFileExistsA(path
))
697 if (PathFindOnPathExA(path
, dirs
, dwWhich
))
699 if (PathFileExistsDefExtA(path
, dwWhich
))
701 if (!is_file_spec
) GetFullPathNameA(path
, MAX_PATH
, path
, NULL
);
702 SetLastError(ERROR_FILE_NOT_FOUND
);
708 SetLastError(ERROR_FILE_NOT_FOUND
);
712 GetFullPathNameA(path
, MAX_PATH
, path
, NULL
);
717 static BOOL
PathResolveW(WCHAR
*path
, const WCHAR
**dirs
, DWORD flags
)
719 BOOL is_file_spec
= PathIsFileSpecW(path
);
720 DWORD dwWhich
= flags
& PRF_DONTFINDLNK
? 0xf : 0xff;
722 TRACE("(%s,%p,0x%08x)\n", debugstr_w(path
), dirs
, flags
);
724 if (flags
& PRF_VERIFYEXISTS
&& !PathFileExistsW(path
))
726 if (PathFindOnPathExW(path
, dirs
, dwWhich
))
728 if (PathFileExistsDefExtW(path
, dwWhich
))
730 if (!is_file_spec
) GetFullPathNameW(path
, MAX_PATH
, path
, NULL
);
731 SetLastError(ERROR_FILE_NOT_FOUND
);
737 SetLastError(ERROR_FILE_NOT_FOUND
);
741 GetFullPathNameW(path
, MAX_PATH
, path
, NULL
);
746 /*************************************************************************
747 * PathResolve [SHELL32.51]
749 BOOL WINAPI
PathResolveAW(void *path
, const void **paths
, DWORD flags
)
751 if (SHELL_OsIsUnicode())
752 return PathResolveW(path
, (const WCHAR
**)paths
, flags
);
754 return PathResolveA(path
, (const char **)paths
, flags
);
757 /*************************************************************************
758 * PathProcessCommandA
760 static LONG
PathProcessCommandA (
766 FIXME("%s %p 0x%04x 0x%04x stub\n",
767 lpszPath
, lpszBuff
, dwBuffSize
, dwFlags
);
768 if(!lpszPath
) return -1;
769 if(lpszBuff
) strcpy(lpszBuff
, lpszPath
);
770 return strlen(lpszPath
);
773 /*************************************************************************
774 * PathProcessCommandW
776 static LONG
PathProcessCommandW (
782 FIXME("(%s, %p, 0x%04x, 0x%04x) stub\n",
783 debugstr_w(lpszPath
), lpszBuff
, dwBuffSize
, dwFlags
);
784 if(!lpszPath
) return -1;
785 if(lpszBuff
) lstrcpyW(lpszBuff
, lpszPath
);
786 return lstrlenW(lpszPath
);
789 /*************************************************************************
790 * PathProcessCommand (SHELL32.653)
792 LONG WINAPI
PathProcessCommandAW (
798 if (SHELL_OsIsUnicode())
799 return PathProcessCommandW(lpszPath
, lpszBuff
, dwBuffSize
, dwFlags
);
800 return PathProcessCommandA(lpszPath
, lpszBuff
, dwBuffSize
, dwFlags
);
804 ########## special ##########
807 /*************************************************************************
808 * PathSetDlgItemPath (SHELL32.48)
810 VOID WINAPI
PathSetDlgItemPathAW(HWND hDlg
, int id
, LPCVOID pszPath
)
812 if (SHELL_OsIsUnicode())
813 PathSetDlgItemPathW(hDlg
, id
, pszPath
);
815 PathSetDlgItemPathA(hDlg
, id
, pszPath
);
818 typedef enum _CSIDL_Type
{
822 CSIDL_Type_Disallowed
,
823 CSIDL_Type_NonExistent
,
824 CSIDL_Type_WindowsPath
,
825 CSIDL_Type_SystemPath
,
826 CSIDL_Type_SystemX86Path
,
827 CSIDL_Type_ProgramData
,
830 #define CSIDL_CONTACTS 0x0043
831 #define CSIDL_DOWNLOADS 0x0047
832 #define CSIDL_LINKS 0x004d
833 #define CSIDL_APPDATA_LOCALLOW 0x004e
834 #define CSIDL_SAVED_GAMES 0x0062
835 #define CSIDL_SEARCHES 0x0063
839 IApplicationDestinations IApplicationDestinations_iface
;
841 } IApplicationDestinationsImpl
;
843 static inline IApplicationDestinationsImpl
*impl_from_IApplicationDestinations( IApplicationDestinations
*iface
)
845 return CONTAINING_RECORD(iface
, IApplicationDestinationsImpl
, IApplicationDestinations_iface
);
848 static HRESULT WINAPI
ApplicationDestinations_QueryInterface(IApplicationDestinations
*iface
, REFIID riid
,
851 IApplicationDestinationsImpl
*This
= impl_from_IApplicationDestinations(iface
);
853 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppv
);
858 if (IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IApplicationDestinations
, riid
))
860 *ppv
= &This
->IApplicationDestinations_iface
;
861 IUnknown_AddRef((IUnknown
*)*ppv
);
863 TRACE("Returning IApplicationDestinations: %p\n", *ppv
);
868 FIXME("(%p)->(%s, %p) interface not supported.\n", This
, debugstr_guid(riid
), ppv
);
870 return E_NOINTERFACE
;
873 static ULONG WINAPI
ApplicationDestinations_AddRef(IApplicationDestinations
*iface
)
875 IApplicationDestinationsImpl
*This
= impl_from_IApplicationDestinations(iface
);
876 ULONG ref
= InterlockedIncrement(&This
->ref
);
878 TRACE("(%p), new refcount=%i\n", This
, ref
);
883 static ULONG WINAPI
ApplicationDestinations_Release(IApplicationDestinations
*iface
)
885 IApplicationDestinationsImpl
*This
= impl_from_IApplicationDestinations(iface
);
886 ULONG ref
= InterlockedDecrement(&This
->ref
);
888 TRACE("(%p), new refcount=%i\n", This
, ref
);
896 static HRESULT WINAPI
ApplicationDestinations_SetAppID(IApplicationDestinations
*iface
, const WCHAR
*appid
)
898 IApplicationDestinationsImpl
*This
= impl_from_IApplicationDestinations(iface
);
900 FIXME("(%p, %s) stub!\n", This
, debugstr_w(appid
));
905 static HRESULT WINAPI
ApplicationDestinations_RemoveDestination(IApplicationDestinations
*iface
, IUnknown
*punk
)
907 IApplicationDestinationsImpl
*This
= impl_from_IApplicationDestinations(iface
);
909 FIXME("(%p, %p) stub!\n", This
, punk
);
914 static HRESULT WINAPI
ApplicationDestinations_RemoveAllDestinations(IApplicationDestinations
*iface
)
916 IApplicationDestinationsImpl
*This
= impl_from_IApplicationDestinations(iface
);
918 FIXME("(%p) stub!\n", This
);
923 static const IApplicationDestinationsVtbl ApplicationDestinationsVtbl
=
925 ApplicationDestinations_QueryInterface
,
926 ApplicationDestinations_AddRef
,
927 ApplicationDestinations_Release
,
928 ApplicationDestinations_SetAppID
,
929 ApplicationDestinations_RemoveDestination
,
930 ApplicationDestinations_RemoveAllDestinations
933 HRESULT WINAPI
ApplicationDestinations_Constructor(IUnknown
*outer
, REFIID riid
, LPVOID
*ppv
)
935 IApplicationDestinationsImpl
*This
;
938 TRACE("(%p, %s, %p)\n", outer
, debugstr_guid(riid
), ppv
);
941 return CLASS_E_NOAGGREGATION
;
943 if (!(This
= SHAlloc(sizeof(*This
))))
944 return E_OUTOFMEMORY
;
946 This
->IApplicationDestinations_iface
.lpVtbl
= &ApplicationDestinationsVtbl
;
949 hr
= IUnknown_QueryInterface(&This
->IApplicationDestinations_iface
, riid
, ppv
);
958 IApplicationDocumentLists IApplicationDocumentLists_iface
;
960 } IApplicationDocumentListsImpl
;
962 static inline IApplicationDocumentListsImpl
*impl_from_IApplicationDocumentLists( IApplicationDocumentLists
*iface
)
964 return CONTAINING_RECORD(iface
, IApplicationDocumentListsImpl
, IApplicationDocumentLists_iface
);
967 static HRESULT WINAPI
ApplicationDocumentLists_QueryInterface(IApplicationDocumentLists
*iface
,
968 REFIID riid
, LPVOID
*ppv
)
970 IApplicationDocumentListsImpl
*This
= impl_from_IApplicationDocumentLists(iface
);
972 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppv
);
977 if (IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IApplicationDocumentLists
, riid
))
979 *ppv
= &This
->IApplicationDocumentLists_iface
;
980 IUnknown_AddRef((IUnknown
*)*ppv
);
982 TRACE("Returning IApplicationDocumentLists: %p\n", *ppv
);
987 FIXME("(%p)->(%s, %p) interface not supported.\n", This
, debugstr_guid(riid
), ppv
);
989 return E_NOINTERFACE
;
992 static ULONG WINAPI
ApplicationDocumentLists_AddRef(IApplicationDocumentLists
*iface
)
994 IApplicationDocumentListsImpl
*This
= impl_from_IApplicationDocumentLists(iface
);
995 ULONG ref
= InterlockedIncrement(&This
->ref
);
997 TRACE("(%p), new refcount=%i\n", This
, ref
);
1002 static ULONG WINAPI
ApplicationDocumentLists_Release(IApplicationDocumentLists
*iface
)
1004 IApplicationDocumentListsImpl
*This
= impl_from_IApplicationDocumentLists(iface
);
1005 ULONG ref
= InterlockedDecrement(&This
->ref
);
1007 TRACE("(%p), new refcount=%i\n", This
, ref
);
1015 static HRESULT WINAPI
ApplicationDocumentLists_SetAppID(IApplicationDocumentLists
*iface
,
1018 IApplicationDocumentListsImpl
*This
= impl_from_IApplicationDocumentLists(iface
);
1020 FIXME("(%p, %s) stub!\n", This
, debugstr_w(appid
));
1025 static HRESULT WINAPI
ApplicationDocumentLists_GetList(IApplicationDocumentLists
*iface
,
1026 APPDOCLISTTYPE list_type
, UINT item_count
,
1027 REFIID riid
, void **obj
)
1029 IApplicationDocumentListsImpl
*This
= impl_from_IApplicationDocumentLists(iface
);
1031 FIXME("(%p, %u, %u, %s, %p): stub\n", This
, list_type
, item_count
, debugstr_guid(riid
), obj
);
1036 static const IApplicationDocumentListsVtbl ApplicationDocumentListsVtbl
=
1038 ApplicationDocumentLists_QueryInterface
,
1039 ApplicationDocumentLists_AddRef
,
1040 ApplicationDocumentLists_Release
,
1041 ApplicationDocumentLists_SetAppID
,
1042 ApplicationDocumentLists_GetList
1045 HRESULT WINAPI
ApplicationDocumentLists_Constructor(IUnknown
*outer
, REFIID riid
, LPVOID
*ppv
)
1047 IApplicationDocumentListsImpl
*This
;
1050 TRACE("(%p, %s, %p)\n", outer
, debugstr_guid(riid
), ppv
);
1053 return CLASS_E_NOAGGREGATION
;
1055 if (!(This
= SHAlloc(sizeof(*This
))))
1056 return E_OUTOFMEMORY
;
1058 This
->IApplicationDocumentLists_iface
.lpVtbl
= &ApplicationDocumentListsVtbl
;
1061 hr
= IUnknown_QueryInterface(&This
->IApplicationDocumentLists_iface
, riid
, ppv
);
1070 const KNOWNFOLDERID
*id
;
1073 const WCHAR
*def_path
; /* fallback string or resource ID */
1074 KF_CATEGORY category
;
1076 const KNOWNFOLDERID
*parent
;
1078 const WCHAR
*parsing
;
1080 KF_DEFINITION_FLAGS flags
;
1081 const FOLDERTYPEID
*typeid;
1084 static const CSIDL_DATA CSIDL_Data
[] =
1086 { /* 0x00 - CSIDL_DESKTOP */
1087 .id
= &FOLDERID_Desktop
,
1088 .type
= CSIDL_Type_User
,
1089 .value
= L
"Desktop",
1090 .category
= KF_CATEGORY_PERUSER
,
1093 .attributes
= FILE_ATTRIBUTE_READONLY
,
1095 { /* 0x01 - CSIDL_INTERNET */
1096 .id
= &FOLDERID_InternetFolder
,
1097 .type
= CSIDL_Type_Disallowed
,
1098 .category
= KF_CATEGORY_VIRTUAL
,
1099 .name
= L
"InternetFolder",
1100 .parsing
= L
"::{871C5380-42A0-1069-A2EA-08002B30309D}",
1102 { /* 0x02 - CSIDL_PROGRAMS */
1103 .id
= &FOLDERID_Programs
,
1104 .type
= CSIDL_Type_User
,
1105 .value
= L
"Programs",
1106 .category
= KF_CATEGORY_PERUSER
,
1107 .name
= L
"Programs",
1108 .parent
= &FOLDERID_StartMenu
,
1109 .path
= L
"Programs",
1110 .attributes
= FILE_ATTRIBUTE_READONLY
,
1112 { /* 0x03 - CSIDL_CONTROLS (.CPL files) */
1113 .id
= &FOLDERID_ControlPanelFolder
,
1114 .type
= CSIDL_Type_SystemPath
,
1115 .category
= KF_CATEGORY_VIRTUAL
,
1116 .name
= L
"ControlPanelFolder",
1117 .path
= L
"::{21EC2020-3AEA-1069-A2DD-08002B30309D}",
1118 .parsing
= L
"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0",
1120 { /* 0x04 - CSIDL_PRINTERS */
1121 .id
= &FOLDERID_PrintersFolder
,
1122 .type
= CSIDL_Type_SystemPath
,
1123 .category
= KF_CATEGORY_VIRTUAL
,
1124 .name
= L
"PrintersFolder",
1125 .parsing
= L
"::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}",
1127 { /* 0x05 - CSIDL_PERSONAL */
1128 .id
= &FOLDERID_Documents
,
1129 .type
= CSIDL_Type_User
,
1130 .value
= L
"Personal",
1131 .category
= KF_CATEGORY_PERUSER
,
1132 .name
= L
"Personal",
1133 .parent
= &FOLDERID_Profile
,
1134 .path
= L
"Documents",
1135 .parsing
= L
"::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{FDD39AD0-238F-46AF-ADB4-6C85480369C7}",
1136 .attributes
= FILE_ATTRIBUTE_READONLY
,
1137 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
,
1139 { /* 0x06 - CSIDL_FAVORITES */
1140 .id
= &FOLDERID_Favorites
,
1141 .type
= CSIDL_Type_User
,
1142 .value
= L
"Favorites",
1143 .category
= KF_CATEGORY_PERUSER
,
1144 .name
= L
"Favorites",
1145 .path
= L
"Favorites",
1146 .attributes
= FILE_ATTRIBUTE_READONLY
,
1147 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
| KFDF_PUBLISHEXPANDEDPATH
,
1149 { /* 0x07 - CSIDL_STARTUP */
1150 .id
= &FOLDERID_Startup
,
1151 .type
= CSIDL_Type_User
,
1152 .value
= L
"StartUp",
1153 .category
= KF_CATEGORY_PERUSER
,
1155 .parent
= &FOLDERID_Programs
,
1157 .attributes
= FILE_ATTRIBUTE_READONLY
,
1158 .flags
= KFDF_PRECREATE
,
1160 { /* 0x08 - CSIDL_RECENT */
1161 .id
= &FOLDERID_Recent
,
1162 .type
= CSIDL_Type_User
,
1164 .category
= KF_CATEGORY_PERUSER
,
1166 .parent
= &FOLDERID_RoamingAppData
,
1167 .path
= L
"Microsoft\\Windows\\Recent",
1168 .attributes
= FILE_ATTRIBUTE_READONLY
,
1169 .flags
= KFDF_PRECREATE
,
1171 { /* 0x09 - CSIDL_SENDTO */
1172 .id
= &FOLDERID_SendTo
,
1173 .type
= CSIDL_Type_User
,
1175 .category
= KF_CATEGORY_PERUSER
,
1177 .parent
= &FOLDERID_RoamingAppData
,
1178 .path
= L
"Microsoft\\Windows\\SendTo",
1179 .flags
= KFDF_PRECREATE
,
1181 { /* 0x0a - CSIDL_BITBUCKET - Recycle Bin */
1182 .id
= &FOLDERID_RecycleBinFolder
,
1183 .type
= CSIDL_Type_Disallowed
,
1184 .category
= KF_CATEGORY_VIRTUAL
,
1185 .name
= L
"RecycleBinFolder",
1186 .parsing
= L
"::{645FF040-5081-101B-9F08-00AA002F954E}",
1188 { /* 0x0b - CSIDL_STARTMENU */
1189 .id
= &FOLDERID_StartMenu
,
1190 .type
= CSIDL_Type_User
,
1191 .value
= L
"Start Menu",
1192 .category
= KF_CATEGORY_PERUSER
,
1193 .name
= L
"Start Menu",
1194 .parent
= &FOLDERID_RoamingAppData
,
1195 .path
= L
"Microsoft\\Windows\\Start Menu",
1196 .attributes
= FILE_ATTRIBUTE_READONLY
,
1197 .flags
= KFDF_PRECREATE
,
1199 { /* 0x0c - CSIDL_MYDOCUMENTS */
1201 .type
= CSIDL_Type_Disallowed
, /* matches WinXP--can't get its path */
1203 { /* 0x0d - CSIDL_MYMUSIC */
1204 .id
= &FOLDERID_Music
,
1205 .type
= CSIDL_Type_User
,
1206 .value
= L
"My Music",
1207 .category
= KF_CATEGORY_PERUSER
,
1208 .name
= L
"My Music",
1209 .parent
= &FOLDERID_Profile
,
1211 .parsing
= L
"::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{4BD8D571-6D19-48D3-BE97-422220080E43}",
1212 .attributes
= FILE_ATTRIBUTE_READONLY
,
1213 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
,
1215 { /* 0x0e - CSIDL_MYVIDEO */
1216 .id
= &FOLDERID_Videos
,
1217 .type
= CSIDL_Type_User
,
1218 .value
= L
"My Videos",
1219 .category
= KF_CATEGORY_PERUSER
,
1220 .name
= L
"My Video",
1221 .parent
= &FOLDERID_Profile
,
1223 .parsing
= L
"::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{18989B1D-99B5-455B-841C-AB7C74E4DDFC}",
1224 .attributes
= FILE_ATTRIBUTE_READONLY
,
1225 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
,
1227 { /* 0x0f - unassigned */
1229 .type
= CSIDL_Type_Disallowed
,
1231 { /* 0x10 - CSIDL_DESKTOPDIRECTORY */
1232 .id
= &FOLDERID_Desktop
,
1233 .type
= CSIDL_Type_User
,
1234 .value
= L
"Desktop",
1235 .category
= KF_CATEGORY_PERUSER
,
1237 .parent
= &FOLDERID_Profile
,
1239 .attributes
= FILE_ATTRIBUTE_READONLY
,
1240 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
| KFDF_PUBLISHEXPANDEDPATH
,
1242 { /* 0x11 - CSIDL_DRIVES */
1243 .id
= &FOLDERID_ComputerFolder
,
1244 .type
= CSIDL_Type_Disallowed
,
1245 .category
= KF_CATEGORY_VIRTUAL
,
1246 .name
= L
"MyComputerFolder",
1247 .parsing
= L
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
1249 { /* 0x12 - CSIDL_NETWORK */
1250 .id
= &FOLDERID_NetworkFolder
,
1251 .type
= CSIDL_Type_Disallowed
,
1252 .category
= KF_CATEGORY_VIRTUAL
,
1253 .name
= L
"NetworkPlacesFolder",
1254 .parsing
= L
"::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}",
1256 { /* 0x13 - CSIDL_NETHOOD */
1257 .id
= &FOLDERID_NetHood
,
1258 .type
= CSIDL_Type_User
,
1259 .value
= L
"NetHood",
1260 .category
= KF_CATEGORY_PERUSER
,
1262 .parent
= &FOLDERID_RoamingAppData
,
1263 .path
= L
"Microsoft\\Windows\\Network Shortcuts",
1265 { /* 0x14 - CSIDL_FONTS */
1266 .id
= &FOLDERID_Fonts
,
1267 .type
= CSIDL_Type_WindowsPath
,
1269 .def_path
= L
"Fonts",
1270 .category
= KF_CATEGORY_FIXED
,
1272 .parent
= &FOLDERID_Windows
,
1273 .typeid = &FOLDERID_Windows
1275 { /* 0x15 - CSIDL_TEMPLATES */
1276 .id
= &FOLDERID_Templates
,
1277 .type
= CSIDL_Type_User
,
1278 .value
= L
"Templates",
1279 .category
= KF_CATEGORY_PERUSER
,
1280 .name
= L
"Templates",
1281 .parent
= &FOLDERID_RoamingAppData
,
1282 .path
= L
"Microsoft\\Windows\\Templates",
1284 { /* 0x16 - CSIDL_COMMON_STARTMENU */
1285 .id
= &FOLDERID_CommonStartMenu
,
1286 .type
= CSIDL_Type_ProgramData
,
1287 .value
= L
"Common Start Menu",
1288 .category
= KF_CATEGORY_COMMON
,
1289 .name
= L
"Common Start Menu",
1290 .parent
= &FOLDERID_ProgramData
,
1291 .path
= L
"Microsoft\\Windows\\Start Menu",
1292 .attributes
= FILE_ATTRIBUTE_READONLY
,
1294 { /* 0x17 - CSIDL_COMMON_PROGRAMS */
1295 .id
= &FOLDERID_CommonPrograms
,
1296 .type
= CSIDL_Type_ProgramData
,
1297 .value
= L
"Common Programs",
1298 .category
= KF_CATEGORY_COMMON
,
1299 .name
= L
"Common Programs",
1300 .parent
= &FOLDERID_CommonStartMenu
,
1301 .path
= L
"Programs",
1302 .attributes
= FILE_ATTRIBUTE_READONLY
,
1304 { /* 0x18 - CSIDL_COMMON_STARTUP */
1305 .id
= &FOLDERID_CommonStartup
,
1306 .type
= CSIDL_Type_ProgramData
,
1307 .value
= L
"Common StartUp",
1308 .category
= KF_CATEGORY_COMMON
,
1309 .name
= L
"Common Startup",
1310 .parent
= &FOLDERID_CommonPrograms
,
1312 .attributes
= FILE_ATTRIBUTE_READONLY
,
1313 .flags
= KFDF_PRECREATE
,
1315 { /* 0x19 - CSIDL_COMMON_DESKTOPDIRECTORY */
1316 .id
= &FOLDERID_PublicDesktop
,
1317 .type
= CSIDL_Type_AllUsers
,
1318 .value
= L
"Common Desktop",
1319 .category
= KF_CATEGORY_COMMON
,
1320 .name
= L
"Common Desktop",
1321 .parent
= &FOLDERID_Public
,
1323 .attributes
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
,
1324 .flags
= KFDF_PRECREATE
,
1326 { /* 0x1a - CSIDL_APPDATA */
1327 .id
= &FOLDERID_RoamingAppData
,
1328 .type
= CSIDL_Type_User
,
1329 .value
= L
"AppData",
1330 .category
= KF_CATEGORY_PERUSER
,
1332 .parent
= &FOLDERID_Profile
,
1333 .path
= L
"AppData\\Roaming",
1335 { /* 0x1b - CSIDL_PRINTHOOD */
1336 .id
= &FOLDERID_PrintHood
,
1337 .type
= CSIDL_Type_User
,
1338 .value
= L
"PrintHood",
1339 .category
= KF_CATEGORY_PERUSER
,
1340 .name
= L
"PrintHood",
1341 .parent
= &FOLDERID_RoamingAppData
,
1342 .path
= L
"Microsoft\\Windows\\Printer Shortcuts",
1344 { /* 0x1c - CSIDL_LOCAL_APPDATA */
1345 .id
= &FOLDERID_LocalAppData
,
1346 .type
= CSIDL_Type_User
,
1347 .value
= L
"Local AppData",
1348 .category
= KF_CATEGORY_PERUSER
,
1349 .name
= L
"Local AppData",
1350 .parent
= &FOLDERID_Profile
,
1351 .path
= L
"AppData\\Local",
1352 .flags
= KFDF_LOCAL_REDIRECT_ONLY
| KFDF_PUBLISHEXPANDEDPATH
,
1354 { /* 0x1d - CSIDL_ALTSTARTUP */
1356 .type
= CSIDL_Type_NonExistent
,
1358 { /* 0x1e - CSIDL_COMMON_ALTSTARTUP */
1360 .type
= CSIDL_Type_NonExistent
,
1362 { /* 0x1f - CSIDL_COMMON_FAVORITES */
1363 .id
= &FOLDERID_Favorites
,
1364 .type
= CSIDL_Type_AllUsers
,
1365 .value
= L
"Common Favorites",
1366 .category
= KF_CATEGORY_PERUSER
,
1367 .name
= L
"Favorites",
1368 .parent
= &FOLDERID_Profile
,
1369 .path
= L
"Favorites",
1370 .attributes
= FILE_ATTRIBUTE_READONLY
,
1371 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
| KFDF_PUBLISHEXPANDEDPATH
,
1373 { /* 0x20 - CSIDL_INTERNET_CACHE */
1374 .id
= &FOLDERID_InternetCache
,
1375 .type
= CSIDL_Type_User
,
1377 .category
= KF_CATEGORY_PERUSER
,
1379 .parent
= &FOLDERID_LocalAppData
,
1380 .path
= L
"Microsoft\\Windows\\INetCache",
1381 .flags
= KFDF_LOCAL_REDIRECT_ONLY
,
1383 { /* 0x21 - CSIDL_COOKIES */
1384 .id
= &FOLDERID_Cookies
,
1385 .type
= CSIDL_Type_User
,
1386 .value
= L
"Cookies",
1387 .category
= KF_CATEGORY_PERUSER
,
1389 .parent
= &FOLDERID_LocalAppData
,
1390 .path
= L
"Microsoft\\Windows\\INetCookies",
1392 { /* 0x22 - CSIDL_HISTORY */
1393 .id
= &FOLDERID_History
,
1394 .type
= CSIDL_Type_User
,
1395 .value
= L
"History",
1396 .category
= KF_CATEGORY_PERUSER
,
1398 .parent
= &FOLDERID_LocalAppData
,
1399 .path
= L
"Microsoft\\Windows\\History",
1400 .flags
= KFDF_LOCAL_REDIRECT_ONLY
,
1402 { /* 0x23 - CSIDL_COMMON_APPDATA */
1403 .id
= &FOLDERID_ProgramData
,
1404 .type
= CSIDL_Type_ProgramData
,
1405 .value
= L
"Common AppData",
1406 .category
= KF_CATEGORY_FIXED
,
1407 .name
= L
"Common AppData",
1409 { /* 0x24 - CSIDL_WINDOWS */
1410 .id
= &FOLDERID_Windows
,
1411 .type
= CSIDL_Type_WindowsPath
,
1412 .category
= KF_CATEGORY_FIXED
,
1415 { /* 0x25 - CSIDL_SYSTEM */
1416 .id
= &FOLDERID_System
,
1417 .type
= CSIDL_Type_SystemPath
,
1418 .category
= KF_CATEGORY_FIXED
,
1421 { /* 0x26 - CSIDL_PROGRAM_FILES */
1422 .id
= &FOLDERID_ProgramFiles
,
1423 .type
= CSIDL_Type_CurrVer
,
1424 .value
= L
"ProgramFilesDir",
1425 .def_path
= L
"Program Files",
1426 .category
= KF_CATEGORY_FIXED
,
1427 .name
= L
"ProgramFiles",
1428 .attributes
= FILE_ATTRIBUTE_READONLY
,
1430 { /* 0x27 - CSIDL_MYPICTURES */
1431 .id
= &FOLDERID_Pictures
,
1432 .type
= CSIDL_Type_User
,
1433 .value
= L
"My Pictures",
1434 .category
= KF_CATEGORY_PERUSER
,
1435 .name
= L
"My Pictures",
1436 .parent
= &FOLDERID_Profile
,
1437 .path
= L
"Pictures",
1438 .parsing
= L
"::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{33E28130-4E1E-4676-835A-98395C3BC3BB}",
1439 .attributes
= FILE_ATTRIBUTE_READONLY
,
1440 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
,
1442 { /* 0x28 - CSIDL_PROFILE */
1443 .id
= &FOLDERID_Profile
,
1444 .type
= CSIDL_Type_User
,
1445 .category
= KF_CATEGORY_FIXED
,
1448 { /* 0x29 - CSIDL_SYSTEMX86 */
1449 .id
= &FOLDERID_SystemX86
,
1450 .type
= CSIDL_Type_SystemX86Path
,
1451 .category
= KF_CATEGORY_FIXED
,
1452 .name
= L
"SystemX86",
1454 { /* 0x2a - CSIDL_PROGRAM_FILESX86 */
1455 .id
= &FOLDERID_ProgramFilesX86
,
1456 .type
= CSIDL_Type_CurrVer
,
1457 .value
= L
"ProgramFilesDir (x86)",
1458 .def_path
= L
"Program Files (x86)",
1459 .category
= KF_CATEGORY_FIXED
,
1460 .name
= L
"ProgramFilesX86",
1461 .attributes
= FILE_ATTRIBUTE_READONLY
,
1463 { /* 0x2b - CSIDL_PROGRAM_FILES_COMMON */
1464 .id
= &FOLDERID_ProgramFilesCommon
,
1465 .type
= CSIDL_Type_CurrVer
,
1466 .value
= L
"CommonFilesDir",
1467 .def_path
= L
"Program Files\\Common Files",
1468 .category
= KF_CATEGORY_FIXED
,
1469 .name
= L
"ProgramFilesCommon",
1471 { /* 0x2c - CSIDL_PROGRAM_FILES_COMMONX86 */
1472 .id
= &FOLDERID_ProgramFilesCommonX86
,
1473 .type
= CSIDL_Type_CurrVer
,
1474 .value
= L
"CommonFilesDir (x86)",
1475 .def_path
= L
"Program Files (x86)\\Common Files",
1476 .category
= KF_CATEGORY_FIXED
,
1477 .name
= L
"ProgramFilesCommonX86",
1479 { /* 0x2d - CSIDL_COMMON_TEMPLATES */
1480 .id
= &FOLDERID_CommonTemplates
,
1481 .type
= CSIDL_Type_ProgramData
,
1482 .value
= L
"Common Templates",
1483 .category
= KF_CATEGORY_COMMON
,
1484 .name
= L
"Common Templates",
1485 .parent
= &FOLDERID_ProgramData
,
1486 .path
= L
"Microsoft\\Windows\\Templates",
1488 { /* 0x2e - CSIDL_COMMON_DOCUMENTS */
1489 .id
= &FOLDERID_PublicDocuments
,
1490 .type
= CSIDL_Type_AllUsers
,
1491 .value
= L
"Common Documents",
1492 .category
= KF_CATEGORY_COMMON
,
1493 .name
= L
"Common Documents",
1494 .parent
= &FOLDERID_Public
,
1495 .path
= L
"Documents",
1496 .attributes
= FILE_ATTRIBUTE_READONLY
,
1497 .flags
= KFDF_PRECREATE
,
1499 { /* 0x2f - CSIDL_COMMON_ADMINTOOLS */
1500 .id
= &FOLDERID_CommonAdminTools
,
1501 .type
= CSIDL_Type_ProgramData
,
1502 .value
= L
"Common Administrative Tools",
1503 .category
= KF_CATEGORY_COMMON
,
1504 .name
= L
"Common Administrative Tools",
1505 .parent
= &FOLDERID_CommonPrograms
,
1506 .path
= L
"Administrative Tools",
1507 .attributes
= FILE_ATTRIBUTE_READONLY
,
1508 .flags
= KFDF_PRECREATE
,
1510 { /* 0x30 - CSIDL_ADMINTOOLS */
1511 .id
= &FOLDERID_AdminTools
,
1512 .type
= CSIDL_Type_User
,
1513 .value
= L
"Administrative Tools",
1514 .category
= KF_CATEGORY_PERUSER
,
1515 .name
= L
"Administrative Tools",
1516 .parent
= &FOLDERID_Programs
,
1517 .path
= L
"Administrative Tools",
1518 .attributes
= FILE_ATTRIBUTE_READONLY
,
1519 .flags
= KFDF_PRECREATE
,
1521 { /* 0x31 - CSIDL_CONNECTIONS */
1522 .id
= &FOLDERID_ConnectionsFolder
,
1523 .type
= CSIDL_Type_Disallowed
,
1524 .category
= KF_CATEGORY_VIRTUAL
,
1525 .name
= L
"ConnectionsFolder",
1526 .path
= L
"Administrative Tools",
1527 .parsing
= L
"::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
1529 { /* 0x32 - unassigned */
1531 .type
= CSIDL_Type_Disallowed
,
1533 { /* 0x33 - unassigned */
1535 .type
= CSIDL_Type_Disallowed
,
1537 { /* 0x34 - unassigned */
1539 .type
= CSIDL_Type_Disallowed
,
1541 { /* 0x35 - CSIDL_COMMON_MUSIC */
1542 .id
= &FOLDERID_PublicMusic
,
1543 .type
= CSIDL_Type_AllUsers
,
1544 .value
= L
"CommonMusic",
1545 .category
= KF_CATEGORY_COMMON
,
1546 .name
= L
"CommonMusic",
1547 .parent
= &FOLDERID_Public
,
1549 .attributes
= FILE_ATTRIBUTE_READONLY
,
1550 .flags
= KFDF_PRECREATE
,
1552 { /* 0x36 - CSIDL_COMMON_PICTURES */
1553 .id
= &FOLDERID_PublicPictures
,
1554 .type
= CSIDL_Type_AllUsers
,
1555 .value
= L
"CommonPictures",
1556 .category
= KF_CATEGORY_COMMON
,
1557 .name
= L
"CommonPictures",
1558 .parent
= &FOLDERID_Public
,
1559 .path
= L
"Pictures",
1560 .attributes
= FILE_ATTRIBUTE_READONLY
,
1561 .flags
= KFDF_PRECREATE
,
1563 { /* 0x37 - CSIDL_COMMON_VIDEO */
1564 .id
= &FOLDERID_PublicVideos
,
1565 .type
= CSIDL_Type_AllUsers
,
1566 .value
= L
"CommonVideo",
1567 .category
= KF_CATEGORY_COMMON
,
1568 .name
= L
"CommonVideo",
1569 .parent
= &FOLDERID_Public
,
1571 .attributes
= FILE_ATTRIBUTE_READONLY
,
1572 .flags
= KFDF_PRECREATE
,
1574 { /* 0x38 - CSIDL_RESOURCES */
1575 .id
= &FOLDERID_ResourceDir
,
1576 .type
= CSIDL_Type_WindowsPath
,
1577 .def_path
= L
"Resources",
1578 .category
= KF_CATEGORY_FIXED
,
1579 .name
= L
"ResourceDir",
1581 { /* 0x39 - CSIDL_RESOURCES_LOCALIZED */
1582 .id
= &FOLDERID_LocalizedResourcesDir
,
1583 .type
= CSIDL_Type_NonExistent
,
1584 .category
= KF_CATEGORY_FIXED
,
1585 .name
= L
"LocalizedResourcesDir",
1587 { /* 0x3a - CSIDL_COMMON_OEM_LINKS */
1588 .id
= &FOLDERID_CommonOEMLinks
,
1589 .type
= CSIDL_Type_ProgramData
,
1590 .category
= KF_CATEGORY_COMMON
,
1591 .name
= L
"OEM Links",
1592 .parent
= &FOLDERID_ProgramData
,
1593 .path
= L
"OEM Links",
1595 { /* 0x3b - CSIDL_CDBURN_AREA */
1596 .id
= &FOLDERID_CDBurning
,
1597 .type
= CSIDL_Type_User
,
1598 .value
= L
"CD Burning",
1599 .category
= KF_CATEGORY_PERUSER
,
1600 .name
= L
"CD Burning",
1601 .parent
= &FOLDERID_LocalAppData
,
1602 .path
= L
"Microsoft\\Windows\\Burn\\Burn",
1603 .attributes
= FILE_ATTRIBUTE_READONLY
,
1604 .flags
= KFDF_LOCAL_REDIRECT_ONLY
,
1606 { /* 0x3c unassigned */
1608 .type
= CSIDL_Type_Disallowed
,
1610 { /* 0x3d - CSIDL_COMPUTERSNEARME */
1612 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1614 { /* 0x3e - CSIDL_PROFILES */
1616 .type
= CSIDL_Type_Disallowed
, /* oddly, this matches WinXP */
1619 .id
= &FOLDERID_AddNewPrograms
,
1620 .type
= CSIDL_Type_Disallowed
,
1621 .category
= KF_CATEGORY_VIRTUAL
,
1622 .name
= L
"AddNewProgramsFolder",
1623 .parsing
= L
"::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{15eae92e-f17a-4431-9f28-805e482dafd4}",
1626 .id
= &FOLDERID_AppUpdates
,
1627 .type
= CSIDL_Type_Disallowed
,
1628 .category
= KF_CATEGORY_VIRTUAL
,
1629 .name
= L
"AppUpdatesFolder",
1630 .parsing
= L
"::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}\\::{d450a8a1-9568-45c7-9c0e-b4f9fb4537bd}",
1633 .id
= &FOLDERID_ChangeRemovePrograms
,
1634 .type
= CSIDL_Type_Disallowed
,
1635 .category
= KF_CATEGORY_VIRTUAL
,
1636 .name
= L
"ChangeRemoveProgramsFolder",
1637 .parsing
= L
"::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}",
1640 .id
= &FOLDERID_ConflictFolder
,
1641 .type
= CSIDL_Type_Disallowed
,
1642 .category
= KF_CATEGORY_VIRTUAL
,
1643 .name
= L
"ConflictFolder",
1644 .parsing
= L
"::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{E413D040-6788-4C22-957E-175D1C513A34},",
1646 { /* 0x43 - CSIDL_CONTACTS */
1647 .id
= &FOLDERID_Contacts
,
1648 .type
= CSIDL_Type_User
,
1649 .category
= KF_CATEGORY_PERUSER
,
1650 .name
= L
"Contacts",
1651 .parent
= &FOLDERID_Profile
,
1652 .path
= L
"Contacts",
1653 .parsing
= L
"::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{56784854-C6CB-462B-8169-88E350ACB882}",
1654 .attributes
= FILE_ATTRIBUTE_READONLY
,
1655 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
| KFDF_PUBLISHEXPANDEDPATH
,
1658 .id
= &FOLDERID_DeviceMetadataStore
,
1659 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1660 .category
= KF_CATEGORY_COMMON
,
1661 .name
= L
"Device Metadata Store",
1662 .parent
= &FOLDERID_ProgramData
,
1663 .path
= L
"Microsoft\\Windows\\DeviceMetadataStore",
1667 .type
= CSIDL_Type_Disallowed
,
1670 .id
= &FOLDERID_DocumentsLibrary
,
1671 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1672 .category
= KF_CATEGORY_PERUSER
,
1673 .name
= L
"DocumentsLibrary",
1674 .parent
= &FOLDERID_Libraries
,
1675 .path
= L
"Documents.library-ms",
1676 .parsing
= L
"::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{7b0db17d-9cd2-4a93-9733-46cc89022e7c}",
1677 .flags
= KFDF_PRECREATE
| KFDF_STREAM
,
1679 { /* 0x47 - CSIDL_DOWNLOADS */
1680 .id
= &FOLDERID_Downloads
,
1681 .type
= CSIDL_Type_User
,
1682 .category
= KF_CATEGORY_PERUSER
,
1683 .name
= L
"Downloads",
1684 .parent
= &FOLDERID_Profile
,
1685 .path
= L
"Downloads",
1686 .attributes
= FILE_ATTRIBUTE_READONLY
,
1687 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
| KFDF_PUBLISHEXPANDEDPATH
,
1690 .id
= &FOLDERID_Games
,
1691 .type
= CSIDL_Type_Disallowed
,
1692 .category
= KF_CATEGORY_VIRTUAL
,
1694 .parsing
= L
"::{ED228FDF-9EA8-4870-83b1-96b02CFE0D52}",
1697 .id
= &FOLDERID_GameTasks
,
1698 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1699 .category
= KF_CATEGORY_PERUSER
,
1700 .name
= L
"GameTasks",
1701 .parent
= &FOLDERID_LocalAppData
,
1702 .path
= L
"Microsoft\\Windows\\GameExplorer",
1703 .flags
= KFDF_LOCAL_REDIRECT_ONLY
,
1706 .id
= &FOLDERID_HomeGroup
,
1707 .type
= CSIDL_Type_Disallowed
,
1708 .category
= KF_CATEGORY_VIRTUAL
,
1709 .name
= L
"HomeGroupFolder",
1710 .parsing
= L
"::{B4FB3F98-C1EA-428d-A78A-D1F5659CBA93}",
1713 .id
= &FOLDERID_ImplicitAppShortcuts
,
1714 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1715 .category
= KF_CATEGORY_PERUSER
,
1716 .name
= L
"ImplicitAppShortcuts",
1717 .parent
= &FOLDERID_UserPinned
,
1718 .path
= L
"ImplicitAppShortcuts",
1719 .flags
= KFDF_PRECREATE
,
1722 .id
= &FOLDERID_Libraries
,
1723 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1724 .category
= KF_CATEGORY_PERUSER
,
1725 .name
= L
"Libraries",
1726 .parent
= &FOLDERID_RoamingAppData
,
1727 .path
= L
"Microsoft\\Windows\\Libraries",
1728 .flags
= KFDF_PRECREATE
| KFDF_PUBLISHEXPANDEDPATH
,
1730 { /* 0x4d - CSIDL_LINKS */
1731 .id
= &FOLDERID_Links
,
1732 .type
= CSIDL_Type_User
,
1733 .category
= KF_CATEGORY_PERUSER
,
1735 .parent
= &FOLDERID_Profile
,
1737 .parsing
= L
"::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{bfb9d5e0-c6a9-404c-b2b2-ae6db6af4968}",
1738 .attributes
= FILE_ATTRIBUTE_READONLY
,
1739 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
| KFDF_PUBLISHEXPANDEDPATH
,
1741 { /* 0x4e - CSIDL_APPDATA_LOCALLOW */
1742 .id
= &FOLDERID_LocalAppDataLow
,
1743 .type
= CSIDL_Type_User
,
1744 .category
= KF_CATEGORY_PERUSER
,
1745 .name
= L
"LocalAppDataLow",
1746 .parent
= &FOLDERID_Profile
,
1747 .path
= L
"AppData\\LocalLow",
1748 .attributes
= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
,
1749 .flags
= KFDF_LOCAL_REDIRECT_ONLY
| KFDF_PRECREATE
| KFDF_PUBLISHEXPANDEDPATH
,
1752 .id
= &FOLDERID_MusicLibrary
,
1753 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1754 .category
= KF_CATEGORY_PERUSER
,
1755 .name
= L
"MusicLibrary",
1756 .parent
= &FOLDERID_Libraries
,
1757 .path
= L
"Music.library-ms",
1758 .parsing
= L
"::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{2112AB0A-C86A-4ffe-A368-0DE96E47012E}",
1759 .flags
= KFDF_PRECREATE
| KFDF_STREAM
,
1762 .id
= &FOLDERID_OriginalImages
,
1763 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1764 .category
= KF_CATEGORY_PERUSER
,
1765 .name
= L
"Original Images",
1766 .parent
= &FOLDERID_LocalAppData
,
1767 .path
= L
"Microsoft\\Windows Photo Gallery\\Original Images",
1770 .id
= &FOLDERID_PhotoAlbums
,
1771 .type
= CSIDL_Type_User
,
1772 .category
= KF_CATEGORY_PERUSER
,
1773 .name
= L
"PhotoAlbums",
1774 .parent
= &FOLDERID_Pictures
,
1775 .path
= L
"Slide Shows",
1776 .attributes
= FILE_ATTRIBUTE_READONLY
,
1779 .id
= &FOLDERID_PicturesLibrary
,
1780 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1781 .category
= KF_CATEGORY_PERUSER
,
1782 .name
= L
"PicturesLibrary",
1783 .parent
= &FOLDERID_Libraries
,
1784 .path
= L
"Pictures.library-ms",
1785 .parsing
= L
"::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{A990AE9F-A03B-4e80-94BC-9912D7504104}",
1786 .flags
= KFDF_PRECREATE
| KFDF_STREAM
,
1789 .id
= &FOLDERID_Playlists
,
1790 .type
= CSIDL_Type_User
,
1791 .category
= KF_CATEGORY_PERUSER
,
1792 .name
= L
"Playlists",
1793 .parent
= &FOLDERID_Music
,
1794 .path
= L
"Playlists",
1795 .attributes
= FILE_ATTRIBUTE_READONLY
,
1798 .id
= &FOLDERID_ProgramFilesX64
,
1800 .type
= CSIDL_Type_CurrVer
,
1801 .value
= L
"ProgramFilesDir",
1802 .def_path
= L
"Program Files",
1804 .type
= CSIDL_Type_NonExistent
,
1806 .category
= KF_CATEGORY_FIXED
,
1807 .name
= L
"ProgramFilesX64",
1810 .id
= &FOLDERID_ProgramFilesCommonX64
,
1812 .type
= CSIDL_Type_CurrVer
,
1813 .value
= L
"ProgramFilesCommonX64",
1814 .def_path
= L
"Program Files\\Common Files",
1816 .type
= CSIDL_Type_NonExistent
,
1818 .category
= KF_CATEGORY_FIXED
,
1819 .name
= L
"ProgramFilesCommonX64",
1822 .id
= &FOLDERID_Public
,
1823 .type
= CSIDL_Type_AllUsers
,
1824 .category
= KF_CATEGORY_FIXED
,
1826 .parsing
= L
"::{4336a54d-038b-4685-ab02-99bb52d3fb8b}",
1827 .attributes
= FILE_ATTRIBUTE_READONLY
,
1828 .flags
= KFDF_PRECREATE
,
1831 .id
= &FOLDERID_PublicDownloads
,
1832 .type
= CSIDL_Type_AllUsers
,
1833 .category
= KF_CATEGORY_COMMON
,
1834 .name
= L
"CommonDownloads",
1835 .parent
= &FOLDERID_Public
,
1836 .path
= L
"Downloads",
1837 .attributes
= FILE_ATTRIBUTE_READONLY
,
1838 .flags
= KFDF_PRECREATE
,
1841 .id
= &FOLDERID_PublicGameTasks
,
1842 .type
= CSIDL_Type_ProgramData
,
1843 .category
= KF_CATEGORY_COMMON
,
1844 .name
= L
"PublicGameTasks",
1845 .parent
= &FOLDERID_ProgramData
,
1846 .path
= L
"Microsoft\\Windows\\GameExplorer",
1847 .flags
= KFDF_LOCAL_REDIRECT_ONLY
,
1850 .id
= &FOLDERID_PublicLibraries
,
1851 .type
= CSIDL_Type_AllUsers
,
1852 .category
= KF_CATEGORY_COMMON
,
1853 .name
= L
"PublicLibraries",
1854 .parent
= &FOLDERID_Public
,
1855 .path
= L
"Libraries",
1856 .attributes
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
,
1857 .flags
= KFDF_PRECREATE
,
1860 .id
= &FOLDERID_PublicRingtones
,
1861 .type
= CSIDL_Type_ProgramData
,
1862 .category
= KF_CATEGORY_COMMON
,
1863 .name
= L
"CommonRingtones",
1864 .parent
= &FOLDERID_ProgramData
,
1865 .path
= L
"Microsoft\\Windows\\Ringtones",
1866 .flags
= KFDF_PRECREATE
,
1869 .id
= &FOLDERID_QuickLaunch
,
1870 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1871 .category
= KF_CATEGORY_PERUSER
,
1872 .name
= L
"Quick Launch",
1873 .parent
= &FOLDERID_RoamingAppData
,
1874 .path
= L
"Microsoft\\Internet Explorer\\Quick Launch",
1877 .id
= &FOLDERID_RecordedTVLibrary
,
1878 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1879 .category
= KF_CATEGORY_COMMON
,
1880 .name
= L
"RecordedTVLibrary",
1881 .parent
= &FOLDERID_PublicLibraries
,
1882 .path
= L
"RecordedTV.library-ms",
1883 .flags
= KFDF_PRECREATE
| KFDF_STREAM
,
1886 .id
= &FOLDERID_Ringtones
,
1887 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1888 .category
= KF_CATEGORY_PERUSER
,
1889 .name
= L
"Ringtones",
1890 .parent
= &FOLDERID_LocalAppData
,
1891 .path
= L
"Microsoft\\Windows\\Ringtones",
1892 .flags
= KFDF_PRECREATE
,
1895 .id
= &FOLDERID_SampleMusic
,
1896 .type
= CSIDL_Type_AllUsers
,
1897 .category
= KF_CATEGORY_COMMON
,
1898 .name
= L
"SampleMusic",
1899 .parent
= &FOLDERID_PublicMusic
,
1900 .path
= L
"Sample Music",
1901 .attributes
= FILE_ATTRIBUTE_READONLY
,
1902 .flags
= KFDF_PRECREATE
,
1905 .id
= &FOLDERID_SamplePictures
,
1906 .type
= CSIDL_Type_AllUsers
,
1907 .category
= KF_CATEGORY_COMMON
,
1908 .name
= L
"SamplePictures",
1909 .parent
= &FOLDERID_PublicPictures
,
1910 .path
= L
"Sample Pictures",
1911 .attributes
= FILE_ATTRIBUTE_READONLY
,
1912 .flags
= KFDF_PRECREATE
,
1915 .id
= &FOLDERID_SamplePlaylists
,
1916 .type
= CSIDL_Type_AllUsers
,
1917 .category
= KF_CATEGORY_COMMON
,
1918 .name
= L
"SamplePlaylists",
1919 .parent
= &FOLDERID_PublicMusic
,
1920 .path
= L
"Sample Playlists",
1921 .attributes
= FILE_ATTRIBUTE_READONLY
,
1922 .flags
= KFDF_PRECREATE
,
1925 .id
= &FOLDERID_SampleVideos
,
1926 .type
= CSIDL_Type_AllUsers
,
1927 .category
= KF_CATEGORY_COMMON
,
1928 .name
= L
"SampleVideos",
1929 .parent
= &FOLDERID_PublicVideos
,
1930 .path
= L
"Sample Videos",
1931 .attributes
= FILE_ATTRIBUTE_READONLY
,
1932 .flags
= KFDF_PRECREATE
,
1934 { /* 0x62 - CSIDL_SAVED_GAMES */
1935 .id
= &FOLDERID_SavedGames
,
1936 .type
= CSIDL_Type_User
,
1937 .category
= KF_CATEGORY_PERUSER
,
1938 .name
= L
"SavedGames",
1939 .parent
= &FOLDERID_Profile
,
1940 .path
= L
"Saved Games",
1941 .parsing
= L
"::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}",
1942 .attributes
= FILE_ATTRIBUTE_READONLY
,
1943 .flags
= KFDF_ROAMABLE
| KFDF_PRECREATE
| KFDF_PUBLISHEXPANDEDPATH
,
1945 { /* 0x63 - CSIDL_SEARCHES */
1946 .id
= &FOLDERID_SavedSearches
,
1947 .type
= CSIDL_Type_User
,
1948 .category
= KF_CATEGORY_PERUSER
,
1949 .name
= L
"Searches",
1950 .parent
= &FOLDERID_Profile
,
1951 .path
= L
"Searches",
1952 .parsing
= L
"::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{7d1d3a04-debb-4115-95cf-2f29da2920da}",
1953 .attributes
= FILE_ATTRIBUTE_READONLY
,
1954 .flags
= KFDF_PRECREATE
| KFDF_PUBLISHEXPANDEDPATH
,
1957 .id
= &FOLDERID_SEARCH_CSC
,
1958 .type
= CSIDL_Type_Disallowed
,
1959 .category
= KF_CATEGORY_VIRTUAL
,
1960 .name
= L
"CSCFolder",
1961 .parsing
= L
"shell:::{BD7A2E7B-21CB-41b2-A086-B309680C6B7E}\\*",
1964 .id
= &FOLDERID_SEARCH_MAPI
,
1965 .type
= CSIDL_Type_Disallowed
,
1966 .category
= KF_CATEGORY_VIRTUAL
,
1967 .name
= L
"MAPIFolder",
1968 .parsing
= L
"shell:::{89D83576-6BD1-4C86-9454-BEB04E94C819}\\*",
1971 .id
= &FOLDERID_SearchHome
,
1972 .type
= CSIDL_Type_Disallowed
,
1973 .category
= KF_CATEGORY_VIRTUAL
,
1974 .name
= L
"SearchHomeFolder",
1975 .parsing
= L
"::{9343812e-1c37-4a49-a12e-4b2d810d956b}",
1978 .id
= &FOLDERID_SidebarDefaultParts
,
1979 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1980 .category
= KF_CATEGORY_COMMON
,
1981 .name
= L
"Default Gadgets",
1982 .parent
= &FOLDERID_ProgramFiles
,
1983 .path
= L
"Windows Sidebar\\Gadgets",
1986 .id
= &FOLDERID_SidebarParts
,
1987 .type
= CSIDL_Type_Disallowed
, /* FIXME */
1988 .category
= KF_CATEGORY_PERUSER
,
1990 .parent
= &FOLDERID_LocalAppData
,
1991 .path
= L
"Microsoft\\Windows Sidebar\\Gadgets",
1994 .id
= &FOLDERID_SyncManagerFolder
,
1995 .type
= CSIDL_Type_Disallowed
,
1996 .category
= KF_CATEGORY_VIRTUAL
,
1997 .name
= L
"SyncCenterFolder",
1998 .parsing
= L
"::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}",
2001 .id
= &FOLDERID_SyncResultsFolder
,
2002 .type
= CSIDL_Type_Disallowed
,
2003 .category
= KF_CATEGORY_VIRTUAL
,
2004 .name
= L
"SyncResultsFolder",
2005 .parsing
= L
"::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{BC48B32F-5910-47F5-8570-5074A8A5636A},",
2008 .id
= &FOLDERID_SyncSetupFolder
,
2009 .type
= CSIDL_Type_Disallowed
,
2010 .category
= KF_CATEGORY_VIRTUAL
,
2011 .name
= L
"SyncSetupFolder",
2012 .parsing
= L
"::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{F1390A9A-A3F4-4E5D-9C5F-98F3BD8D935C},",
2015 .id
= &FOLDERID_UserPinned
,
2016 .type
= CSIDL_Type_Disallowed
, /* FIXME */
2017 .category
= KF_CATEGORY_PERUSER
,
2018 .name
= L
"User Pinned",
2019 .parent
= &FOLDERID_QuickLaunch
,
2020 .path
= L
"User Pinned",
2021 .attributes
= FILE_ATTRIBUTE_HIDDEN
,
2022 .flags
= KFDF_PRECREATE
,
2025 .id
= &FOLDERID_UserProfiles
,
2026 .type
= CSIDL_Type_CurrVer
,
2028 .def_path
= L
"Users",
2029 .category
= KF_CATEGORY_FIXED
,
2030 .name
= L
"UserProfiles",
2031 .attributes
= FILE_ATTRIBUTE_READONLY
,
2032 .flags
= KFDF_PRECREATE
,
2035 .id
= &FOLDERID_UserProgramFiles
,
2036 .type
= CSIDL_Type_Disallowed
, /* FIXME */
2037 .category
= KF_CATEGORY_PERUSER
,
2038 .name
= L
"UserProgramFiles",
2039 .parent
= &FOLDERID_LocalAppData
,
2040 .path
= L
"Programs",
2043 .id
= &FOLDERID_UserProgramFilesCommon
,
2044 .type
= CSIDL_Type_Disallowed
, /* FIXME */
2045 .category
= KF_CATEGORY_PERUSER
,
2046 .name
= L
"UserProgramFilesCommon",
2047 .parent
= &FOLDERID_UserProgramFiles
,
2051 .id
= &FOLDERID_UsersFiles
,
2052 .type
= CSIDL_Type_Disallowed
,
2053 .category
= KF_CATEGORY_VIRTUAL
,
2054 .name
= L
"UsersFilesFolder",
2055 .parsing
= L
"::{59031a47-3f72-44a7-89c5-5595fe6b30ee}",
2058 .id
= &FOLDERID_UsersLibraries
,
2059 .type
= CSIDL_Type_Disallowed
,
2060 .category
= KF_CATEGORY_VIRTUAL
,
2061 .name
= L
"UsersLibrariesFolder",
2062 .parsing
= L
"::{031E4825-7B94-4dc3-B131-E946B44C8DD5}",
2065 .id
= &FOLDERID_VideosLibrary
,
2066 .type
= CSIDL_Type_Disallowed
, /* FIXME */
2067 .category
= KF_CATEGORY_PERUSER
,
2068 .name
= L
"VideosLibrary",
2069 .path
= L
"Videos.library-ms",
2070 .parsing
= L
"::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{491E922F-5643-4af4-A7EB-4E7A138D8174}",
2074 static int csidl_from_id( const KNOWNFOLDERID
*id
)
2077 for (i
= 0; i
< ARRAY_SIZE(CSIDL_Data
); i
++)
2078 if (IsEqualGUID( CSIDL_Data
[i
].id
, id
)) return i
;
2082 static HRESULT
_SHExpandEnvironmentStrings(LPCWSTR szSrc
, LPWSTR szDest
);
2084 /* Gets the value named value from the registry key
2085 * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
2086 * (or from rootKey\userPrefix\... if userPrefix is not NULL) into path, which
2087 * is assumed to be MAX_PATH WCHARs in length.
2088 * If it exists, expands the value and writes the expanded value to
2089 * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
2090 * Returns successful error code if the value was retrieved from the registry,
2091 * and a failure otherwise.
2093 static HRESULT
_SHGetUserShellFolderPath(HKEY rootKey
, LPCWSTR userPrefix
,
2094 LPCWSTR value
, LPWSTR path
)
2097 WCHAR shellFolderPath
[MAX_PATH
], userShellFolderPath
[MAX_PATH
];
2098 LPCWSTR pShellFolderPath
, pUserShellFolderPath
;
2099 HKEY userShellFolderKey
, shellFolderKey
;
2100 DWORD dwType
, dwPathLen
;
2102 TRACE("%p,%s,%s,%p\n",rootKey
, debugstr_w(userPrefix
), debugstr_w(value
),
2107 lstrcpyW(shellFolderPath
, userPrefix
);
2108 PathAddBackslashW(shellFolderPath
);
2109 lstrcatW(shellFolderPath
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
2110 pShellFolderPath
= shellFolderPath
;
2111 lstrcpyW(userShellFolderPath
, userPrefix
);
2112 PathAddBackslashW(userShellFolderPath
);
2113 lstrcatW(userShellFolderPath
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders");
2114 pUserShellFolderPath
= userShellFolderPath
;
2118 pUserShellFolderPath
= L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
2119 pShellFolderPath
= L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
2122 if (RegCreateKeyW(rootKey
, pShellFolderPath
, &shellFolderKey
))
2124 TRACE("Failed to create %s\n", debugstr_w(pShellFolderPath
));
2127 if (RegCreateKeyW(rootKey
, pUserShellFolderPath
, &userShellFolderKey
))
2129 TRACE("Failed to create %s\n",
2130 debugstr_w(pUserShellFolderPath
));
2131 RegCloseKey(shellFolderKey
);
2135 dwPathLen
= MAX_PATH
* sizeof(WCHAR
);
2136 if (!RegQueryValueExW(userShellFolderKey
, value
, NULL
, &dwType
,
2137 (LPBYTE
)path
, &dwPathLen
) && (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
))
2141 path
[dwPathLen
/ sizeof(WCHAR
)] = '\0';
2142 if (dwType
== REG_EXPAND_SZ
&& path
[0] == '%')
2144 WCHAR szTemp
[MAX_PATH
];
2146 _SHExpandEnvironmentStrings(path
, szTemp
);
2147 lstrcpynW(path
, szTemp
, MAX_PATH
);
2149 ret
= RegSetValueExW(shellFolderKey
, value
, 0, REG_SZ
, (LPBYTE
)path
,
2150 (lstrlenW(path
) + 1) * sizeof(WCHAR
));
2151 if (ret
!= ERROR_SUCCESS
)
2152 hr
= HRESULT_FROM_WIN32(ret
);
2158 RegCloseKey(shellFolderKey
);
2159 RegCloseKey(userShellFolderKey
);
2160 TRACE("returning 0x%08x\n", hr
);
2164 static void append_relative_path(BYTE folder
, WCHAR
*pszPath
)
2166 if (CSIDL_Data
[folder
].path
)
2168 PathAddBackslashW(pszPath
);
2169 lstrcatW(pszPath
, CSIDL_Data
[folder
].path
);
2171 else if (CSIDL_Data
[folder
].def_path
)
2173 PathAddBackslashW(pszPath
);
2174 lstrcatW(pszPath
, CSIDL_Data
[folder
].def_path
);
2178 /* Gets a 'semi-expanded' default value of the CSIDL with index folder into
2179 * pszPath, based on the entries in CSIDL_Data. By semi-expanded, I mean:
2180 * - Depending on the entry's type, the path may begin with an (unexpanded)
2181 * environment variable name. The caller is responsible for expanding
2182 * environment strings if so desired.
2183 * The types that are prepended with environment variables are:
2184 * CSIDL_Type_User: %USERPROFILE%
2185 * CSIDL_Type_AllUsers: %ALLUSERSPROFILE%
2186 * CSIDL_Type_CurrVer: %SystemDrive%
2187 * (Others might make sense too, but as yet are unneeded.)
2189 static HRESULT
_SHGetDefaultValue(BYTE folder
, LPWSTR pszPath
)
2193 TRACE("0x%02x,%p\n", folder
, pszPath
);
2195 if (folder
>= ARRAY_SIZE(CSIDL_Data
))
2196 return E_INVALIDARG
;
2199 return E_INVALIDARG
;
2207 case CSIDL_PROGRAM_FILES
:
2208 case CSIDL_PROGRAM_FILESX86
:
2209 IsWow64Process( GetCurrentProcess(), &is_wow64
);
2210 folder
= is_wow64
? CSIDL_PROGRAM_FILESX86
: CSIDL_PROGRAM_FILES
;
2212 case CSIDL_PROGRAM_FILES_COMMON
:
2213 case CSIDL_PROGRAM_FILES_COMMONX86
:
2214 IsWow64Process( GetCurrentProcess(), &is_wow64
);
2215 folder
= is_wow64
? CSIDL_PROGRAM_FILES_COMMONX86
: CSIDL_PROGRAM_FILES_COMMON
;
2220 if (!CSIDL_Data
[folder
].parent
)
2222 /* hit the root, sub in env var */
2223 switch (CSIDL_Data
[folder
].type
)
2225 case CSIDL_Type_User
:
2226 lstrcpyW(pszPath
, L
"%USERPROFILE%");
2228 case CSIDL_Type_AllUsers
:
2229 lstrcpyW(pszPath
, L
"%PUBLIC%");
2231 case CSIDL_Type_ProgramData
:
2232 lstrcpyW(pszPath
, L
"%ProgramData%");
2234 case CSIDL_Type_CurrVer
:
2235 lstrcpyW(pszPath
, L
"%SystemDrive%");
2238 ; /* no corresponding env. var, do nothing */
2242 /* prepend with parent */
2243 hr
= _SHGetDefaultValue(csidl_from_id(CSIDL_Data
[folder
].parent
), pszPath
);
2247 append_relative_path(folder
, pszPath
);
2249 TRACE("returning 0x%08x\n", hr
);
2253 /* Gets the (unexpanded) value of the folder with index folder into pszPath.
2254 * The folder's type is assumed to be CSIDL_Type_CurrVer. Its default value
2255 * can be overridden in the HKLM\\Software\\Microsoft\\Windows\\CurrentVersion key.
2256 * If dwFlags has SHGFP_TYPE_DEFAULT set or if the value isn't overridden in
2257 * the registry, uses _SHGetDefaultValue to get the value.
2259 static HRESULT
_SHGetCurrentVersionPath(DWORD dwFlags
, BYTE folder
,
2264 TRACE("0x%08x,0x%02x,%p\n", dwFlags
, folder
, pszPath
);
2266 if (folder
>= ARRAY_SIZE(CSIDL_Data
))
2267 return E_INVALIDARG
;
2268 if (CSIDL_Data
[folder
].type
!= CSIDL_Type_CurrVer
)
2269 return E_INVALIDARG
;
2271 return E_INVALIDARG
;
2273 if (dwFlags
& SHGFP_TYPE_DEFAULT
)
2274 hr
= _SHGetDefaultValue(folder
, pszPath
);
2279 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows\\CurrentVersion", &hKey
))
2283 DWORD dwType
, dwPathLen
= MAX_PATH
* sizeof(WCHAR
);
2285 if (RegQueryValueExW(hKey
, CSIDL_Data
[folder
].value
, NULL
,
2286 &dwType
, (LPBYTE
)pszPath
, &dwPathLen
) ||
2287 (dwType
!= REG_SZ
&& dwType
!= REG_EXPAND_SZ
))
2289 hr
= _SHGetDefaultValue(folder
, pszPath
);
2290 dwType
= REG_EXPAND_SZ
;
2293 case CSIDL_PROGRAM_FILESX86
:
2294 case CSIDL_PROGRAM_FILES_COMMONX86
:
2295 /* these two should never be set on 32-bit setups */
2299 IsWow64Process( GetCurrentProcess(), &is_wow64
);
2300 if (!is_wow64
) break;
2304 RegSetValueExW(hKey
, CSIDL_Data
[folder
].value
, 0, dwType
,
2305 (LPBYTE
)pszPath
, (lstrlenW(pszPath
)+1)*sizeof(WCHAR
));
2310 pszPath
[dwPathLen
/ sizeof(WCHAR
)] = '\0';
2316 TRACE("returning 0x%08x (output path is %s)\n", hr
, debugstr_w(pszPath
));
2320 static LPWSTR
_GetUserSidStringFromToken(HANDLE Token
)
2322 char InfoBuffer
[64];
2323 PTOKEN_USER UserInfo
;
2327 UserInfo
= (PTOKEN_USER
) InfoBuffer
;
2328 if (! GetTokenInformation(Token
, TokenUser
, InfoBuffer
, sizeof(InfoBuffer
),
2331 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
2333 UserInfo
= heap_alloc(InfoSize
);
2334 if (UserInfo
== NULL
)
2336 if (! GetTokenInformation(Token
, TokenUser
, UserInfo
, InfoSize
,
2339 heap_free(UserInfo
);
2344 if (! ConvertSidToStringSidW(UserInfo
->User
.Sid
, &SidStr
))
2347 if (UserInfo
!= (PTOKEN_USER
) InfoBuffer
)
2348 heap_free(UserInfo
);
2353 /* Gets the user's path (unexpanded) for the CSIDL with index folder:
2354 * If SHGFP_TYPE_DEFAULT is set, calls _SHGetDefaultValue for it. Otherwise
2355 * calls _SHGetUserShellFolderPath for it. Where it looks depends on hToken:
2356 * - if hToken is -1, looks in HKEY_USERS\.Default
2357 * - otherwise looks first in HKEY_CURRENT_USER, followed by HKEY_LOCAL_MACHINE
2358 * if HKEY_CURRENT_USER doesn't contain any entries. If both fail, finally
2359 * calls _SHGetDefaultValue for it.
2361 static HRESULT
_SHGetUserProfilePath(HANDLE hToken
, DWORD dwFlags
, BYTE folder
,
2364 const WCHAR
*szValueName
;
2368 TRACE("%p,0x%08x,0x%02x,%p\n", hToken
, dwFlags
, folder
, pszPath
);
2370 if (folder
>= ARRAY_SIZE(CSIDL_Data
))
2371 return E_INVALIDARG
;
2372 if (CSIDL_Data
[folder
].type
!= CSIDL_Type_User
)
2373 return E_INVALIDARG
;
2375 return E_INVALIDARG
;
2377 if (dwFlags
& SHGFP_TYPE_DEFAULT
)
2379 if (hToken
!= NULL
&& hToken
!= (HANDLE
)-1)
2381 FIXME("unsupported for user other than current or default\n");
2384 hr
= _SHGetDefaultValue(folder
, pszPath
);
2388 static const WCHAR DefaultW
[] = L
".Default";
2389 LPCWSTR userPrefix
= NULL
;
2392 if (hToken
== (HANDLE
)-1)
2394 hRootKey
= HKEY_USERS
;
2395 userPrefix
= DefaultW
;
2397 else if (hToken
== NULL
)
2398 hRootKey
= HKEY_CURRENT_USER
;
2401 hRootKey
= HKEY_USERS
;
2402 userPrefix
= _GetUserSidStringFromToken(hToken
);
2403 if (userPrefix
== NULL
)
2410 /* For CSIDL_Type_User we also use the GUID if no szValueName is provided */
2411 szValueName
= CSIDL_Data
[folder
].value
;
2414 StringFromGUID2( CSIDL_Data
[folder
].id
, buffer
, 39 );
2415 szValueName
= &buffer
[0];
2418 hr
= _SHGetUserShellFolderPath(hRootKey
, userPrefix
, szValueName
, pszPath
);
2419 if (FAILED(hr
) && hRootKey
!= HKEY_LOCAL_MACHINE
)
2420 hr
= _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE
, NULL
, szValueName
, pszPath
);
2422 hr
= _SHGetDefaultValue(folder
, pszPath
);
2423 if (userPrefix
!= NULL
&& userPrefix
!= DefaultW
)
2424 LocalFree((HLOCAL
) userPrefix
);
2427 TRACE("returning 0x%08x (output path is %s)\n", hr
, debugstr_w(pszPath
));
2431 /* Gets the (unexpanded) path for the CSIDL with index folder. If dwFlags has
2432 * SHGFP_TYPE_DEFAULT set, calls _SHGetDefaultValue. Otherwise calls
2433 * _SHGetUserShellFolderPath for it, looking only in HKEY_LOCAL_MACHINE.
2434 * If this fails, falls back to _SHGetDefaultValue.
2436 static HRESULT
_SHGetAllUsersProfilePath(DWORD dwFlags
, BYTE folder
,
2441 TRACE("0x%08x,0x%02x,%p\n", dwFlags
, folder
, pszPath
);
2443 if (folder
>= ARRAY_SIZE(CSIDL_Data
))
2444 return E_INVALIDARG
;
2445 if (CSIDL_Data
[folder
].type
!= CSIDL_Type_AllUsers
&& CSIDL_Data
[folder
].type
!= CSIDL_Type_ProgramData
)
2446 return E_INVALIDARG
;
2448 return E_INVALIDARG
;
2450 if (dwFlags
& SHGFP_TYPE_DEFAULT
)
2451 hr
= _SHGetDefaultValue(folder
, pszPath
);
2454 hr
= _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE
, NULL
,
2455 CSIDL_Data
[folder
].value
, pszPath
);
2457 hr
= _SHGetDefaultValue(folder
, pszPath
);
2459 TRACE("returning 0x%08x (output path is %s)\n", hr
, debugstr_w(pszPath
));
2463 static HRESULT
_SHOpenProfilesKey(PHKEY pKey
)
2468 lRet
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList", 0, NULL
, 0,
2469 KEY_ALL_ACCESS
, NULL
, pKey
, &disp
);
2470 return HRESULT_FROM_WIN32(lRet
);
2473 /* Reads the value named szValueName from the key profilesKey (assumed to be
2474 * opened by _SHOpenProfilesKey) into szValue, which is assumed to be MAX_PATH
2475 * WCHARs in length. If it doesn't exist, returns szDefault (and saves
2476 * szDefault to the registry).
2478 static HRESULT
_SHGetProfilesValue(HKEY profilesKey
, LPCWSTR szValueName
,
2479 LPWSTR szValue
, LPCWSTR szDefault
)
2482 DWORD type
, dwPathLen
= MAX_PATH
* sizeof(WCHAR
);
2485 TRACE("%p,%s,%p,%s\n", profilesKey
, debugstr_w(szValueName
), szValue
,
2486 debugstr_w(szDefault
));
2487 lRet
= RegQueryValueExW(profilesKey
, szValueName
, NULL
, &type
,
2488 (LPBYTE
)szValue
, &dwPathLen
);
2489 if (!lRet
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) && dwPathLen
2492 dwPathLen
/= sizeof(WCHAR
);
2493 szValue
[dwPathLen
] = '\0';
2498 /* Missing or invalid value, set a default */
2499 lstrcpynW(szValue
, szDefault
, MAX_PATH
);
2500 TRACE("Setting missing value %s to %s\n", debugstr_w(szValueName
),
2501 debugstr_w(szValue
));
2502 lRet
= RegSetValueExW(profilesKey
, szValueName
, 0, REG_EXPAND_SZ
,
2504 (lstrlenW(szValue
) + 1) * sizeof(WCHAR
));
2506 hr
= HRESULT_FROM_WIN32(lRet
);
2510 TRACE("returning 0x%08x (output value is %s)\n", hr
, debugstr_w(szValue
));
2514 /* Attempts to expand environment variables from szSrc into szDest, which is
2515 * assumed to be MAX_PATH characters in length. Before referring to the
2516 * environment, handles a few variables directly, because the environment
2517 * variables may not be set when this is called (as during Wine's installation
2518 * when default values are being written to the registry).
2519 * The directly handled environment variables, and their source, are:
2520 * - ALLUSERSPROFILE, USERPROFILE: reads from the registry
2521 * - SystemDrive: uses GetSystemDirectoryW and uses the drive portion of its
2523 * If one of the directly handled environment variables is expanded, only
2524 * expands a single variable, and only in the beginning of szSrc.
2526 static HRESULT
_SHExpandEnvironmentStrings(LPCWSTR szSrc
, LPWSTR szDest
)
2529 WCHAR szTemp
[MAX_PATH
], szProfilesPrefix
[MAX_PATH
] = { 0 };
2532 TRACE("%s, %p\n", debugstr_w(szSrc
), szDest
);
2534 if (!szSrc
|| !szDest
) return E_INVALIDARG
;
2536 /* short-circuit if there's nothing to expand */
2537 if (szSrc
[0] != '%')
2539 lstrcpyW(szDest
, szSrc
);
2543 /* Get the profile prefix, we'll probably be needing it */
2544 hr
= _SHOpenProfilesKey(&key
);
2547 WCHAR def_val
[MAX_PATH
];
2549 /* get the system drive */
2550 GetSystemDirectoryW(def_val
, MAX_PATH
);
2551 lstrcpyW( def_val
+ 3, L
"users" );
2553 hr
= _SHGetProfilesValue(key
, L
"ProfilesDirectory", szProfilesPrefix
, def_val
);
2557 lstrcpyW(szTemp
, szSrc
);
2558 while (SUCCEEDED(hr
) && szTemp
[0] == '%')
2560 if (!wcsnicmp(szTemp
, L
"%ALLUSERSPROFILE%", lstrlenW(L
"%ALLUSERSPROFILE%")))
2562 WCHAR szAllUsers
[MAX_PATH
], def_val
[MAX_PATH
];
2564 GetSystemDirectoryW(def_val
, MAX_PATH
);
2565 lstrcpyW( def_val
+ 3, L
"users\\Public" );
2567 hr
= _SHGetProfilesValue(key
, L
"Public", szAllUsers
, def_val
);
2568 PathAppendW(szDest
, szAllUsers
);
2569 PathAppendW(szDest
, szTemp
+ lstrlenW(L
"%ALLUSERSPROFILE%"));
2571 else if (!wcsnicmp(szTemp
, L
"%PUBLIC%", lstrlenW(L
"%PUBLIC%")))
2573 WCHAR szAllUsers
[MAX_PATH
], def_val
[MAX_PATH
];
2575 GetSystemDirectoryW(def_val
, MAX_PATH
);
2576 lstrcpyW( def_val
+ 3, L
"users\\Public" );
2578 hr
= _SHGetProfilesValue(key
, L
"Public", szAllUsers
, def_val
);
2579 PathAppendW(szDest
, szAllUsers
);
2580 PathAppendW(szDest
, szTemp
+ lstrlenW(L
"%PUBLIC%"));
2582 else if (!wcsnicmp(szTemp
, L
"%ProgramData%", lstrlenW(L
"%ProgramData%")))
2584 WCHAR szProgramData
[MAX_PATH
], def_val
[MAX_PATH
];
2585 HKEY shellFolderKey
;
2586 DWORD dwType
, dwPathLen
= sizeof(def_val
);
2587 BOOL in_registry
= FALSE
;
2589 if (!RegCreateKeyW(HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", &shellFolderKey
))
2591 if (!RegQueryValueExW(shellFolderKey
, L
"Common AppData", NULL
, &dwType
,
2592 (LPBYTE
)def_val
, &dwPathLen
) && (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
))
2595 RegCloseKey(shellFolderKey
);
2600 GetSystemDirectoryW(def_val
, MAX_PATH
);
2601 lstrcpyW( def_val
+ 3, L
"ProgramData" );
2604 hr
= _SHGetProfilesValue(key
, L
"ProgramData", szProgramData
, def_val
);
2605 PathAppendW(szDest
, szProgramData
);
2606 PathAppendW(szDest
, szTemp
+ lstrlenW(L
"%ProgramData%"));
2608 else if (!wcsnicmp(szTemp
, L
"%USERPROFILE%", lstrlenW(L
"%USERPROFILE%")))
2610 WCHAR userName
[MAX_PATH
];
2611 DWORD userLen
= MAX_PATH
;
2613 lstrcpyW(szDest
, szProfilesPrefix
);
2614 GetUserNameW(userName
, &userLen
);
2615 PathAppendW(szDest
, userName
);
2616 PathAppendW(szDest
, szTemp
+ lstrlenW(L
"%USERPROFILE%"));
2618 else if (!wcsnicmp(szTemp
, L
"%SystemDrive%", lstrlenW(L
"%SystemDrive%")))
2620 GetSystemDirectoryW(szDest
, MAX_PATH
);
2621 lstrcpyW(szDest
+ 3, szTemp
+ lstrlenW(L
"%SystemDrive%") + 1);
2625 DWORD ret
= ExpandEnvironmentStringsW(szTemp
, szDest
, MAX_PATH
);
2628 hr
= E_NOT_SUFFICIENT_BUFFER
;
2630 hr
= HRESULT_FROM_WIN32(GetLastError());
2631 else if (!wcscmp( szTemp
, szDest
)) break; /* nothing expanded */
2633 if (SUCCEEDED(hr
)) lstrcpyW(szTemp
, szDest
);
2638 TRACE("returning 0x%08x (input was %s, output is %s)\n", hr
,
2639 debugstr_w(szSrc
), debugstr_w(szDest
));
2643 static char *xdg_config
;
2644 static DWORD xdg_config_len
;
2646 static BOOL WINAPI
init_xdg_dirs( INIT_ONCE
*once
, void *param
, void **context
)
2648 const WCHAR
*var
, *fmt
= L
"\\??\\unix%s/user-dirs.dirs";
2654 if (!(var
= _wgetenv( L
"XDG_CONFIG_HOME" )) || var
[0] != '/')
2656 if (!(var
= _wgetenv( L
"WINEHOMEDIR" ))) return TRUE
;
2657 fmt
= L
"%s/.config/user-dirs.dirs";
2659 len
= lstrlenW(var
) + lstrlenW(fmt
);
2660 name
= heap_alloc( len
* sizeof(WCHAR
) );
2661 swprintf( name
, len
, fmt
, var
);
2662 name
[1] = '\\'; /* change \??\ to \\?\ */
2663 for (ptr
= name
; *ptr
; ptr
++) if (*ptr
== '/') *ptr
= '\\';
2665 file
= CreateFileW( name
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
2667 if (file
!= INVALID_HANDLE_VALUE
)
2669 len
= GetFileSize( file
, NULL
);
2670 if (!(xdg_config
= heap_alloc( len
+ 1 ))) return TRUE
;
2671 if (!ReadFile( file
, xdg_config
, len
, &xdg_config_len
, NULL
))
2673 heap_free( xdg_config
);
2678 for (p
= xdg_config
; p
< xdg_config
+ xdg_config_len
; p
++) if (*p
== '\n') *p
= 0;
2679 *p
= 0; /* append null to simplify string parsing */
2681 CloseHandle( file
);
2686 static char *get_xdg_path( const char *var
)
2688 static INIT_ONCE once
;
2689 char *p
, *ret
= NULL
;
2692 InitOnceExecuteOnce( &once
, init_xdg_dirs
, NULL
, NULL
);
2693 if (!xdg_config
) return NULL
;
2695 for (p
= xdg_config
; p
< xdg_config
+ xdg_config_len
; p
+= strlen(p
) + 1)
2697 while (*p
== ' ' || *p
== '\t') p
++;
2698 if (strncmp( p
, var
, strlen(var
) )) continue;
2700 while (*p
== ' ' || *p
== '\t') p
++;
2701 if (*p
!= '=') continue;
2703 while (*p
== ' ' || *p
== '\t') p
++;
2704 if (*p
!= '"') continue;
2706 if (*p
!= '/' && strncmp( p
, "$HOME/", 6 )) continue;
2708 if (!(ret
= heap_alloc( strlen(p
) + 1 ))) break;
2709 for (i
= 0; *p
&& *p
!= '"'; i
++, p
++)
2711 if (*p
== '\\' && p
[1]) p
++;
2725 static BOOL
link_folder( HANDLE mgr
, const UNICODE_STRING
*path
, const char *link
)
2727 struct mountmgr_shell_folder
*ioctl
;
2728 DWORD len
= sizeof(*ioctl
) + path
->Length
+ strlen(link
) + 1;
2731 if (!(ioctl
= heap_alloc( len
))) return FALSE
;
2732 ioctl
->create_backup
= FALSE
;
2733 ioctl
->folder_offset
= sizeof(*ioctl
);
2734 ioctl
->folder_size
= path
->Length
;
2735 memcpy( (char *)ioctl
+ ioctl
->folder_offset
, path
->Buffer
, ioctl
->folder_size
);
2736 ioctl
->symlink_offset
= ioctl
->folder_offset
+ ioctl
->folder_size
;
2737 strcpy( (char *)ioctl
+ ioctl
->symlink_offset
, link
);
2739 ret
= DeviceIoControl( mgr
, IOCTL_MOUNTMGR_DEFINE_SHELL_FOLDER
, ioctl
, len
, NULL
, 0, NULL
, NULL
);
2744 /******************************************************************************
2747 * Sets up a symbolic link for one of the 'My Whatever' shell folders to point
2748 * into the corresponding XDG directory.
2750 static void create_link( const WCHAR
*path
, const char *xdg_name
, const char *default_name
)
2752 UNICODE_STRING nt_name
;
2753 char *target
= NULL
;
2756 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
| GENERIC_WRITE
,
2757 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2758 0, 0 )) == INVALID_HANDLE_VALUE
)
2760 FIXME( "failed to connect to mount manager\n" );
2764 nt_name
.Buffer
= NULL
;
2765 if (!RtlDosPathNameToNtPathName_U( path
, &nt_name
, NULL
, NULL
)) goto done
;
2767 if ((target
= get_xdg_path( xdg_name
)))
2769 if (link_folder( mgr
, &nt_name
, target
)) goto done
;
2771 if (link_folder( mgr
, &nt_name
, default_name
)) goto done
;
2773 /* fall back to HOME */
2774 link_folder( mgr
, &nt_name
, "$HOME" );
2777 RtlFreeUnicodeString( &nt_name
);
2778 heap_free( target
);
2782 /******************************************************************************
2783 * _SHCreateSymbolicLink [Internal]
2785 * Sets up a symbolic link for one of the special shell folders to point into
2786 * the users home directory.
2789 * nFolder [I] CSIDL identifying the folder.
2791 static void _SHCreateSymbolicLink(int nFolder
, const WCHAR
*path
)
2793 DWORD folder
= nFolder
& CSIDL_FOLDER_MASK
;
2796 case CSIDL_PERSONAL
:
2797 create_link( path
, "XDG_DOCUMENTS_DIR", "$HOME/Documents" );
2799 case CSIDL_DESKTOPDIRECTORY
:
2800 create_link( path
, "XDG_DESKTOP_DIR", "$HOME/Desktop" );
2802 case CSIDL_MYPICTURES
:
2803 create_link( path
, "XDG_PICTURES_DIR", "$HOME/Pictures" );
2806 create_link( path
, "XDG_VIDEOS_DIR", "$HOME/Movies" );
2809 create_link( path
, "XDG_MUSIC_DIR", "$HOME/Music" );
2811 case CSIDL_DOWNLOADS
:
2812 create_link( path
, "XDG_DOWNLOAD_DIR", "$HOME/Downloads" );
2814 case CSIDL_TEMPLATES
:
2815 create_link( path
, "XDG_TEMPLATES_DIR", "$HOME/Templates" );
2820 /******************************************************************************
2821 * SHGetFolderPathW [SHELL32.@]
2823 * Convert nFolder to path.
2827 * Failure: standard HRESULT error codes.
2830 * Most values can be overridden in either
2831 * HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
2832 * or in the same location in HKLM.
2833 * The "Shell Folders" registry key was used in NT4 and earlier systems.
2834 * Beginning with Windows 2000, the "User Shell Folders" key is used, so
2835 * changes made to it are made to the former key too. This synchronization is
2836 * done on-demand: not until someone requests the value of one of these paths
2837 * (by calling one of the SHGet functions) is the value synchronized.
2838 * Furthermore, the HKCU paths take precedence over the HKLM paths.
2840 HRESULT WINAPI
SHGetFolderPathW(
2841 HWND hwndOwner
, /* [I] owner window */
2842 int nFolder
, /* [I] CSIDL identifying the folder */
2843 HANDLE hToken
, /* [I] access token */
2844 DWORD dwFlags
, /* [I] which path to return */
2845 LPWSTR pszPath
) /* [O] converted path */
2847 HRESULT hr
= SHGetFolderPathAndSubDirW(hwndOwner
, nFolder
, hToken
, dwFlags
, NULL
, pszPath
);
2848 if(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
) == hr
)
2849 hr
= HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
2853 HRESULT WINAPI
SHGetFolderPathAndSubDirA(
2854 HWND hwndOwner
, /* [I] owner window */
2855 int nFolder
, /* [I] CSIDL identifying the folder */
2856 HANDLE hToken
, /* [I] access token */
2857 DWORD dwFlags
, /* [I] which path to return */
2858 LPCSTR pszSubPath
, /* [I] sub directory of the specified folder */
2859 LPSTR pszPath
) /* [O] converted path */
2863 LPWSTR pszSubPathW
= NULL
;
2864 LPWSTR pszPathW
= NULL
;
2866 TRACE("%p,%#x,%p,%#x,%s,%p\n", hwndOwner
, nFolder
, hToken
, dwFlags
, debugstr_a(pszSubPath
), pszPath
);
2869 pszPathW
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
2871 hr
= HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY
);
2875 TRACE("%08x,%08x,%s\n",nFolder
, dwFlags
, debugstr_w(pszSubPathW
));
2877 /* SHGetFolderPathAndSubDirW does not distinguish if pszSubPath isn't
2878 * set (null), or an empty string.therefore call it without the parameter set
2879 * if pszSubPath is an empty string
2881 if (pszSubPath
&& pszSubPath
[0]) {
2882 length
= MultiByteToWideChar(CP_ACP
, 0, pszSubPath
, -1, NULL
, 0);
2883 pszSubPathW
= heap_alloc(length
* sizeof(WCHAR
));
2885 hr
= HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY
);
2888 MultiByteToWideChar(CP_ACP
, 0, pszSubPath
, -1, pszSubPathW
, length
);
2891 hr
= SHGetFolderPathAndSubDirW(hwndOwner
, nFolder
, hToken
, dwFlags
, pszSubPathW
, pszPathW
);
2893 if (SUCCEEDED(hr
) && pszPath
)
2894 WideCharToMultiByte(CP_ACP
, 0, pszPathW
, -1, pszPath
, MAX_PATH
, NULL
, NULL
);
2897 heap_free(pszPathW
);
2898 heap_free(pszSubPathW
);
2902 /*************************************************************************
2903 * SHGetFolderPathAndSubDirW [SHELL32.@]
2905 HRESULT WINAPI
SHGetFolderPathAndSubDirW(
2906 HWND hwndOwner
, /* [I] owner window */
2907 int nFolder
, /* [I] CSIDL identifying the folder */
2908 HANDLE hToken
, /* [I] access token */
2909 DWORD dwFlags
, /* [I] which path to return */
2910 LPCWSTR pszSubPath
,/* [I] sub directory of the specified folder */
2911 LPWSTR pszPath
) /* [O] converted path */
2914 WCHAR szBuildPath
[MAX_PATH
], szTemp
[MAX_PATH
];
2915 DWORD folder
= nFolder
& CSIDL_FOLDER_MASK
;
2919 TRACE("%p,%#x,%p,%#x,%s,%p\n", hwndOwner
, nFolder
, hToken
, dwFlags
, debugstr_w(pszSubPath
), pszPath
);
2921 /* Windows always NULL-terminates the resulting path regardless of success
2922 * or failure, so do so first
2927 if (folder
>= ARRAY_SIZE(CSIDL_Data
))
2928 return E_INVALIDARG
;
2929 if ((SHGFP_TYPE_CURRENT
!= dwFlags
) && (SHGFP_TYPE_DEFAULT
!= dwFlags
))
2930 return E_INVALIDARG
;
2932 type
= CSIDL_Data
[folder
].type
;
2935 case CSIDL_Type_Disallowed
:
2938 case CSIDL_Type_NonExistent
:
2941 case CSIDL_Type_WindowsPath
:
2942 GetWindowsDirectoryW(szTemp
, MAX_PATH
);
2943 append_relative_path(folder
, szTemp
);
2946 case CSIDL_Type_SystemPath
:
2947 GetSystemDirectoryW(szTemp
, MAX_PATH
);
2948 append_relative_path(folder
, szTemp
);
2951 case CSIDL_Type_SystemX86Path
:
2952 if (!GetSystemWow64DirectoryW(szTemp
, MAX_PATH
)) GetSystemDirectoryW(szTemp
, MAX_PATH
);
2953 append_relative_path(folder
, szTemp
);
2956 case CSIDL_Type_CurrVer
:
2957 hr
= _SHGetCurrentVersionPath(dwFlags
, folder
, szTemp
);
2959 case CSIDL_Type_User
:
2960 hr
= _SHGetUserProfilePath(hToken
, dwFlags
, folder
, szTemp
);
2962 case CSIDL_Type_AllUsers
:
2963 case CSIDL_Type_ProgramData
:
2964 hr
= _SHGetAllUsersProfilePath(dwFlags
, folder
, szTemp
);
2967 FIXME("bogus type %d, please fix\n", type
);
2972 /* Expand environment strings if necessary */
2974 hr
= _SHExpandEnvironmentStrings(szTemp
, szBuildPath
);
2976 lstrcpyW(szBuildPath
, szTemp
);
2978 if (FAILED(hr
)) goto end
;
2981 /* make sure the new path does not exceed the buffer length
2982 * and remember to backslash and terminate it */
2983 if(MAX_PATH
< (lstrlenW(szBuildPath
) + lstrlenW(pszSubPath
) + 2)) {
2984 hr
= HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE
);
2987 PathAppendW(szBuildPath
, pszSubPath
);
2988 PathRemoveBackslashW(szBuildPath
);
2990 /* Copy the path if it's available before we might return */
2991 if (SUCCEEDED(hr
) && pszPath
)
2992 lstrcpyW(pszPath
, szBuildPath
);
2994 /* if we don't care about existing directories we are ready */
2995 if(nFolder
& CSIDL_FLAG_DONT_VERIFY
) goto end
;
2997 if (PathFileExistsW(szBuildPath
)) goto end
;
2999 /* not existing but we are not allowed to create it. The return value
3000 * is verified against shell32 version 6.0.
3002 if (!(nFolder
& CSIDL_FLAG_CREATE
))
3004 hr
= HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
);
3008 /* create symbolic links rather than directories for specific
3009 * user shell folders */
3010 _SHCreateSymbolicLink(folder
, szBuildPath
);
3012 /* create directory/directories */
3013 ret
= SHCreateDirectoryExW(hwndOwner
, szBuildPath
, NULL
);
3014 if (ret
&& ret
!= ERROR_ALREADY_EXISTS
)
3016 ERR("Failed to create directory %s.\n", debugstr_w(szBuildPath
));
3021 TRACE("Created missing system directory %s\n", debugstr_w(szBuildPath
));
3023 TRACE("returning 0x%08x (final path is %s)\n", hr
, debugstr_w(szBuildPath
));
3027 /*************************************************************************
3028 * SHGetFolderPathA [SHELL32.@]
3030 * See SHGetFolderPathW.
3032 HRESULT WINAPI
SHGetFolderPathA(
3039 WCHAR szTemp
[MAX_PATH
];
3042 TRACE("%p,%d,%p,%#x,%p\n", hwndOwner
, nFolder
, hToken
, dwFlags
, pszPath
);
3046 hr
= SHGetFolderPathW(hwndOwner
, nFolder
, hToken
, dwFlags
, szTemp
);
3047 if (SUCCEEDED(hr
) && pszPath
)
3048 WideCharToMultiByte(CP_ACP
, 0, szTemp
, -1, pszPath
, MAX_PATH
, NULL
,
3054 /* For each folder in folders, if its value has not been set in the registry,
3055 * calls _SHGetUserProfilePath or _SHGetAllUsersProfilePath (depending on the
3056 * folder's type) to get the unexpanded value first.
3057 * Writes the unexpanded value to User Shell Folders, and queries it with
3058 * SHGetFolderPathW to force the creation of the directory if it doesn't
3059 * already exist. SHGetFolderPathW also returns the expanded value, which
3060 * this then writes to Shell Folders.
3062 static HRESULT
_SHRegisterFolders(HKEY hRootKey
, HANDLE hToken
,
3063 LPCWSTR szUserShellFolderPath
, LPCWSTR szShellFolderPath
, const UINT folders
[],
3066 const WCHAR
*szValueName
;
3069 WCHAR path
[MAX_PATH
];
3071 HKEY hUserKey
= NULL
, hKey
= NULL
;
3072 DWORD dwType
, dwPathLen
;
3075 TRACE("%p,%p,%s,%p,%u\n", hRootKey
, hToken
,
3076 debugstr_w(szUserShellFolderPath
), folders
, foldersLen
);
3078 ret
= RegCreateKeyW(hRootKey
, szUserShellFolderPath
, &hUserKey
);
3080 hr
= HRESULT_FROM_WIN32(ret
);
3083 ret
= RegCreateKeyW(hRootKey
, szShellFolderPath
, &hKey
);
3085 hr
= HRESULT_FROM_WIN32(ret
);
3087 for (i
= 0; SUCCEEDED(hr
) && i
< foldersLen
; i
++)
3089 dwPathLen
= MAX_PATH
* sizeof(WCHAR
);
3091 /* For CSIDL_Type_User we also use the GUID if no szValueName is provided */
3092 szValueName
= CSIDL_Data
[folders
[i
]].value
;
3093 if (!szValueName
&& CSIDL_Data
[folders
[i
]].type
== CSIDL_Type_User
)
3095 StringFromGUID2( CSIDL_Data
[folders
[i
]].id
, buffer
, 39 );
3096 szValueName
= &buffer
[0];
3099 if (RegQueryValueExW(hUserKey
, szValueName
, NULL
,
3100 &dwType
, (LPBYTE
)path
, &dwPathLen
) || (dwType
!= REG_SZ
&&
3101 dwType
!= REG_EXPAND_SZ
))
3104 if (CSIDL_Data
[folders
[i
]].type
== CSIDL_Type_User
)
3105 _SHGetUserProfilePath(hToken
, SHGFP_TYPE_DEFAULT
, folders
[i
],
3107 else if (CSIDL_Data
[folders
[i
]].type
== CSIDL_Type_AllUsers
||
3108 CSIDL_Data
[folders
[i
]].type
== CSIDL_Type_ProgramData
)
3109 _SHGetAllUsersProfilePath(SHGFP_TYPE_DEFAULT
, folders
[i
], path
);
3110 else if (CSIDL_Data
[folders
[i
]].type
== CSIDL_Type_WindowsPath
)
3112 GetWindowsDirectoryW(path
, MAX_PATH
);
3113 append_relative_path(folders
[i
], path
);
3119 ret
= RegSetValueExW(hUserKey
, szValueName
, 0, REG_EXPAND_SZ
,
3120 (LPBYTE
)path
, (lstrlenW(path
) + 1) * sizeof(WCHAR
));
3122 hr
= HRESULT_FROM_WIN32(ret
);
3125 hr
= SHGetFolderPathW(NULL
, folders
[i
] | CSIDL_FLAG_CREATE
,
3126 hToken
, SHGFP_TYPE_DEFAULT
, path
);
3127 ret
= RegSetValueExW(hKey
, szValueName
, 0, REG_SZ
,
3128 (LPBYTE
)path
, (lstrlenW(path
) + 1) * sizeof(WCHAR
));
3130 hr
= HRESULT_FROM_WIN32(ret
);
3136 /* create the default dir, which may be different from the path
3137 * stored in the registry. */
3138 SHGetFolderPathW(NULL
, folders
[i
] | CSIDL_FLAG_CREATE
,
3139 hToken
, SHGFP_TYPE_DEFAULT
, path
);
3143 RegCloseKey(hUserKey
);
3147 TRACE("returning 0x%08x\n", hr
);
3151 static HRESULT
_SHRegisterUserShellFolders(BOOL bDefault
)
3153 static const UINT folders
[] = {
3164 CSIDL_DESKTOPDIRECTORY
,
3168 CSIDL_LOCAL_APPDATA
,
3169 CSIDL_INTERNET_CACHE
,
3178 CSIDL_APPDATA_LOCALLOW
,
3182 WCHAR userShellFolderPath
[MAX_PATH
], shellFolderPath
[MAX_PATH
];
3183 LPCWSTR pUserShellFolderPath
, pShellFolderPath
;
3188 TRACE("%s\n", bDefault
? "TRUE" : "FALSE");
3191 hToken
= (HANDLE
)-1;
3192 hRootKey
= HKEY_USERS
;
3193 lstrcpyW(userShellFolderPath
, L
".Default");
3194 PathAddBackslashW(userShellFolderPath
);
3195 lstrcatW(userShellFolderPath
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders");
3196 pUserShellFolderPath
= userShellFolderPath
;
3197 lstrcpyW(shellFolderPath
, L
".Default");
3198 PathAddBackslashW(shellFolderPath
);
3199 lstrcatW(shellFolderPath
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
3200 pShellFolderPath
= shellFolderPath
;
3205 hRootKey
= HKEY_CURRENT_USER
;
3206 pUserShellFolderPath
= L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
3207 pShellFolderPath
= L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
3210 hr
= _SHRegisterFolders(hRootKey
, hToken
, pUserShellFolderPath
,
3211 pShellFolderPath
, folders
, ARRAY_SIZE(folders
));
3212 TRACE("returning 0x%08x\n", hr
);
3216 static HRESULT
_SHRegisterCommonShellFolders(void)
3218 static const UINT folders
[] = {
3219 CSIDL_COMMON_STARTMENU
,
3220 CSIDL_COMMON_PROGRAMS
,
3221 CSIDL_COMMON_STARTUP
,
3222 CSIDL_COMMON_DESKTOPDIRECTORY
,
3223 CSIDL_COMMON_FAVORITES
,
3224 CSIDL_COMMON_APPDATA
,
3225 CSIDL_COMMON_TEMPLATES
,
3226 CSIDL_COMMON_DOCUMENTS
,
3227 CSIDL_COMMON_ADMINTOOLS
,
3229 CSIDL_COMMON_PICTURES
,
3235 hr
= _SHRegisterFolders(HKEY_LOCAL_MACHINE
, NULL
,
3236 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders",
3237 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
3238 folders
, ARRAY_SIZE(folders
));
3239 TRACE("returning 0x%08x\n", hr
);
3243 /******************************************************************************
3244 * create_extra_folders [Internal]
3246 * Create some extra folders that don't have a standard CSIDL definition.
3248 static HRESULT
create_extra_folders(void)
3250 WCHAR path
[MAX_PATH
+5];
3253 DWORD type
, size
, ret
;
3255 ret
= RegCreateKeyW( HKEY_CURRENT_USER
, L
"Environment", &hkey
);
3256 if (ret
) return HRESULT_FROM_WIN32( ret
);
3258 /* FIXME: should be under AppData, but we don't want spaces in the temp path */
3259 hr
= SHGetFolderPathAndSubDirW( 0, CSIDL_PROFILE
| CSIDL_FLAG_CREATE
, NULL
,
3260 SHGFP_TYPE_DEFAULT
, L
"Temp", path
);
3263 size
= sizeof(path
);
3264 if (RegQueryValueExW( hkey
, L
"TEMP", NULL
, &type
, (LPBYTE
)path
, &size
))
3265 RegSetValueExW( hkey
, L
"TEMP", 0, REG_SZ
, (LPBYTE
)path
, (lstrlenW(path
) + 1) * sizeof(WCHAR
) );
3266 size
= sizeof(path
);
3267 if (RegQueryValueExW( hkey
, L
"TMP", NULL
, &type
, (LPBYTE
)path
, &size
))
3268 RegSetValueExW( hkey
, L
"TMP", 0, REG_SZ
, (LPBYTE
)path
, (lstrlenW(path
) + 1) * sizeof(WCHAR
) );
3270 RegCloseKey( hkey
);
3274 hr
= SHGetFolderPathAndSubDirW( 0, CSIDL_COMMON_APPDATA
| CSIDL_FLAG_CREATE
, NULL
,
3275 SHGFP_TYPE_DEFAULT
, L
"Microsoft", path
);
3279 hr
= SHGetFolderPathAndSubDirW(0, CSIDL_APPDATA
| CSIDL_FLAG_CREATE
, NULL
,
3280 SHGFP_TYPE_DEFAULT
, L
"Microsoft\\Windows\\Themes", path
);
3286 /******************************************************************************
3287 * set_folder_attributes
3289 * Set the various folder attributes registry keys.
3291 static HRESULT
set_folder_attributes(void)
3300 DWORD call_for_attr
;
3303 { &CLSID_UnixFolder
, TRUE
, FALSE
, FALSE
},
3304 { &CLSID_UnixDosFolder
, TRUE
, FALSE
, FALSE
,
3305 SFGAO_FILESYSANCESTOR
|SFGAO_FOLDER
|SFGAO_HASSUBFOLDER
, SFGAO_FILESYSTEM
},
3306 { &CLSID_FolderShortcut
, FALSE
, FALSE
, FALSE
,
3307 SFGAO_FILESYSTEM
|SFGAO_FOLDER
|SFGAO_LINK
,
3308 SFGAO_HASSUBFOLDER
|SFGAO_FILESYSTEM
|SFGAO_FOLDER
|SFGAO_FILESYSANCESTOR
},
3309 { &CLSID_MyDocuments
, TRUE
, FALSE
, FALSE
,
3310 SFGAO_FILESYSANCESTOR
|SFGAO_FOLDER
|SFGAO_HASSUBFOLDER
, SFGAO_FILESYSTEM
},
3311 { &CLSID_RecycleBin
, FALSE
, FALSE
, FALSE
,
3312 SFGAO_FOLDER
|SFGAO_DROPTARGET
|SFGAO_HASPROPSHEET
},
3313 { &CLSID_ControlPanel
, FALSE
, TRUE
, TRUE
,
3314 SFGAO_FOLDER
|SFGAO_HASSUBFOLDER
}
3318 WCHAR buffer
[39 + ARRAY_SIZE(L
"CLSID\\") + ARRAY_SIZE(L
"\\ShellFolder")];
3322 for (i
= 0; i
< ARRAY_SIZE(folders
); i
++)
3324 lstrcpyW( buffer
, L
"CLSID\\" );
3325 StringFromGUID2( folders
[i
].clsid
, buffer
+ lstrlenW(buffer
), 39 );
3326 lstrcatW( buffer
, L
"\\ShellFolder" );
3327 res
= RegCreateKeyExW( HKEY_CLASSES_ROOT
, buffer
, 0, NULL
, 0,
3328 KEY_READ
| KEY_WRITE
, NULL
, &hkey
, NULL
);
3329 if (res
) return HRESULT_FROM_WIN32( res
);
3330 if (folders
[i
].wfparsing
)
3331 res
= RegSetValueExW( hkey
, L
"WantsFORPARSING", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(WCHAR
) );
3332 if (folders
[i
].wfdisplay
)
3333 res
= RegSetValueExW( hkey
, L
"WantsFORDISPLAY", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(WCHAR
) );
3334 if (folders
[i
].hideasdel
)
3335 res
= RegSetValueExW( hkey
, L
"HideAsDeletePerUser", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(WCHAR
) );
3336 if (folders
[i
].attr
)
3337 res
= RegSetValueExW( hkey
, L
"Attributes", 0, REG_DWORD
,
3338 (const BYTE
*)&folders
[i
].attr
, sizeof(DWORD
));
3339 if (folders
[i
].call_for_attr
)
3340 res
= RegSetValueExW( hkey
, L
"CallForAttributes", 0, REG_DWORD
,
3341 (const BYTE
*)&folders
[i
].call_for_attr
, sizeof(DWORD
));
3342 RegCloseKey( hkey
);
3347 /*************************************************************************
3348 * SHGetSpecialFolderPathA [SHELL32.@]
3350 BOOL WINAPI
SHGetSpecialFolderPathA (
3356 return SHGetFolderPathA(hwndOwner
, nFolder
+ (bCreate
? CSIDL_FLAG_CREATE
: 0), NULL
, 0,
3360 /*************************************************************************
3361 * SHGetSpecialFolderPathW
3363 BOOL WINAPI
SHGetSpecialFolderPathW (
3369 return SHGetFolderPathW(hwndOwner
, nFolder
+ (bCreate
? CSIDL_FLAG_CREATE
: 0), NULL
, 0,
3373 /*************************************************************************
3374 * SHGetSpecialFolderPath (SHELL32.175)
3376 BOOL WINAPI
SHGetSpecialFolderPathAW (
3383 if (SHELL_OsIsUnicode())
3384 return SHGetSpecialFolderPathW (hwndOwner
, szPath
, nFolder
, bCreate
);
3385 return SHGetSpecialFolderPathA (hwndOwner
, szPath
, nFolder
, bCreate
);
3388 /*************************************************************************
3389 * SHGetFolderLocation [SHELL32.@]
3391 * Gets the folder locations from the registry and creates a pidl.
3395 * nFolder [I] CSIDL_xxxxx
3396 * hToken [I] token representing user, or NULL for current user, or -1 for
3398 * dwReserved [I] must be zero
3399 * ppidl [O] PIDL of a special folder
3403 * Failure: Standard OLE-defined error result, S_FALSE or E_INVALIDARG
3406 * Creates missing reg keys and directories.
3407 * Mostly forwards to SHGetFolderPathW, but a few values of nFolder return
3408 * virtual folders that are handled here.
3410 HRESULT WINAPI
SHGetFolderLocation(
3415 LPITEMIDLIST
*ppidl
)
3417 HRESULT hr
= E_INVALIDARG
;
3419 TRACE("%p 0x%08x %p 0x%08x %p\n",
3420 hwndOwner
, nFolder
, hToken
, dwReserved
, ppidl
);
3423 return E_INVALIDARG
;
3425 return E_INVALIDARG
;
3427 /* The virtual folders' locations are not user-dependent */
3429 switch (nFolder
& CSIDL_FOLDER_MASK
)
3432 *ppidl
= _ILCreateDesktop();
3435 case CSIDL_PERSONAL
:
3436 *ppidl
= _ILCreateMyDocuments();
3439 case CSIDL_INTERNET
:
3440 *ppidl
= _ILCreateIExplore();
3443 case CSIDL_CONTROLS
:
3444 *ppidl
= _ILCreateControlPanel();
3447 case CSIDL_PRINTERS
:
3448 *ppidl
= _ILCreatePrinters();
3451 case CSIDL_BITBUCKET
:
3452 *ppidl
= _ILCreateBitBucket();
3456 *ppidl
= _ILCreateMyComputer();
3460 *ppidl
= _ILCreateNetwork();
3465 WCHAR szPath
[MAX_PATH
];
3467 hr
= SHGetFolderPathW(hwndOwner
, nFolder
, hToken
,
3468 SHGFP_TYPE_CURRENT
, szPath
);
3473 TRACE("Value=%s\n", debugstr_w(szPath
));
3474 hr
= SHILCreateFromPathW(szPath
, ppidl
, &attributes
);
3476 else if (hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
3478 /* unlike SHGetFolderPath, SHGetFolderLocation in shell32
3479 * version 6.0 returns E_FAIL for nonexistent paths
3488 TRACE("-- (new pidl %p)\n",*ppidl
);
3492 /*************************************************************************
3493 * SHGetSpecialFolderLocation [SHELL32.@]
3496 * In NT5, SHGetSpecialFolderLocation needs the <winntdir>/Recent
3499 HRESULT WINAPI
SHGetSpecialFolderLocation(
3502 LPITEMIDLIST
* ppidl
)
3504 HRESULT hr
= E_INVALIDARG
;
3506 TRACE("(%p,0x%x,%p)\n", hwndOwner
,nFolder
,ppidl
);
3509 return E_INVALIDARG
;
3511 hr
= SHGetFolderLocation(hwndOwner
, nFolder
, NULL
, 0, ppidl
);
3515 /*************************************************************************
3516 * SHGetKnownFolderPath [SHELL32.@]
3518 HRESULT WINAPI
SHGetKnownFolderPath(REFKNOWNFOLDERID rfid
, DWORD flags
, HANDLE token
, WCHAR
**ret_path
)
3520 WCHAR pathW
[MAX_PATH
];
3522 int folder
= csidl_from_id(rfid
), shgfp_flags
;
3524 TRACE("%s, 0x%08x, %p, %p\n", debugstr_guid(rfid
), flags
, token
, ret_path
);
3529 return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND
);
3531 if (flags
& ~(KF_FLAG_CREATE
|KF_FLAG_SIMPLE_IDLIST
|KF_FLAG_DONT_UNEXPAND
|
3532 KF_FLAG_DONT_VERIFY
|KF_FLAG_NO_ALIAS
|KF_FLAG_INIT
|KF_FLAG_DEFAULT_PATH
))
3534 FIXME("flags 0x%08x not supported\n", flags
);
3535 return E_INVALIDARG
;
3537 folder
|= flags
& CSIDL_FLAG_MASK
;
3538 shgfp_flags
= flags
& KF_FLAG_DEFAULT_PATH
? SHGFP_TYPE_DEFAULT
: SHGFP_TYPE_CURRENT
;
3540 hr
= SHGetFolderPathAndSubDirW( 0, folder
, token
, shgfp_flags
, NULL
, pathW
);
3543 TRACE("Failed to get folder path, %#x.\n", hr
);
3547 TRACE("Final path is %s, %#x\n", debugstr_w(pathW
), hr
);
3549 *ret_path
= CoTaskMemAlloc((lstrlenW(pathW
) + 1) * sizeof(WCHAR
));
3551 return E_OUTOFMEMORY
;
3552 lstrcpyW(*ret_path
, pathW
);
3557 /*************************************************************************
3558 * SHGetFolderPathEx [SHELL32.@]
3560 HRESULT WINAPI
SHGetFolderPathEx(REFKNOWNFOLDERID rfid
, DWORD flags
, HANDLE token
, LPWSTR path
, DWORD len
)
3565 TRACE("%s, 0x%08x, %p, %p, %u\n", debugstr_guid(rfid
), flags
, token
, path
, len
);
3567 if (!path
|| !len
) return E_INVALIDARG
;
3569 hr
= SHGetKnownFolderPath( rfid
, flags
, token
, &buffer
);
3570 if (SUCCEEDED( hr
))
3572 if (lstrlenW( buffer
) + 1 > len
)
3574 CoTaskMemFree( buffer
);
3575 return HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER
);
3577 lstrcpyW( path
, buffer
);
3578 CoTaskMemFree( buffer
);
3584 * Internal function to convert known folder identifier to path of registry key
3585 * associated with known folder.
3588 * rfid [I] pointer to known folder identifier (may be NULL)
3589 * lpStringGuid [I] string with known folder identifier (used when rfid is NULL)
3590 * lpPath [O] place to store string address. String should be
3591 * later freed using HeapFree(GetProcessHeap(),0, ... )
3593 static HRESULT
get_known_folder_registry_path(
3594 REFKNOWNFOLDERID rfid
,
3595 LPWSTR lpStringGuid
,
3602 TRACE("(%s, %s, %p)\n", debugstr_guid(rfid
), debugstr_w(lpStringGuid
), lpPath
);
3605 StringFromGUID2(rfid
, sGuid
, ARRAY_SIZE(sGuid
));
3607 lstrcpyW(sGuid
, lpStringGuid
);
3609 length
= lstrlenW(L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FolderDescriptions")+51;
3610 *lpPath
= heap_alloc(length
*sizeof(WCHAR
));
3616 lstrcpyW(*lpPath
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FolderDescriptions\\");
3617 lstrcatW(*lpPath
, sGuid
);
3623 static HRESULT
get_known_folder_wstr(const WCHAR
*regpath
, const WCHAR
*value
, WCHAR
**out
)
3629 hr
= HRESULT_FROM_WIN32(RegGetValueW(HKEY_LOCAL_MACHINE
, regpath
, value
, RRF_RT_REG_SZ
, NULL
, NULL
, &size
));
3633 *out
= CoTaskMemAlloc(size
);
3635 return E_OUTOFMEMORY
;
3637 hr
= HRESULT_FROM_WIN32(RegGetValueW(HKEY_LOCAL_MACHINE
, regpath
, value
, RRF_RT_REG_SZ
, NULL
, *out
, &size
));
3639 CoTaskMemFree(*out
);
3646 static HRESULT
get_known_folder_dword(const WCHAR
*registryPath
, const WCHAR
*value
, DWORD
*out
)
3648 DWORD dwSize
= sizeof(DWORD
);
3650 return HRESULT_FROM_WIN32(RegGetValueW(HKEY_LOCAL_MACHINE
, registryPath
, value
, RRF_RT_DWORD
, &dwType
, out
, &dwSize
));
3654 * Internal function to get place where folder redirection information are stored.
3657 * rfid [I] pointer to known folder identifier (may be NULL)
3658 * rootKey [O] root key where the redirection information are stored
3659 * It can be HKLM for COMMON folders, and HKCU for PERUSER folders.
3661 static HRESULT
get_known_folder_redirection_place(
3662 REFKNOWNFOLDERID rfid
,
3666 LPWSTR lpRegistryPath
= NULL
;
3667 KF_CATEGORY category
;
3669 /* first, get known folder's category */
3670 hr
= get_known_folder_registry_path(rfid
, NULL
, &lpRegistryPath
);
3673 hr
= get_known_folder_dword(lpRegistryPath
, L
"Category", &category
);
3677 if(category
== KF_CATEGORY_COMMON
)
3679 *rootKey
= HKEY_LOCAL_MACHINE
;
3682 else if(category
== KF_CATEGORY_PERUSER
)
3684 *rootKey
= HKEY_CURRENT_USER
;
3691 heap_free(lpRegistryPath
);
3695 static HRESULT
get_known_folder_path_by_id(REFKNOWNFOLDERID folderId
, LPWSTR lpRegistryPath
, DWORD dwFlags
, LPWSTR
*ppszPath
);
3697 static HRESULT
redirect_known_folder(
3698 REFKNOWNFOLDERID rfid
,
3700 KF_REDIRECT_FLAGS flags
,
3701 LPCWSTR pszTargetPath
,
3703 KNOWNFOLDERID
const *pExclusion
,
3707 HKEY rootKey
= HKEY_LOCAL_MACHINE
, hKey
;
3709 LPWSTR lpRegistryPath
= NULL
, lpSrcPath
= NULL
;
3710 TRACE("(%s, %p, 0x%08x, %s, %d, %p, %p)\n", debugstr_guid(rfid
), hwnd
, flags
, debugstr_w(pszTargetPath
), cFolders
, pExclusion
, ppszError
);
3712 if (ppszError
) *ppszError
= NULL
;
3714 hr
= get_known_folder_registry_path(rfid
, NULL
, &lpRegistryPath
);
3717 hr
= get_known_folder_path_by_id(rfid
, lpRegistryPath
, 0, &lpSrcPath
);
3719 heap_free(lpRegistryPath
);
3721 /* get path to redirection storage */
3723 hr
= get_known_folder_redirection_place(rfid
, &rootKey
);
3725 /* write redirection information */
3727 hr
= HRESULT_FROM_WIN32(RegCreateKeyExW(rootKey
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders", 0, NULL
, 0, KEY_WRITE
, NULL
, &hKey
, NULL
));
3731 StringFromGUID2(rfid
, sGuid
, ARRAY_SIZE(sGuid
));
3733 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sGuid
, 0, REG_SZ
, (LPBYTE
)pszTargetPath
, (lstrlenW(pszTargetPath
)+1)*sizeof(WCHAR
)));
3738 /* make sure destination path exists */
3739 SHCreateDirectory(NULL
, pszTargetPath
);
3741 /* copy content if required */
3742 if(SUCCEEDED(hr
) && (flags
& KF_REDIRECT_COPY_CONTENTS
) )
3744 WCHAR srcPath
[MAX_PATH
+1], dstPath
[MAX_PATH
+1];
3745 SHFILEOPSTRUCTW fileOp
;
3747 ZeroMemory(srcPath
, sizeof(srcPath
));
3748 lstrcpyW(srcPath
, lpSrcPath
);
3749 lstrcatW(srcPath
, L
"\\*");
3751 ZeroMemory(dstPath
, sizeof(dstPath
));
3752 lstrcpyW(dstPath
, pszTargetPath
);
3754 ZeroMemory(&fileOp
, sizeof(fileOp
));
3756 if(flags
& KF_REDIRECT_DEL_SOURCE_CONTENTS
)
3757 fileOp
.wFunc
= FO_MOVE
;
3759 fileOp
.wFunc
= FO_COPY
;
3761 fileOp
.pFrom
= srcPath
;
3762 fileOp
.pTo
= dstPath
;
3763 fileOp
.fFlags
= FOF_NO_UI
;
3765 hr
= (SHFileOperationW(&fileOp
)==0 ? S_OK
: E_FAIL
);
3767 if(flags
& KF_REDIRECT_DEL_SOURCE_CONTENTS
)
3769 ZeroMemory(srcPath
, sizeof(srcPath
));
3770 lstrcpyW(srcPath
, lpSrcPath
);
3772 ZeroMemory(&fileOp
, sizeof(fileOp
));
3773 fileOp
.wFunc
= FO_DELETE
;
3774 fileOp
.pFrom
= srcPath
;
3775 fileOp
.fFlags
= FOF_NO_UI
;
3777 hr
= (SHFileOperationW(&fileOp
)==0 ? S_OK
: E_FAIL
);
3781 CoTaskMemFree(lpSrcPath
);
3789 IKnownFolder IKnownFolder_iface
;
3792 LPWSTR registryPath
;
3795 static inline struct knownfolder
*impl_from_IKnownFolder( IKnownFolder
*iface
)
3797 return CONTAINING_RECORD( iface
, struct knownfolder
, IKnownFolder_iface
);
3800 static ULONG WINAPI
knownfolder_AddRef(
3801 IKnownFolder
*iface
)
3803 struct knownfolder
*knownfolder
= impl_from_IKnownFolder( iface
);
3804 return InterlockedIncrement( &knownfolder
->refs
);
3807 static ULONG WINAPI
knownfolder_Release(
3808 IKnownFolder
*iface
)
3810 struct knownfolder
*knownfolder
= impl_from_IKnownFolder( iface
);
3811 LONG refs
= InterlockedDecrement( &knownfolder
->refs
);
3814 TRACE("destroying %p\n", knownfolder
);
3815 heap_free( knownfolder
->registryPath
);
3816 heap_free( knownfolder
);
3821 static HRESULT WINAPI
knownfolder_QueryInterface(
3822 IKnownFolder
*iface
,
3826 struct knownfolder
*This
= impl_from_IKnownFolder( iface
);
3828 TRACE("%p %s %p\n", This
, debugstr_guid( riid
), ppv
);
3831 if ( IsEqualGUID( riid
, &IID_IKnownFolder
) ||
3832 IsEqualGUID( riid
, &IID_IUnknown
) )
3836 else if ( IsEqualGUID( riid
, &IID_IMarshal
) )
3838 TRACE("IID_IMarshal returning NULL.\n");
3839 return E_NOINTERFACE
;
3843 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
3844 return E_NOINTERFACE
;
3846 IKnownFolder_AddRef( iface
);
3850 static HRESULT
knownfolder_set_id(
3851 struct knownfolder
*knownfolder
,
3852 const KNOWNFOLDERID
*kfid
)
3857 TRACE("%s\n", debugstr_guid(kfid
));
3859 knownfolder
->id
= *kfid
;
3861 /* check is it registry-registered folder */
3862 hr
= get_known_folder_registry_path(kfid
, NULL
, &knownfolder
->registryPath
);
3864 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
, knownfolder
->registryPath
, 0, 0, &hKey
));
3873 /* This known folder is not registered. To mark it, we set registryPath to NULL */
3874 heap_free(knownfolder
->registryPath
);
3875 knownfolder
->registryPath
= NULL
;
3882 static HRESULT WINAPI
knownfolder_GetId(
3883 IKnownFolder
*iface
,
3884 KNOWNFOLDERID
*pkfid
)
3886 struct knownfolder
*knownfolder
= impl_from_IKnownFolder( iface
);
3888 TRACE("%p\n", pkfid
);
3890 *pkfid
= knownfolder
->id
;
3894 static HRESULT WINAPI
knownfolder_GetCategory(
3895 IKnownFolder
*iface
,
3896 KF_CATEGORY
*pCategory
)
3898 struct knownfolder
*knownfolder
= impl_from_IKnownFolder(iface
);
3901 TRACE("%p, %p\n", knownfolder
, pCategory
);
3903 /* we cannot get a category for a folder which is not registered */
3904 if(!knownfolder
->registryPath
)
3908 hr
= get_known_folder_dword(knownfolder
->registryPath
, L
"Category", pCategory
);
3913 static HRESULT WINAPI
knownfolder_GetShellItem(
3914 IKnownFolder
*iface
,
3919 struct knownfolder
*knownfolder
= impl_from_IKnownFolder(iface
);
3920 TRACE("(%p, 0x%08x, %s, %p)\n", knownfolder
, flags
, debugstr_guid(riid
), ppv
);
3921 return SHGetKnownFolderItem(&knownfolder
->id
, flags
, NULL
, riid
, ppv
);
3924 static HRESULT
get_known_folder_path(
3926 LPWSTR registryPath
,
3930 DWORD dwSize
, dwType
;
3931 WCHAR path
[MAX_PATH
] = {0};
3932 WCHAR parentGuid
[39];
3933 KF_CATEGORY category
;
3934 LPWSTR parentRegistryPath
, parentPath
;
3935 HKEY hRedirectionRootKey
= NULL
;
3937 TRACE("(%s, %p)\n", debugstr_w(registryPath
), ppszPath
);
3940 /* check if folder has parent */
3941 dwSize
= sizeof(parentGuid
);
3942 hr
= HRESULT_FROM_WIN32(RegGetValueW(HKEY_LOCAL_MACHINE
, registryPath
, L
"ParentFolder", RRF_RT_REG_SZ
, &dwType
, parentGuid
, &dwSize
));
3943 if(hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
)) hr
= S_FALSE
;
3947 /* get parent's known folder path (recursive) */
3948 hr
= get_known_folder_registry_path(NULL
, parentGuid
, &parentRegistryPath
);
3949 if(FAILED(hr
)) return hr
;
3951 hr
= get_known_folder_path(parentGuid
, parentRegistryPath
, &parentPath
);
3953 heap_free(parentRegistryPath
);
3957 lstrcatW(path
, parentPath
);
3958 lstrcatW(path
, L
"\\");
3960 heap_free(parentRegistryPath
);
3961 heap_free(parentPath
);
3964 /* check, if folder was redirected */
3966 hr
= get_known_folder_dword(registryPath
, L
"Category", &category
);
3970 if(category
== KF_CATEGORY_COMMON
)
3971 hRedirectionRootKey
= HKEY_LOCAL_MACHINE
;
3972 else if(category
== KF_CATEGORY_PERUSER
)
3973 hRedirectionRootKey
= HKEY_CURRENT_USER
;
3975 if(hRedirectionRootKey
)
3977 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRedirectionRootKey
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders", sFolderId
, RRF_RT_REG_SZ
, NULL
, NULL
, &dwSize
));
3981 *ppszPath
= CoTaskMemAlloc(dwSize
+(lstrlenW(path
)+1)*sizeof(WCHAR
));
3982 if(!*ppszPath
) hr
= E_OUTOFMEMORY
;
3987 lstrcpyW(*ppszPath
, path
);
3988 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRedirectionRootKey
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders", sFolderId
, RRF_RT_REG_SZ
, NULL
, *ppszPath
+ lstrlenW(path
), &dwSize
));
3994 /* no redirection, use previous way - read the relative path from folder definition */
3995 hr
= HRESULT_FROM_WIN32(RegGetValueW(HKEY_LOCAL_MACHINE
, registryPath
, L
"RelativePath", RRF_RT_REG_SZ
, &dwType
, NULL
, &dwSize
));
3999 *ppszPath
= CoTaskMemAlloc(dwSize
+(lstrlenW(path
)+1)*sizeof(WCHAR
));
4000 if(!*ppszPath
) hr
= E_OUTOFMEMORY
;
4005 lstrcpyW(*ppszPath
, path
);
4006 hr
= HRESULT_FROM_WIN32(RegGetValueW(HKEY_LOCAL_MACHINE
, registryPath
, L
"RelativePath", RRF_RT_REG_SZ
, &dwType
, *ppszPath
+ lstrlenW(path
), &dwSize
));
4011 TRACE("returning path: %s\n", debugstr_w(*ppszPath
));
4015 static HRESULT
get_known_folder_path_by_id(
4016 REFKNOWNFOLDERID folderId
,
4017 LPWSTR lpRegistryPath
,
4021 HRESULT hr
= E_FAIL
;
4025 TRACE("(%s, %s, 0x%08x, %p)\n", debugstr_guid(folderId
), debugstr_w(lpRegistryPath
), dwFlags
, ppszPath
);
4027 /* if this is registry-registered known folder, get path from registry */
4030 StringFromGUID2(folderId
, sGuid
, ARRAY_SIZE(sGuid
));
4032 hr
= get_known_folder_path(sGuid
, lpRegistryPath
, ppszPath
);
4034 /* in other case, use older way */
4037 hr
= SHGetKnownFolderPath( folderId
, dwFlags
, NULL
, ppszPath
);
4039 if (FAILED(hr
)) return hr
;
4041 /* check if known folder really exists */
4042 dwAttributes
= GetFileAttributesW(*ppszPath
);
4043 if(dwAttributes
== INVALID_FILE_ATTRIBUTES
|| !(dwAttributes
& FILE_ATTRIBUTE_DIRECTORY
) )
4045 TRACE("directory %s not found\n", debugstr_w(*ppszPath
));
4046 CoTaskMemFree(*ppszPath
);
4048 hr
= HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
4054 static HRESULT WINAPI
knownfolder_GetPath(
4055 IKnownFolder
*iface
,
4059 struct knownfolder
*knownfolder
= impl_from_IKnownFolder( iface
);
4060 TRACE("(%p, 0x%08x, %p)\n", knownfolder
, dwFlags
, ppszPath
);
4062 return get_known_folder_path_by_id(&knownfolder
->id
, knownfolder
->registryPath
, dwFlags
, ppszPath
);
4065 static HRESULT WINAPI
knownfolder_SetPath(
4066 IKnownFolder
*iface
,
4070 struct knownfolder
*knownfolder
= impl_from_IKnownFolder( iface
);
4073 TRACE("(%p, 0x%08x, %s)\n", knownfolder
, dwFlags
, debugstr_w(pszPath
));
4075 /* check if the known folder is registered */
4076 if(!knownfolder
->registryPath
)
4080 hr
= redirect_known_folder(&knownfolder
->id
, NULL
, 0, pszPath
, 0, NULL
, NULL
);
4085 static HRESULT WINAPI
knownfolder_GetIDList(
4086 IKnownFolder
*iface
,
4088 PIDLIST_ABSOLUTE
*ppidl
)
4090 struct knownfolder
*knownfolder
= impl_from_IKnownFolder( iface
);
4091 TRACE("(%p, 0x%08x, %p)\n", knownfolder
, flags
, ppidl
);
4092 return SHGetKnownFolderIDList(&knownfolder
->id
, flags
, NULL
, ppidl
);
4095 static HRESULT WINAPI
knownfolder_GetFolderType(
4096 IKnownFolder
*iface
,
4097 FOLDERTYPEID
*pftid
)
4099 FIXME("%p\n", pftid
);
4103 static HRESULT WINAPI
knownfolder_GetRedirectionCapabilities(
4104 IKnownFolder
*iface
,
4105 KF_REDIRECTION_CAPABILITIES
*pCapabilities
)
4107 FIXME("%p stub\n", pCapabilities
);
4108 if(!pCapabilities
) return E_INVALIDARG
;
4109 *pCapabilities
= KF_REDIRECTION_CAPABILITIES_DENY_ALL
;
4113 static HRESULT WINAPI
knownfolder_GetFolderDefinition(
4114 IKnownFolder
*iface
,
4115 KNOWNFOLDER_DEFINITION
*pKFD
)
4117 struct knownfolder
*knownfolder
= impl_from_IKnownFolder( iface
);
4120 WCHAR parentGuid
[39];
4121 TRACE("(%p, %p)\n", knownfolder
, pKFD
);
4123 if(!pKFD
) return E_INVALIDARG
;
4125 ZeroMemory(pKFD
, sizeof(*pKFD
));
4127 /* required fields */
4128 hr
= get_known_folder_dword(knownfolder
->registryPath
, L
"Category", &pKFD
->category
);
4132 hr
= get_known_folder_wstr(knownfolder
->registryPath
, L
"Name", &pKFD
->pszName
);
4136 /* optional fields */
4137 dwSize
= sizeof(parentGuid
);
4138 hr
= HRESULT_FROM_WIN32(RegGetValueW(HKEY_LOCAL_MACHINE
, knownfolder
->registryPath
, L
"ParentFolder",
4139 RRF_RT_REG_SZ
, NULL
, parentGuid
, &dwSize
));
4142 hr
= IIDFromString(parentGuid
, &pKFD
->fidParent
);
4147 get_known_folder_dword(knownfolder
->registryPath
, L
"Attributes", &pKFD
->dwAttributes
);
4149 get_known_folder_wstr(knownfolder
->registryPath
, L
"RelativePath", &pKFD
->pszRelativePath
);
4151 get_known_folder_wstr(knownfolder
->registryPath
, L
"ParsingName", &pKFD
->pszParsingName
);
4156 static const struct IKnownFolderVtbl knownfolder_vtbl
=
4158 knownfolder_QueryInterface
,
4160 knownfolder_Release
,
4162 knownfolder_GetCategory
,
4163 knownfolder_GetShellItem
,
4164 knownfolder_GetPath
,
4165 knownfolder_SetPath
,
4166 knownfolder_GetIDList
,
4167 knownfolder_GetFolderType
,
4168 knownfolder_GetRedirectionCapabilities
,
4169 knownfolder_GetFolderDefinition
4172 static HRESULT
knownfolder_create( struct knownfolder
**knownfolder
)
4174 struct knownfolder
*kf
;
4176 kf
= heap_alloc( sizeof(*kf
) );
4177 if (!kf
) return E_OUTOFMEMORY
;
4179 kf
->IKnownFolder_iface
.lpVtbl
= &knownfolder_vtbl
;
4181 memset( &kf
->id
, 0, sizeof(kf
->id
) );
4182 kf
->registryPath
= NULL
;
4186 TRACE("returning iface %p\n", &kf
->IKnownFolder_iface
);
4190 struct foldermanager
4192 IKnownFolderManager IKnownFolderManager_iface
;
4198 static inline struct foldermanager
*impl_from_IKnownFolderManager( IKnownFolderManager
*iface
)
4200 return CONTAINING_RECORD( iface
, struct foldermanager
, IKnownFolderManager_iface
);
4203 static ULONG WINAPI
foldermanager_AddRef(
4204 IKnownFolderManager
*iface
)
4206 struct foldermanager
*foldermanager
= impl_from_IKnownFolderManager( iface
);
4207 return InterlockedIncrement( &foldermanager
->refs
);
4210 static ULONG WINAPI
foldermanager_Release(
4211 IKnownFolderManager
*iface
)
4213 struct foldermanager
*foldermanager
= impl_from_IKnownFolderManager( iface
);
4214 LONG refs
= InterlockedDecrement( &foldermanager
->refs
);
4217 TRACE("destroying %p\n", foldermanager
);
4218 heap_free( foldermanager
->ids
);
4219 heap_free( foldermanager
);
4224 static HRESULT WINAPI
foldermanager_QueryInterface(
4225 IKnownFolderManager
*iface
,
4229 struct foldermanager
*This
= impl_from_IKnownFolderManager( iface
);
4231 TRACE("%p %s %p\n", This
, debugstr_guid( riid
), ppv
);
4234 if ( IsEqualGUID( riid
, &IID_IKnownFolderManager
) ||
4235 IsEqualGUID( riid
, &IID_IUnknown
) )
4239 else if ( IsEqualGUID( riid
, &IID_IMarshal
) )
4241 TRACE("IID_IMarshal returning NULL.\n");
4242 return E_NOINTERFACE
;
4246 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
4247 return E_NOINTERFACE
;
4249 IKnownFolderManager_AddRef( iface
);
4253 static HRESULT WINAPI
foldermanager_FolderIdFromCsidl(
4254 IKnownFolderManager
*iface
,
4256 KNOWNFOLDERID
*pfid
)
4258 TRACE("%d, %p\n", nCsidl
, pfid
);
4260 if (nCsidl
>= ARRAY_SIZE(CSIDL_Data
))
4261 return E_INVALIDARG
;
4262 *pfid
= *CSIDL_Data
[nCsidl
].id
;
4266 static HRESULT WINAPI
foldermanager_FolderIdToCsidl(
4267 IKnownFolderManager
*iface
,
4268 REFKNOWNFOLDERID rfid
,
4273 TRACE("%s, %p\n", debugstr_guid(rfid
), pnCsidl
);
4275 csidl
= csidl_from_id( rfid
);
4276 if (csidl
== -1) return E_INVALIDARG
;
4281 static HRESULT WINAPI
foldermanager_GetFolderIds(
4282 IKnownFolderManager
*iface
,
4283 KNOWNFOLDERID
**ppKFId
,
4286 struct foldermanager
*fm
= impl_from_IKnownFolderManager( iface
);
4288 TRACE("%p, %p\n", ppKFId
, pCount
);
4290 *ppKFId
= CoTaskMemAlloc(fm
->num_ids
* sizeof(KNOWNFOLDERID
));
4291 memcpy(*ppKFId
, fm
->ids
, fm
->num_ids
* sizeof(KNOWNFOLDERID
));
4292 *pCount
= fm
->num_ids
;
4296 static BOOL
is_knownfolder( struct foldermanager
*fm
, const KNOWNFOLDERID
*id
)
4300 LPWSTR registryPath
= NULL
;
4303 /* TODO: move all entries from "CSIDL_Data" static array to registry known folder descriptions */
4304 for (i
= 0; i
< fm
->num_ids
; i
++)
4305 if (IsEqualGUID( &fm
->ids
[i
], id
)) return TRUE
;
4307 hr
= get_known_folder_registry_path(id
, NULL
, ®istryPath
);
4310 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
, registryPath
, 0, 0, &hKey
));
4311 heap_free(registryPath
);
4323 static HRESULT WINAPI
foldermanager_GetFolder(
4324 IKnownFolderManager
*iface
,
4325 REFKNOWNFOLDERID rfid
,
4326 IKnownFolder
**ppkf
)
4328 struct foldermanager
*fm
= impl_from_IKnownFolderManager( iface
);
4329 struct knownfolder
*kf
;
4332 TRACE("%s, %p\n", debugstr_guid(rfid
), ppkf
);
4334 if (!is_knownfolder( fm
, rfid
))
4336 WARN("unknown folder\n");
4337 return E_INVALIDARG
;
4339 hr
= knownfolder_create( &kf
);
4340 if (SUCCEEDED( hr
))
4342 hr
= knownfolder_set_id( kf
, rfid
);
4343 *ppkf
= &kf
->IKnownFolder_iface
;
4351 static HRESULT WINAPI
foldermanager_GetFolderByName(
4352 IKnownFolderManager
*iface
,
4353 LPCWSTR pszCanonicalName
,
4354 IKnownFolder
**ppkf
)
4356 struct foldermanager
*fm
= impl_from_IKnownFolderManager( iface
);
4357 struct knownfolder
*kf
;
4362 TRACE( "%s, %p\n", debugstr_w(pszCanonicalName
), ppkf
);
4364 for (i
= 0; i
< fm
->num_ids
; i
++)
4367 hr
= get_known_folder_registry_path( &fm
->ids
[i
], NULL
, &path
);
4368 if (FAILED( hr
)) return hr
;
4370 hr
= get_known_folder_wstr( path
, L
"Name", &name
);
4372 if (FAILED( hr
)) return hr
;
4374 found
= !wcsicmp( pszCanonicalName
, name
);
4375 CoTaskMemFree( name
);
4381 hr
= knownfolder_create( &kf
);
4382 if (FAILED( hr
)) return hr
;
4384 hr
= knownfolder_set_id( kf
, &fm
->ids
[i
] );
4387 IKnownFolder_Release( &kf
->IKnownFolder_iface
);
4390 *ppkf
= &kf
->IKnownFolder_iface
;
4394 hr
= HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND
);
4401 static HRESULT
register_folder(const KNOWNFOLDERID
*rfid
, const KNOWNFOLDER_DEFINITION
*pKFD
)
4406 LPWSTR registryPath
= NULL
;
4408 hr
= get_known_folder_registry_path(rfid
, NULL
, ®istryPath
);
4409 TRACE("registry path: %s\n", debugstr_w(registryPath
));
4412 hr
= HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, registryPath
, 0, NULL
, 0, KEY_WRITE
, 0, &hKey
, &dwDisp
));
4416 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"Category", 0, REG_DWORD
, (LPBYTE
)&pKFD
->category
, sizeof(pKFD
->category
)));
4418 if(SUCCEEDED(hr
) && pKFD
->dwAttributes
!= 0)
4419 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"Attributes", 0, REG_DWORD
, (LPBYTE
)&pKFD
->dwAttributes
, sizeof(pKFD
->dwAttributes
)));
4422 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"Name", 0, REG_SZ
, (LPBYTE
)pKFD
->pszName
, (lstrlenW(pKFD
->pszName
)+1)*sizeof(WCHAR
) ));
4424 if(SUCCEEDED(hr
) && pKFD
->pszParsingName
)
4425 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"ParsingName", 0, REG_SZ
, (LPBYTE
)pKFD
->pszParsingName
, (lstrlenW(pKFD
->pszParsingName
)+1)*sizeof(WCHAR
) ));
4427 if(SUCCEEDED(hr
) && !IsEqualGUID(&pKFD
->fidParent
, &GUID_NULL
))
4429 WCHAR sParentGuid
[39];
4430 StringFromGUID2(&pKFD
->fidParent
, sParentGuid
, ARRAY_SIZE(sParentGuid
));
4432 /* this known folder has parent folder */
4433 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"ParentFolder", 0, REG_SZ
, (LPBYTE
)sParentGuid
, sizeof(sParentGuid
)));
4436 if(SUCCEEDED(hr
) && pKFD
->category
!= KF_CATEGORY_VIRTUAL
&& pKFD
->pszRelativePath
)
4437 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"RelativePath", 0, REG_SZ
, (LPBYTE
)pKFD
->pszRelativePath
, (lstrlenW(pKFD
->pszRelativePath
)+1)*sizeof(WCHAR
) ));
4442 SHDeleteKeyW(HKEY_LOCAL_MACHINE
, registryPath
);
4445 heap_free(registryPath
);
4449 static HRESULT WINAPI
foldermanager_RegisterFolder(
4450 IKnownFolderManager
*iface
,
4451 REFKNOWNFOLDERID rfid
,
4452 KNOWNFOLDER_DEFINITION
const *pKFD
)
4454 TRACE("(%p, %s, %p)\n", iface
, debugstr_guid(rfid
), pKFD
);
4455 return register_folder(rfid
, pKFD
);
4458 static HRESULT WINAPI
foldermanager_UnregisterFolder(
4459 IKnownFolderManager
*iface
,
4460 REFKNOWNFOLDERID rfid
)
4463 LPWSTR registryPath
= NULL
;
4464 TRACE("(%p, %s)\n", iface
, debugstr_guid(rfid
));
4466 hr
= get_known_folder_registry_path(rfid
, NULL
, ®istryPath
);
4469 hr
= HRESULT_FROM_WIN32(SHDeleteKeyW(HKEY_LOCAL_MACHINE
, registryPath
));
4471 heap_free(registryPath
);
4475 static HRESULT WINAPI
foldermanager_FindFolderFromPath(
4476 IKnownFolderManager
*iface
,
4479 IKnownFolder
**ppkf
)
4481 FIXME("%s, 0x%08x, %p\n", debugstr_w(pszPath
), mode
, ppkf
);
4485 static HRESULT WINAPI
foldermanager_FindFolderFromIDList(
4486 IKnownFolderManager
*iface
,
4487 PCIDLIST_ABSOLUTE pidl
,
4488 IKnownFolder
**ppkf
)
4490 FIXME("%p, %p\n", pidl
, ppkf
);
4494 static HRESULT WINAPI
foldermanager_Redirect(
4495 IKnownFolderManager
*iface
,
4496 REFKNOWNFOLDERID rfid
,
4498 KF_REDIRECT_FLAGS flags
,
4499 LPCWSTR pszTargetPath
,
4501 KNOWNFOLDERID
const *pExclusion
,
4504 return redirect_known_folder(rfid
, hwnd
, flags
, pszTargetPath
, cFolders
, pExclusion
, ppszError
);
4507 static const struct IKnownFolderManagerVtbl foldermanager_vtbl
=
4509 foldermanager_QueryInterface
,
4510 foldermanager_AddRef
,
4511 foldermanager_Release
,
4512 foldermanager_FolderIdFromCsidl
,
4513 foldermanager_FolderIdToCsidl
,
4514 foldermanager_GetFolderIds
,
4515 foldermanager_GetFolder
,
4516 foldermanager_GetFolderByName
,
4517 foldermanager_RegisterFolder
,
4518 foldermanager_UnregisterFolder
,
4519 foldermanager_FindFolderFromPath
,
4520 foldermanager_FindFolderFromIDList
,
4521 foldermanager_Redirect
4524 static HRESULT
foldermanager_create( void **ppv
)
4527 struct foldermanager
*fm
;
4529 fm
= heap_alloc( sizeof(*fm
) );
4530 if (!fm
) return E_OUTOFMEMORY
;
4532 fm
->IKnownFolderManager_iface
.lpVtbl
= &foldermanager_vtbl
;
4536 for (i
= 0; i
< ARRAY_SIZE(CSIDL_Data
); i
++)
4538 if (!IsEqualGUID( CSIDL_Data
[i
].id
, &GUID_NULL
)) fm
->num_ids
++;
4540 fm
->ids
= heap_alloc( fm
->num_ids
* sizeof(KNOWNFOLDERID
) );
4544 return E_OUTOFMEMORY
;
4546 for (i
= j
= 0; i
< ARRAY_SIZE(CSIDL_Data
); i
++)
4548 if (!IsEqualGUID( CSIDL_Data
[i
].id
, &GUID_NULL
))
4550 fm
->ids
[j
] = *CSIDL_Data
[i
].id
;
4554 TRACE("found %u known folders\n", fm
->num_ids
);
4555 *ppv
= &fm
->IKnownFolderManager_iface
;
4557 TRACE("returning iface %p\n", *ppv
);
4561 HRESULT WINAPI
KnownFolderManager_Constructor( IUnknown
*punk
, REFIID riid
, void **ppv
)
4563 TRACE("%p, %s, %p\n", punk
, debugstr_guid(riid
), ppv
);
4568 return CLASS_E_NOAGGREGATION
;
4570 return foldermanager_create( ppv
);
4573 HRESULT WINAPI
SHGetKnownFolderIDList(REFKNOWNFOLDERID rfid
, DWORD flags
, HANDLE token
, PIDLIST_ABSOLUTE
*pidl
)
4575 TRACE("%s, 0x%08x, %p, %p\n", debugstr_guid(rfid
), flags
, token
, pidl
);
4578 return E_INVALIDARG
;
4581 FIXME("unsupported flags: 0x%08x\n", flags
);
4584 FIXME("user token is not used.\n");
4587 if (IsEqualIID(rfid
, &FOLDERID_Desktop
))
4588 *pidl
= _ILCreateDesktop();
4589 else if (IsEqualIID(rfid
, &FOLDERID_RecycleBinFolder
))
4590 *pidl
= _ILCreateBitBucket();
4591 else if (IsEqualIID(rfid
, &FOLDERID_ComputerFolder
))
4592 *pidl
= _ILCreateMyComputer();
4593 else if (IsEqualIID(rfid
, &FOLDERID_PrintersFolder
))
4594 *pidl
= _ILCreatePrinters();
4595 else if (IsEqualIID(rfid
, &FOLDERID_ControlPanelFolder
))
4596 *pidl
= _ILCreateControlPanel();
4597 else if (IsEqualIID(rfid
, &FOLDERID_NetworkFolder
))
4598 *pidl
= _ILCreateNetwork();
4599 else if (IsEqualIID(rfid
, &FOLDERID_Documents
))
4600 *pidl
= _ILCreateMyDocuments();
4603 DWORD attributes
= 0;
4607 hr
= SHGetKnownFolderPath(rfid
, flags
, token
, &pathW
);
4611 hr
= SHILCreateFromPathW(pathW
, pidl
, &attributes
);
4612 CoTaskMemFree(pathW
);
4616 return *pidl
? S_OK
: E_FAIL
;
4619 HRESULT WINAPI
SHGetKnownFolderItem(REFKNOWNFOLDERID rfid
, KNOWN_FOLDER_FLAG flags
, HANDLE hToken
,
4620 REFIID riid
, void **ppv
)
4622 PIDLIST_ABSOLUTE pidl
;
4625 TRACE("%s, 0x%08x, %p, %s, %p\n", debugstr_guid(rfid
), flags
, hToken
, debugstr_guid(riid
), ppv
);
4627 hr
= SHGetKnownFolderIDList(rfid
, flags
, hToken
, &pidl
);
4634 hr
= SHCreateItemFromIDList(pidl
, riid
, ppv
);
4635 CoTaskMemFree(pidl
);
4639 static void register_system_knownfolders(void)
4643 for (i
= 0; i
< ARRAY_SIZE(CSIDL_Data
); ++i
)
4645 const CSIDL_DATA
*folder
= &CSIDL_Data
[i
];
4647 KNOWNFOLDER_DEFINITION kfd
;
4649 /* register_folder won't modify kfd, so cast away const instead of
4651 kfd
.category
= folder
->category
;
4652 kfd
.pszName
= (WCHAR
*)folder
->name
;
4653 kfd
.pszDescription
= NULL
;
4654 kfd
.fidParent
= folder
->parent
? *folder
->parent
: GUID_NULL
;
4655 kfd
.pszRelativePath
= (WCHAR
*)folder
->path
;
4656 kfd
.pszParsingName
= (WCHAR
*)folder
->parsing
;
4657 kfd
.pszTooltip
= NULL
;
4658 kfd
.pszLocalizedName
= NULL
;
4660 kfd
.pszSecurity
= NULL
;
4661 kfd
.dwAttributes
= folder
->attributes
;
4662 kfd
.kfdFlags
= folder
->flags
;
4663 kfd
.ftidType
= folder
->typeid ? *folder
->typeid : GUID_NULL
;
4664 register_folder(folder
->id
, &kfd
);
4669 HRESULT
SHELL_RegisterShellFolders(void)
4673 hr
= _SHRegisterUserShellFolders(TRUE
);
4675 hr
= _SHRegisterUserShellFolders(FALSE
);
4677 hr
= _SHRegisterCommonShellFolders();
4679 hr
= create_extra_folders();
4681 hr
= set_folder_attributes();
4683 register_system_knownfolders();