'What folders make up a user's profile
Short version
Is there an IShellItem that corresponds to a user's entire profile?
Or given all known KNOWNFOLDER constants:
- is there a way to know if the KNOWNFOLDER constant is part of a user's profile
- is there a way to enumerate KNOWNFOLDER constants that haven't been invented yet, so i don't miss any?
Long version
If i wanted to backup a user's entire profile, of course i would start with
SHGetFolderPath(CSIDL_PROFILE): "C:\Users\Ian"
that's obvious. That folder will then normally contain:
C:\Users\Ian
╰── AppData
├── Local
├── LocalLow
╰── Roaming
Some of these other folders already exist as their own CSIDL constants
C:\Users\Ian CSIDL_Profile
╰── AppData
├── Local CSIDL_Local_AppData
├── LocalLow
╰── Roaming CSIDL_AppData
There are also other profile folders that sometimes appear in the Profile folder:
C:\Users\Ian CSIDL_Profile
├── Desktop CSIDL_DesktopDirectoy
├── Documents CSIDL_Personal
├── Pictures CSIDL_MyPictures
├── Music CSIDL_MyMusic
├── Video CSIDL_MyVideo
├── Favorites CSIDL_Favorites
╰── AppData
├── Local CSIDL_Local_AppData
├── LocalLow
╰── Roaming CSIDL_AppData
But these folders don't have to be under %USERPROFILE%
Windows allows users to configure certain special folders to be moved to custom locations:
That means that certain folders can actually exist outside the "Profile" folder:
C:\Users\Ian CSIDL_Profile
╰── AppData
├── Local CSIDL_Local_AppData
╰── LocalLow
D:\Users\Ian
├── Desktop CSIDL_DesktopDirectoy
├── Documents CSIDL_Personal
├── Pictures CSIDL_MyPictures
├── Music CSIDL_MyMusic
├── Video CSIDL_MyVideo
├── Favorites CSIDL_Favorites
╰── AppData
╰── Roaming CSIDL_AppData
And there are a whole slew of CSIDL values that i do not know if they can, or cannot, either through a UI, group policy, or otherwise be moved to other locations:
C:\Users\Ian CSIDL_Profile
╰── AppData
├── Local CSIDL_Local_AppData
│ ├── Microsoft\Windows\History CSIDL_HISTORY
│ ├── Microsoft\Windows\Temporary Internet Files CSIDL_INTERNET_CACHE
│ ╰── Microsoft\Windows\Burn\Burn1 CSIDL_CDBURN_AREA
╰── LocalLow
D:\Users\Ian
├── Desktop CSIDL_DesktopDirectoy
├── Documents CSIDL_Personal
├── Pictures CSIDL_MyPictures
├── Music CSIDL_MyMusic
├── Video CSIDL_MyVideo
├── Favorites CSIDL_Favorites
╰── AppData
╰── Roaming CSIDL_AppData
╰── Microsoft
╰── Windows
├── Recent CSIDL_RECENT
├── Send To CSIDL_SENDTO
├── Start Menu CSIDL_STARTMENU
│ ╰── Programs CSIDL_PROGRAMS
│ ├── Startup CSIDL_STARTUP
│ ├── Startup CSIDL_ALTSTARTUP
│ ╰── Administrative Tools CSIDL_ADMINTOOLS
├── Templates CSIDL_TEMPLATES
╰── Cookies CSIDL_TEMPLATES
I don't want to miss folders
With all these CSIDL values, i might miss some folders that make up a user's profile. In my ideal fantasy world, there would be an IShellItem that corresponds virtually to everything in the user's profile.
In the same way that if you look at the This PC folder (CSIDL_DRIVES
) (formerly known as My Computer), it is a virtual shell folder that contains:
This PC
├── 3D Objects
├── Desktop
├── Documents
├── Downloads
├── Music
├── Pictures
╰── Videos
This is great; it is a virtual folder that the contains folders that make up the user's profile (no matter where those folders might actually be).
Unfortunately that has two drawbacks:
it misses some profile folders (e.g. CSIDL_Favorites)
it then continues to include all of My Computer (nee This PC)
This PC ├── 3D Objects ├── Desktop ├── Documents ├── Downloads ├── Music ├── Pictures ├── Videos ├── OS (C:) ├── Develop (D:) ├── DVD RW Drive (E:) ├── BD ROM Drive (F:) ╰── Local Disk (X:)
"So just backup all CSIDLs that represent per-user folders"
I suppose i could then simply look at every CSIDL, cull any IShellItems that are children of another IShellItem (todo: figure out how to do that), and then only backup those:
CSIDL_PROFILE C:\Users\ian
CSIDL_LOCAL_APPDATA C:\Users\ian\AppData\Local
CSIDL_APPDATA C:\Users\ian\AppData\Roaming
CSIDL_NETHOOD C:\Users\ian\AppData\Roaming\Microsoft\Windows\Network Shortcuts
CSIDL_PRINTHOOD C:\Users\ian\AppData\Roaming\Microsoft\Windows\Printer Shortcuts
CSIDL_DESKTOP D:\Users\ian\Desktop
CSIDL_DESKTOPDIRECTORY D:\Users\ian\Desktop
CSIDL_PERSONAL D:\Users\ian\Documents
CSIDL_MYPICTURES D:\Users\ian\Pictures
CSIDL_MYMUSIC D:\Users\ian\Music
CSIDL_MYVIDEO D:\Users\ian\Videos
CSIDL_FAVORITES D:\Users\ian\Favorites
CSIDL_COMMON_FAVORITES D:\Users\ian\Favorites
CSIDL_RECENT d:\Users\ian\AppData\Roaming\Microsoft\Windows\Recent
CSIDL_SENDTO d:\Users\ian\AppData\Roaming\Microsoft\Windows\SendTo
CSIDL_STARTMENU d:\Users\ian\AppData\Roaming\Microsoft\Windows\Start Menu
CSIDL_PROGRAMS d:\Users\ian\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
CSIDL_STARTUP d:\Users\ian\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
CSIDL_ALTSTARTUP d:\Users\ian\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
CSIDL_ADMINTOOLS d:\Users\ian\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Administrative Tools
CSIDL_TEMPLATES d:\Users\ian\AppData\Roaming\Microsoft\Windows\Templates
CSIDL_COOKIES d:\Users\ian\AppData\Roaming\Microsoft\Windows\Cookies
CSIDL_HISTORY d:\Users\ian\AppData\Local\Microsoft\Windows\History
CSIDL_INTERNET_CACHE d:\Users\ian\AppData\Local\Microsoft\Windows\Temporary Internet Files
CSIDL_CDBURN_AREA C:\Users\ian\AppData\Local\Microsoft\Windows\Burn\Burn1
The problem is that CSIDLs are incomplete (and deprecated). For example:
- there is no CSIDL for Downloads
- there is no CSIDL for 3D Objects
Use KNOWNFOLDERIDs instead
We'll switch to the modern KNOWNFOLDERS. This way i'll get:
- FOLDERID_AccountPictures
- FOLDERID_AppDataDesktop
- FOLDERID_AppDataFavorites
- FOLDERID_AppDataProgramData
- FOLDERID_Objects3D
- FOLDERID_OriginalImages
- snip 34
- FOLDERID_Ringtones
Except KnownFolders doesn't help
My scheme of enumerating all known KNOWNFOLDER constants fails for two reasons.
Any constants that get invented after my application is written will get missed - missing backing up user profile data. Not a great job for a backup application. "All Known Folders on a system can be enumerated."
But even more than that is that i don't know which KNOWNFOLDERS are per-user. For example:
- FOLDERID_AppsFolder
- GUID: GUID {1e87508d-89c2-42f0-8a7e-645a0f50ca58}
- Display Name: Applications
- Folder Type: VIRTUAL
- Default Path: Not applicable—virtual folder
Are Apps per-user? Just because a folder doesn't have a file-system path, doesn't mean it doesn't exist, or that i can't read it, or that i can't enumerate its files, or that i can't backup its content
When using the modern (i.e. Windows 95) Shell API for enumerating files and folders, you can read these files just fine.
Plug your cellphone in via USB to your PC. You can browse the files, and enumerate them with the IShellItem api - even though they don't have a filesystem path.
Summary
Is there a shell virtual folder that corresponds to everything related to a user's profile?
Solution 1:[1]
I don't think a folder with all the users special folders exists, the closest you get is the FOLDERID_UsersFiles
folder but I think this is pretty much the same as just viewing the profile folder.
Known folders can be created by 3rd-party applications, see IKnownFolderManager::RegisterFolder
:
Used particularly by independent software vendors (ISVs) that are adding one of their own folders to the known folder system.
This means you will never be able to make a list of all of them, already invented or otherwise.
I can think of 3 possible ways I would consider to handle this and they all involve using IKnownFolderManager
to enumerate the installed known folders.
IKnownFolder::GetCategory
and look forKF_CATEGORY_PERUSER
folders.Per-user folders are those stored under each user's profile and accessible only by that user.
(I think they really mean folders that by default are stored in the users profile.)
IKnownFolder::GetFolderDefinition
to find the parent folder and walk the parents tree to see if it ends inFOLDERID_Profile
.IKnownFolder::GetPath(KF_FLAG_DEFAULT_PATH,...)
and check if this path is inside the users profile. I see no reason to choose this method.
In most cases the first two methods should give the same results but it does depend on how they are registered. A per-user category folder could in theory live outside the profile folder by default AFAIK and a virtual folder could perhaps have the profile folder as its parent. Using tools like Known Folders Browser or Known Folder Info might be helpful to visualize these differences.
This does not cover most virtual folders like FOLDERID_AppsFolder
but I'm not sure if virtual folders are something you should be backing up.
Virtual folders that display content that is local to the machine is most likely stored somewhere in the users profile (%AppData%?) or in the registry and you are already backing up those folders.
Virtual folders that display content from remote machines (FTP, WebDAV, Gmail etc) might not be something you should be backing up without special confirmation/selection by the user?
Virtual folders that display content from hardware plugged into the machine is not really a part of the users profile IMHO.
Even if you decide that you want to backup virtual folders, how are you going to do it? Are you just going to store the PIDL? Or are you going to ask for a IStream
for each item and store that? The PIDL format might only be known by that specific IShellFolder
class and it might be problematic to make sense of the IStream
when you don't have a instance of that IShellFolder
when viewing backed-up data in your backup program. You would only be able to restore the data to a machine that has that IShellFolder
class available, and even then, it might not support writing IStream
s.
Solution 2:[2]
Is there a shell virtual folder that corresponds to everything related to a user's profile?
AFAIK, no, there is not.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Remy Lebeau |