windowswinapiwindows-shelluser-profile

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:

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:

enter image description here

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).

enter image description here

Unfortunately that has two drawbacks:

"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:

Use KNOWNFOLDERIDs instead

We'll switch to the modern KNOWNFOLDERS. This way i'll get:

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:

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

  • 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.

    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 IStreams.