关于C#:SHGetFolderPath已弃用:检索Windows文件夹路径的替代方法是什么?

SHGetFolderPath Deprecated: What is alternative to retrieve path for Windows folders?

从Windows Vista开始不推荐使用SHGetFolderPath()函数:http://msdn.microsoft.com/zh-cn/library/bb762181(v = VS.85).aspx

在Windows中检索应用程序文件夹路径的替代方法是什么?

1
SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szPath)

除此之外,为什么在使用此功能时出现这些错误:

1
2
3
Error   1   error C2065: 'CSIDL_COMMON_APPDATA' : undeclared identifier

Error   2   error C3861: 'SHGetFolderPath': identifier not found


替代方法在链接到的文档中进行了描述。即它是SHGetKnownFolderPath

但是,SHGetKnownFolderPath仅在Vista或更高版本上可用。因此,如果使用加载时间链接,并在XP上运行一个调用SHGetKnownFolderPath的程序,则该程序将无法启动。如果您希望支持XP,这显然是一个问题。

现在,您可以切换到SHGetKnownFolderPath的运行时链接。在调用它之前执行版本检查,如果该功能不可用,则退回到SHGetFolderPath

就个人而言,我不会让这种贬值过分担心您。 Microsoft以保持向后兼容性而闻名。不要指望SHGetFolderPath很快就会消失。您会发现Windows 8中存在SHGetFolderPath,并且我希望它在现在的10年后的Windows中仍然存在。我的建议是坚持加载时间链接,只有在放弃支持XP时才切换到SHGetKnownFolderPath

您在编辑中提出的另一个问题是如何调用SHGetFolderPath。您需要遵守在问题中链接到的MSDN文档主题底部的要求。具体来说,包括Shlobj.h并将Shlobj.lib传递给链接器。


它被链接到顶部的SHGetKnownFolderPath。

在新API中,CSIDL_COMMON_APPDATA被FOLDERID_ProgramData替换。


当我向已经工作的解决方案中添加几个新的头文件时,我遇到了同样的错误。

我已经在调用SHGetFolderPath,并且还包含了#include <ShlObj.h>,但是它在另一个头文件中。在向其添加新库头文件之前,该解决方案在编译时没有任何错误。

我尝试用SHGetKnownFolderPath()替换SHGetFolderPath(),但这只是将未找到的标识符错误重定向到SHGetKnownFolderPath

On adding #include to the header file of the class calling SHGetFolderPath, the
errors ceased and the solution compiled successfully again.

如本页面所述,在Windows Vista或更高版本的操作系统上调用SHGetFolderPath,将在内部调用SHGetKnownFolderPath


在Microsoft中,备用名称为" SHGetKnownFolderPath"
https://docs.microsoft.com/zh-cn/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpatha

从我的angular来看,这些功能适用于c,c和类似语言。
从powershell,我刚刚阅读了注册表:
PS> cd hkcu:\\\\软件\\\\ Microsoft \\\\ Windows \\\\ CurrentVersion \\\\ Explorer \\\\
PS> dir

在这里浏览" Shell文件夹"和" User Shell文件夹"。

btw:这些用于获取值。我说那是相当安全的。设置值时,最好不要直接使用注册表,因为它会破坏您的一天。使用浏览器->这些"目录"的属性来移动它们,也将移动内容。不幸的是,我不知道在Powershell中使用它的钩子。


我已经在Windows 10 PC上将SHGetFolderPath()与Visual Studio 2015 Enterprise一起使用进行了测试,它进行编译并可以很好地找到当前用户的主文件夹。在SHGetFolderPath() SHGetFolderPath函数的Windows Dev Center页面中,有以下注意事项:

Note As of Windows Vista, this function is merely a wrapper for
SHGetKnownFolderPath. The CSIDL value is translated to its associated
KNOWNFOLDERID and then SHGetKnownFolderPath is called. New
applications should use the known folder system rather than the older
CSIDL system, which is supported only for backward compatibility.

正如大卫·赫夫曼(David Heffman)在他的回答中指出的那样,微软有多年保持向后兼容性的历史,特别是当他们可以采用较旧的功能并将其重定向到具有适当参数的新功能时。 CSIDL值似乎具有相应的KNOWNFOLDERID值。请参见带有简短注释和相应的KNOWNFOLDERID值的CSIDL常量表。

该函数的使用示例如下。此用法检索当前用户的用户文件夹(例如Windows 7下的" C:\\\\ Users \\\\ myuser \\\\ Documents"),然后使用PathAppend()函数将文件夹名称添加到路径的末尾。

1
2
3
4
5
6
7
8
9
10
11
TCHAR   achDevice[MAX_PATH];
HRESULT  hr;
// include file ShlObj.h contains list of CSIDL defines however only a subset
// are supported with Windows 7 and later.
// for the 3rd argument, hToken, can be a specified Access Token or SSID for
// a user other than the current user. Using NULL gives us the current user.
if (SUCCEEDED(hr = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, achDevice))) {
    // append a folder name to the user's Documents directory.
    // the Path Handling functions are pretty handy.
    PathAppend(achDevice, L"xxx");
}

一个可能的失败是一个或多个无效参数(hr == E_INVALIDARG)。返回值S_OK表示调用成功。

有一些CSIDL常量可用于通过使用按位或运算符来修改诸如CSIDL_FLAG_CREATE之类的函数的结果。我不确定这些操作员在Windows 7及更高版本上的运行情况。

Windows 7和更高版本对受支持的CSIDL常量有限制。看起来在Active Directory或类似环境中的复杂,远程安装,重定向和/或共享文件夹中,可能还需要解决一些问题。

另请参阅KNOWNFOLDERID,其中包括一个表,该表指示CSIDLSHGetFolderPath()的某些限制。 CSIDL常量表中的一些示例可能会有用。

1
2
3
4
5
6
7
8
CSIDL_LOCAL_APPDATA - %USERPROFILE%\\AppData\\Local
CSIDL_MYDOCUMENTS - %USERPROFILE%\\Document
CSIDL_PERSONAL -    %USERPROFILE%\\Documents
CSIDL_FONTS -       %windir%\\Fonts
CSIDL_MYMUSIC -     %USERPROFILE%\\Music
CSIDL_MYPICTURES -  %USERPROFILE%\\Pictures
CSIDL_COMMON_APPDATA - %ALLUSERSPROFILE% (%ProgramData%, %SystemDrive%\\ProgramData)
CSIDL_COMMON_DOCUMENTS -    %PUBLIC%\\Documents

顺便说一句,Shell路径处理函数是一个很好的方法库,用于处理文件路径。

另请参阅将通用可写应用程序文件放在何处?