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

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

本文关键字:路径 是什么 方法 文件夹 Windows 检索 SHGetFolderPath      更新时间:2023-10-16

从Windows Vista开始,SHGetFolderPath()函数被弃用:http://msdn.microsoft.com/en-us/library/bb762181%28v=VS.85%29.aspx

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

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

除此之外,为什么我在使用此函数时会出现这些错误:

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很快就会消失。你会发现SHGetFolderPath存在于Windows 8中,我希望它仍然存在于10年后的任何Windows中。我的建议是坚持加载时间链接,只有在放弃支持 XP 时才切换到 SHGetKnownFolderPath

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

它链接在顶部,SHGetKnownFolderPath。

CSIDL_COMMON_APPDATA在新 API 中替换为FOLDERID_ProgramData。

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

我已经在调用SHGetFolderPath并且还包含#include <ShlObj.h>但它在不同的头文件中。解决方案是在我添加新的库头文件之前编译没有任何错误。

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

在将#include <ShlObj.h>添加到调用SHGetFolderPath的类的头文件时,将 错误停止,解决方案再次成功编译。

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

我已经在

Windows 10 PC上使用Visual Studio 2015 Enterprise的SHGetFolderPath()进行了测试,它编译并工作得很好,可以找到当前用户的主文件夹。在 Windows 开发人员中心页面SHGetFolderPath() SHGetFolderPath 函数上有以下注释:

注意:从 Windows Vista 开始,此函数只是 SHGetKnownFolderPath .CSIDL值将转换为其关联的值 KNOWNFOLDERID然后调用SHGetKnownFolderPath。新增功能 应用程序应使用已知的文件夹系统,而不是较旧的文件夹系统 CSIDL系统,仅支持向后兼容。

正如David Heffman在他的回答中指出的那样,Microsoft多年来一直保持向后兼容性,特别是当他们可以使用旧函数并将其重定向到具有适当参数的新函数时。CSIDL值似乎具有相应的KNOWNFOLDERID值。请参阅此表,其中包含带有简短注释和相应KNOWNFOLDERID值的CSIDL常量。

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

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常量可用于修改函数的结果,例如使用按位 OR 运算符修改CSIDL_FLAG_CREATE。我不确定这些操作员在Windows 7及更高版本中的配合情况如何。

Windows 7 及更高版本支持的CSIDL常量存在限制。在 Active Directory 或类似环境中的复杂、远程挂载、重定向和/或共享文件夹中,似乎也可能存在需要克服的问题。

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

CSIDL_LOCAL_APPDATA - %USERPROFILE%AppDataLocal
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 路径处理函数是一个很好的操作文件路径的方法库。

另请参阅将常见的可写应用程序文件放在哪里?

来自微软,altenate是"SHGetKnownFolderPath"https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpatha

在我看来,这些函数适用于 c、c++ 和类似语言。从powershell,我刚刚阅读了注册表:PS> cd hkcu:\Software\Microsoft\Windows\CurrentVersion\Explorer\PS>目录

在这里偷看"外壳文件夹"和"用户外壳文件夹"。

顺便说一句:这些是为了获取值。我会说这是相当安全的。对于设置值,最好不要直接使用注册表,因为它会毁了你的一天。使用这些"目录"的资源管理器 ->属性来移动它们,也会移动内容。不幸的是,我不知道在powershell中使用它的钩子。