哪些文件夹构成了用户的个人资料

时间:2019-04-23 19:27:46

标签: windows winapi windows-shell user-profile

简短版

是否存在与用户的整个个人资料相对应的 IShellItem

或给出所有已知的KNOWNFOLDER常数:

  • 有没有办法知道KNOWNFOLDER常量是否属于用户个人资料
  • 有没有办法枚举尚未发明的KNOWNFOLDER常数,所以我不会错过任何一个吗?

长版

如果我想备份用户的整个个人资料,我当然会以

开头
SHGetFolderPath(CSIDL_PROFILE): "C:\Users\Ian"

很明显。该文件夹通常将包含:

C:\Users\Ian
╰── AppData
    ├── Local
    ├── LocalLow
    ╰── Roaming

其中一些其他文件夹已经作为其自己的 CSIDL 常量

存在
C:\Users\Ian          CSIDL_Profile
╰── AppData               
    ├── Local         
    ├── LocalLow      CSIDL_Local_AppData 
    ╰── Roaming       CSIDL_AppData 

个人资料文件夹中,有时还会出现 其他个人资料文件夹:

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         
    ├── LocalLow      CSIDL_Local_AppData 
    ╰── Roaming       CSIDL_AppData 

但是这些文件夹不必位于%USERPROFILE%下

Windows允许用户配置某些特殊文件夹以将其移动到自定义位置:

enter image description here

这意味着某些文件夹实际上可以存在于“个人资料” 文件夹之外:

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 

有一整套 CSIDL 值,我不知道它们是否可以通过UI,组策略或以其他方式移动到其他位置:

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

我不想错过文件夹

使用所有这些CSIDL值,我可能会错过一些组成用户个人资料的文件夹。在我理想的幻想世界中,会有一个 IShellItem ,它实际上与用户个人资料中的所有内容相对应。

以与查看此PC 文件夹(CSIDL_DRIVESformerly known as My Computer相同的方式,它是一个虚拟外壳包含以下内容的文件夹:

This PC
├── 3D Objects
├── Desktop
├── Documents
├── Downloads
├── Music
├── Pictures
╰── Videos

这太好了;这是一个虚拟文件夹,其中包含构成用户个人资料的文件夹(无论这些文件夹实际位于何处)。

enter image description here

不幸的是,它有两个缺点:

  • 它缺少某些配置文件文件夹(例如CSIDL_Favorites)
  • 然后它继续包含所有我的电脑(请此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:)
    

“因此,只需备份表示每个用户文件夹的所有 CSIDL”

我想我可以然后简单地查看每个CSIDL,剔除属于另一个 IShellItem 子级的 IShellItem (要做的事情:弄清楚如何做到这一点),然后然后只备份那些:

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

问题是CSIDL不完整(不建议使用)。例如:

  • 下载
  • 没有CSIDL
  • 3D对象
  • 没有CSIDL

好的,我将改用现代的 KNOWNFOLDERS

这样我会得到:

  • FOLDERID_AccountPictures
  • FOLDERID_AppDataDesktop
  • FOLDERID_AppDataFavorites
  • FOLDERID_AppDataProgramData
  • FOLDERID_Objects3D
  • FOLDERID_OriginalImages
  • snip 34
  • FOLDERID_铃声

除了KnownFolders没有帮助

我列举所有已知的 KNOWNFOLDER 常量的方案失败有两个原因。

编写我的应用程序后发明的任何常量都将丢失-缺少备份用户配置文件数据。对于备份应用程序来说不是一件好事。

但更重要的是,我不知道哪个已知用户是<用户>每个用户。例如:

  • FOLDERID_AppsFolder
    • GUID :GUID {1e87508d-89c2-42f0-8a7e-645a0f50ca58}
    • 显示名称:应用程序
    • 文件夹类型:虚拟
    • 默认路径:不适用-虚拟文件夹

每个用户应用吗?仅仅因为文件夹没有文件系统路径,并不意味着它不存在,或者我无法读取它,或者我无法枚举其文件,或者我无法备份其内容

使用现代(即Windows 95)Shell API枚举文件和文件夹时,您可以很好地读取这些文件。

通过USB将手机插入PC。您可以浏览文件,并使用 IShellItem API进行枚举-即使它们没有文件系统路径。

摘要

是否存在与用户个人资料相关的所有内容相对应的外壳虚拟文件夹?

2 个答案:

答案 0 :(得分:3)

我认为不存在包含所有用户特殊文件夹的文件夹,最接近的文件夹是FOLDERID_UsersFiles文件夹,但是我认为这与查看配置文件文件夹几乎相同。

已知文件夹可以由第三方应用程序创建,请参见IKnownFolderManager::RegisterFolder

  

特别由将自己的文件夹之一添加到已知文件夹系统的独立软件供应商(ISV)使用。

这意味着您将永远无法列出所有已发明或其他形式的清单。

我可以想到3种可能的解决方法,它们都涉及使用IKnownFolderManager枚举已安装的已知文件夹。

  • IKnownFolder::GetCategory并查找KF_CATEGORY_PERUSER文件夹。

      

    每个用户的文件夹是存储在每个用户的个人资料下并且只能由该用户访问的文件夹。

    (我认为它们实际上是指默认情况下存储在用户个人资料中的文件夹。)

  • IKnownFolder::GetFolderDefinition查找父文件夹,然后遍历父树以查看其是否以FOLDERID_Profile结尾。

  • IKnownFolder::GetPath(KF_FLAG_DEFAULT_PATH,...)并检查此路径是否在用户个人资料内。我认为没有理由选择这种方法。

在大多数情况下,前两种方法应给出相同的结果,但这确实取决于它们的注册方式。理论上,默认情况下,每个用户类别文件夹可以位于配置文件文件夹之外,而AFAIK则可以,而虚拟文件夹则可以将配置文件文件夹作为其父文件夹。使用Known Folders BrowserKnown Folder Info之类的工具可能有助于可视化这些差异。

这并不涵盖大多数虚拟文件夹,例如FOLDERID_AppsFolder,但我不确定是否应该备份虚拟文件夹。

显示计算机本地内容的虚拟文件夹很可能存储在用户配置文件(%AppData%?)或注册表中的某个位置,并且您已经在备份这些文件夹。

显示远程计算机(FTP,WebDAV,Gmail等)中的内容的虚拟文件夹在您未经过用户特殊确认/选择的情况下可能不应该备份吗?

显示来自插入计算机的硬件的内容的虚拟文件夹并不是用户个人资料恕我直言的一部分。

即使您决定要备份虚拟文件夹,也将如何做?您只是要存储PIDL吗?还是要为每个商品索取IStream并将其存储起来?只有特定的IShellFolder类才能知道PIDL格式,并且在查看支持的IStream实例时,如果没有IShellFolder的实例,则可能难以理解IShellFolder备份程序中的数据。您将只能将数据还原到具有该IStream类可用的计算机上,即使那样,它也可能不支持写入#include <stdint.h> #include <stdio.h> // This is typical of the random number generators used in professional games. // It is less "correct" than mersenne twisters, for example, but much faster. inline uint32_t fast_rand(int32_t &seed, uint32_t limit) { // Prevent infinite loops. //if (limit == 0) return 0; // Make a mask that has all 1s in the bottom few bits. // This reduces the number of iterations of the loop to ~1 int leading_zeros = __builtin_clz(limit); int mask = 0xffffffff >> leading_zeros; // Loop until our result is in range using rotate and xor. do { seed = (seed << 1) ^ ((seed >> 31) & 0xa53a9be9); } while ((seed & mask) >= limit); return seed & mask; } int main() { // I'm using two seeds to prevent coupling. // On their own, their quantiles are pretty flat, but // in this example they couple, causing conditioning in the results. int32_t length_seed = (int32_t)0x95abcfad; int32_t swap_seed = (int32_t)0xba7235fab; for (int i = 0; i != 10000000; ++i) { // Note we don't use a std::string. These are very slow. char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; auto num_chars = sizeof(chars) - 1; auto length = fast_rand(length_seed, num_chars-1) + 1; // Trim the string to the right length. chars[length] = 0; // Shuffle the characters. for (int j = 0; j != length; ++j) { int swapper = j + fast_rand(swap_seed, length - j); auto tmp = chars[j]; chars[j] = chars[swapper]; chars[swapper] = tmp; } // Print with puts (not iostreams). puts(chars); } }

答案 1 :(得分:1)

  

是否存在一个外壳虚拟文件夹,该文件夹对应于与用户个人资料相关的所有内容?

AFAIK,不,没有。