1#![cfg(windows)]
2
3use std::{
4 ffi::OsString, fmt::Display, os::windows::ffi::OsStringExt, path::PathBuf, ptr::null_mut,
5};
6
7use winapi::{
8 shared::guiddef::GUID,
9 shared::winerror::{E_FAIL, E_INVALIDARG, HRESULT, S_OK},
10 um::{
11 combaseapi::CoTaskMemFree, knownfolders::*, shlobj::SHGetKnownFolderPath,
12 shtypes::REFKNOWNFOLDERID, winbase::lstrlenW, winnt::PWSTR,
13 },
14};
15
16#[derive(Debug)]
18pub enum Error {
19 Virtual,
20 NotFound,
21 InvalidArg,
22 Other(std::io::Error, HRESULT),
23}
24
25impl Display for Error {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 f.write_str(match self {
28 Error::Virtual => "virtual folders have no path",
29 Error::NotFound => "not found",
30 Error::InvalidArg => "invalid arg",
31 Error::Other(_, _) => "other",
32 })
33 }
34}
35
36impl std::error::Error for Error {}
37
38const NOT_FOUND: HRESULT = 0x80070002u32 as i32;
39const CANNOT_FIND_PATH: HRESULT = 0x80070003u32 as i32;
40
41fn raw_known_folder_path(id: REFKNOWNFOLDERID) -> Result<PathBuf, Error> {
42 let mut ptr: PWSTR = null_mut();
43 let ret = unsafe { SHGetKnownFolderPath(id, 0, null_mut(), &mut ptr) };
44 let result = match ret {
45 S_OK => {
46 let len = unsafe { lstrlenW(ptr) } as usize;
47 let path = unsafe { std::slice::from_raw_parts(ptr, len) };
48 let os_str: OsString = OsString::from_wide(path);
49 Ok(PathBuf::from(os_str))
50 }
51 E_FAIL => Err(Error::Virtual),
52 E_INVALIDARG => Err(Error::InvalidArg),
53 NOT_FOUND | CANNOT_FIND_PATH => Err(Error::NotFound),
54 e => Err(Error::Other(std::io::Error::last_os_error(), e)),
55 };
56
57 unsafe { CoTaskMemFree(ptr as *mut _) };
59
60 result
61}
62
63#[inline(always)]
65pub fn known_folder_path(id: FolderId) -> Result<PathBuf, Error> {
66 raw_known_folder_path(&FOLDER_IDS[id as usize])
67}
68
69#[non_exhaustive]
71pub enum FolderId {
72 NetworkFolder = 0,
73 ComputerFolder,
74 InternetFolder,
75 ControlPanelFolder,
76 PrintersFolder,
77 SyncManagerFolder,
78 SyncSetupFolder,
79 ConflictFolder,
80 SyncResultsFolder,
81 RecycleBinFolder,
82 ConnectionsFolder,
83 Fonts,
84 Desktop,
85 Startup,
86 Programs,
87 StartMenu,
88 Recent,
89 SendTo,
90 Documents,
91 Favorites,
92 NetHood,
93 PrintHood,
94 Templates,
95 CommonStartup,
96 CommonPrograms,
97 CommonStartMenu,
98 PublicDesktop,
99 ProgramData,
100 CommonTemplates,
101 PublicDocuments,
102 RoamingAppData,
103 LocalAppData,
104 LocalAppDataLow,
105 InternetCache,
106 Cookies,
107 History,
108 System,
109 SystemX86,
110 Windows,
111 Profile,
112 Pictures,
113 ProgramFilesX86,
114 ProgramFilesCommonX86,
115 ProgramFilesX64,
116 ProgramFilesCommonX64,
117 ProgramFiles,
118 ProgramFilesCommon,
119 UserProgramFiles,
120 UserProgramFilesCommon,
121 AdminTools,
122 CommonAdminTools,
123 Music,
124 Videos,
125 Ringtones,
126 PublicPictures,
127 PublicMusic,
128 PublicVideos,
129 PublicRingtones,
130 ResourceDir,
131 LocalizedResourcesDir,
132 CommonOEMLinks,
133 CDBurning,
134 UserProfiles,
135 Playlists,
136 SamplePlaylists,
137 SampleMusic,
138 SamplePictures,
139 SampleVideos,
140 PhotoAlbums,
141 Public,
142 ChangeRemovePrograms,
143 AppUpdates,
144 AddNewPrograms,
145 Downloads,
146 PublicDownloads,
147 SavedSearches,
148 QuickLaunch,
149 Contacts,
150 SidebarParts,
151 SidebarDefaultParts,
152 PublicGameTasks,
153 GameTasks,
154 SavedGames,
155 Games,
156 SearchMapi,
157 SearchCsc,
158 Links,
159 UsersFiles,
160 UsersLibraries,
161 SearchHome,
162 OriginalImages,
163 DocumentsLibrary,
164 MusicLibrary,
165 PicturesLibrary,
166 VideosLibrary,
167 RecordedTVLibrary,
168 HomeGroup,
169 HomeGroupCurrentUser,
170 DeviceMetadataStore,
171 Libraries,
172 PublicLibraries,
173 UserPinned,
174 ImplicitAppShortcuts,
175 AccountPictures,
176 PublicUserTiles,
177 AppsFolder,
178 StartMenuAllPrograms,
179 CommonStartMenuPlaces,
180 ApplicationShortcuts,
181 RoamingTiles,
182 RoamedTileImages,
183 Screenshots,
184 CameraRoll,
185 SkyDrive,
186 OneDrive,
187 SkyDriveDocuments,
188 SkyDrivePictures,
189 SkyDriveMusic,
190 SkyDriveCameraRoll,
191 SearchHistory,
192 SearchTemplates,
193 CameraRollLibrary,
194 SavedPictures,
195 SavedPicturesLibrary,
196 RetailDemo,
197 Device,
198 DevelopmentFiles,
199 Objects3D,
200 AppCaptures,
201 LocalDocuments,
202 LocalPictures,
203 LocalVideos,
204 LocalMusic,
205 LocalDownloads,
206 RecordedCalls,
207 AllAppMods,
208 CurrentAppMods,
209 AppDataDesktop,
210 AppDataDocuments,
211 AppDataFavorites,
212 AppDataProgramData,
213}
214
215static FOLDER_IDS: &[GUID] = &[
216 FOLDERID_NetworkFolder,
217 FOLDERID_ComputerFolder,
218 FOLDERID_InternetFolder,
219 FOLDERID_ControlPanelFolder,
220 FOLDERID_PrintersFolder,
221 FOLDERID_SyncManagerFolder,
222 FOLDERID_SyncSetupFolder,
223 FOLDERID_ConflictFolder,
224 FOLDERID_SyncResultsFolder,
225 FOLDERID_RecycleBinFolder,
226 FOLDERID_ConnectionsFolder,
227 FOLDERID_Fonts,
228 FOLDERID_Desktop,
229 FOLDERID_Startup,
230 FOLDERID_Programs,
231 FOLDERID_StartMenu,
232 FOLDERID_Recent,
233 FOLDERID_SendTo,
234 FOLDERID_Documents,
235 FOLDERID_Favorites,
236 FOLDERID_NetHood,
237 FOLDERID_PrintHood,
238 FOLDERID_Templates,
239 FOLDERID_CommonStartup,
240 FOLDERID_CommonPrograms,
241 FOLDERID_CommonStartMenu,
242 FOLDERID_PublicDesktop,
243 FOLDERID_ProgramData,
244 FOLDERID_CommonTemplates,
245 FOLDERID_PublicDocuments,
246 FOLDERID_RoamingAppData,
247 FOLDERID_LocalAppData,
248 FOLDERID_LocalAppDataLow,
249 FOLDERID_InternetCache,
250 FOLDERID_Cookies,
251 FOLDERID_History,
252 FOLDERID_System,
253 FOLDERID_SystemX86,
254 FOLDERID_Windows,
255 FOLDERID_Profile,
256 FOLDERID_Pictures,
257 FOLDERID_ProgramFilesX86,
258 FOLDERID_ProgramFilesCommonX86,
259 FOLDERID_ProgramFilesX64,
260 FOLDERID_ProgramFilesCommonX64,
261 FOLDERID_ProgramFiles,
262 FOLDERID_ProgramFilesCommon,
263 FOLDERID_UserProgramFiles,
264 FOLDERID_UserProgramFilesCommon,
265 FOLDERID_AdminTools,
266 FOLDERID_CommonAdminTools,
267 FOLDERID_Music,
268 FOLDERID_Videos,
269 FOLDERID_Ringtones,
270 FOLDERID_PublicPictures,
271 FOLDERID_PublicMusic,
272 FOLDERID_PublicVideos,
273 FOLDERID_PublicRingtones,
274 FOLDERID_ResourceDir,
275 FOLDERID_LocalizedResourcesDir,
276 FOLDERID_CommonOEMLinks,
277 FOLDERID_CDBurning,
278 FOLDERID_UserProfiles,
279 FOLDERID_Playlists,
280 FOLDERID_SamplePlaylists,
281 FOLDERID_SampleMusic,
282 FOLDERID_SamplePictures,
283 FOLDERID_SampleVideos,
284 FOLDERID_PhotoAlbums,
285 FOLDERID_Public,
286 FOLDERID_ChangeRemovePrograms,
287 FOLDERID_AppUpdates,
288 FOLDERID_AddNewPrograms,
289 FOLDERID_Downloads,
290 FOLDERID_PublicDownloads,
291 FOLDERID_SavedSearches,
292 FOLDERID_QuickLaunch,
293 FOLDERID_Contacts,
294 FOLDERID_SidebarParts,
295 FOLDERID_SidebarDefaultParts,
296 FOLDERID_PublicGameTasks,
297 FOLDERID_GameTasks,
298 FOLDERID_SavedGames,
299 FOLDERID_Games,
300 FOLDERID_SEARCH_MAPI,
301 FOLDERID_SEARCH_CSC,
302 FOLDERID_Links,
303 FOLDERID_UsersFiles,
304 FOLDERID_UsersLibraries,
305 FOLDERID_SearchHome,
306 FOLDERID_OriginalImages,
307 FOLDERID_DocumentsLibrary,
308 FOLDERID_MusicLibrary,
309 FOLDERID_PicturesLibrary,
310 FOLDERID_VideosLibrary,
311 FOLDERID_RecordedTVLibrary,
312 FOLDERID_HomeGroup,
313 FOLDERID_HomeGroupCurrentUser,
314 FOLDERID_DeviceMetadataStore,
315 FOLDERID_Libraries,
316 FOLDERID_PublicLibraries,
317 FOLDERID_UserPinned,
318 FOLDERID_ImplicitAppShortcuts,
319 FOLDERID_AccountPictures,
320 FOLDERID_PublicUserTiles,
321 FOLDERID_AppsFolder,
322 FOLDERID_StartMenuAllPrograms,
323 FOLDERID_CommonStartMenuPlaces,
324 FOLDERID_ApplicationShortcuts,
325 FOLDERID_RoamingTiles,
326 FOLDERID_RoamedTileImages,
327 FOLDERID_Screenshots,
328 FOLDERID_CameraRoll,
329 FOLDERID_SkyDrive,
330 FOLDERID_OneDrive,
331 FOLDERID_SkyDriveDocuments,
332 FOLDERID_SkyDrivePictures,
333 FOLDERID_SkyDriveMusic,
334 FOLDERID_SkyDriveCameraRoll,
335 FOLDERID_SearchHistory,
336 FOLDERID_SearchTemplates,
337 FOLDERID_CameraRollLibrary,
338 FOLDERID_SavedPictures,
339 FOLDERID_SavedPicturesLibrary,
340 FOLDERID_RetailDemo,
341 FOLDERID_Device,
342 FOLDERID_DevelopmentFiles,
343 FOLDERID_Objects3D,
344 FOLDERID_AppCaptures,
345 FOLDERID_LocalDocuments,
346 FOLDERID_LocalPictures,
347 FOLDERID_LocalVideos,
348 FOLDERID_LocalMusic,
349 FOLDERID_LocalDownloads,
350 FOLDERID_RecordedCalls,
351 FOLDERID_AllAppMods,
352 FOLDERID_CurrentAppMods,
353 FOLDERID_AppDataDesktop,
354 FOLDERID_AppDataDocuments,
355 FOLDERID_AppDataFavorites,
356 FOLDERID_AppDataProgramData,
357];
358
359#[cfg(test)]
360mod tests {
361 #[test]
362 fn all_ids() {
363 for (i, id) in super::FOLDER_IDS.iter().enumerate() {
364 let path = super::raw_known_folder_path(id);
365 match path {
366 Ok(path) => println!("{}: {}", i, path.display()),
367 Err(err) => println!("{}: {}", i, err),
368 }
369 }
370 }
371}