【问题标题】:Finding a Windows user's "true" application data folder?查找 Windows 用户的“真实”应用程序数据文件夹?
【发布时间】:2012-09-28 02:22:00
【问题描述】:

我有一个 Delphi 6 应用程序,与大多数 Windows 应用程序一样,它读取/写入数据到用户的“本地应用程序数据”文件夹。我使用下面的代码来确定该文件夹。到目前为止,该代码对我的大多数用户都有效。我遇到了一个用户,其本地应用程序数据不在预期的文件夹中:

C:\Users\Bob\AppData\Roaming\

通常本地应用数据文件夹解析为:

C:\Documents and Settings\Bob\Application Data\

这个用户的特殊情况奇怪的是,通常在 HKEY_LOCAL_MACHINE 中找到的几个注册表项实际上位于 HKEY_CURRENT_USER 中。它们在 Windows 7 上运行。

由于缺乏更好的词,有没有办法为用户获取“真实”应用程序数据,以便我可以更好地驾驭这种情况?如果是在 CSIDL_APPDATA、CSIDL_COMMON_APPDATA 和 CSIDL_LOCAL_APPDATA 特殊文件夹之间进行智能选择,这样做的逻辑是什么?如您所知,我正在寻找一种通用功能,该功能可以根除正确的应用程序数据文件夹,而不管用户正在运行的 Windows 版本或其特定的 PC 配置如何。

我发现这个 Stack Overflow 帖子似乎有答案,但它使用的是 .NET 库中的函数,我使用的是 Delphi 6。如果这个解决方案回答了我的问题,有人可以告诉我一个快速复制它的方法德尔福:

How can i get the path of the current user's "Application Data" folder?

// Function to get the app data special folder.
function GetAppdataFolder: string;
begin
   Result := GetSpecialFolderLocation(CSIDL_APPDATA);
end;

【问题讨论】:

  • @SertacAkyuz - 问题的真正原因是用户需要以管理员权限安装我的程序,这在大多数用户的系统上不会发生。为了公平对待那些已经回答过原帖的人,我将帖子恢复为原始形式并为新问题创建了一个新帖子:stackoverflow.com/questions/12772615/…
  • GetSpecialFolderLocation 在哪里? (我应该在我的使用条款中添加哪个单位?)

标签: windows delphi winapi special-folders appdata


【解决方案1】:

您链接到的 .net 代码使用 Environment.SpecialFolder.ApplicationData,这与 CSIDL_APPDATA 完全相同。因此,您的代码已经等同于您链接到的 .net 代码。并且它们都指向与FOLDERID_RoamingAppData 相同的位置。

查看FOLDERID_RoamingAppData 的文档。它说:

默认路径 %APPDATA% (%USERPROFILE%\AppData\Roaming) 旧版默认路径 %APPDATA% (%USERPROFILE%\Application Data)

“默认路径”是您将在 Vista 或更高版本上看到的内容。 “传统路径”就是您在 XP 上看到的。

您观察到的不同行为只不过是 XP 和 Vista/7/8 之间的预期差异。

在我的 Windows 机器上,

Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)

计算为

C:\Users\heff\AppData\Roaming

换句话说,您的代码已经在做正确的事情。您根本不需要对其进行任何更改。继续使用GetSpecialFolderLocation(CSIDL_APPDATA)


这个用户的特殊情况奇怪的是,通常在 HKEY_LOCAL_MACHINE 中找到的几个注册表项实际上位于 HKEY_CURRENT_USER 中。

这并不罕见。应用程序经常在HKLM 中配置默认​​设置,然后在应用程序首次运行时将它们复制到HKCU。在不了解相关设置的更多详细信息的情况下,很难对您问题的这方面发表评论。

【讨论】:

  • 我回答了你提出的问题。您的更新可能与 XP 上不存在的 UAC 有关。我认为完全改变这样的问题是不公平的。我为这个答案付出了很多努力。我认为您应该回复问题,接受答案并提出新问题。有很多不在这里的细节。
  • 在按照您的要求介绍管理员权限问题之前,我已将帖子恢复为原始形式。
  • 这只是一个简单的错误。我本来打算接受你的回答。它已修复。
  • @SertacAkyuz - 我明白了。当我剪掉用于启动新线程的文本时,我无意中剪掉了代码 sn-p。我可以看到这是多么令人困惑。对于那个很抱歉。它已恢复。
  • @David:记录一下:我们确实收到了来自 Vista/7 计算机的崩溃报告,其中 "ShGetFolderPath(0, CSIDL_APPDATA, 0, shgfp_Type_Current, Path)" 实际上确实返回了 "C:\Users\heff \Application Data”而不是“C:\Users\heff\AppData\Roaming”。我们无法写入该文件夹,因此我们的程序崩溃了。
【解决方案2】:

您可以使用它(包装器)。您需要将 ShlApi 添加到您的 uses 子句中。就像上面的示例一样,传递它CSIDL_APPDATA。有关各种 CSIDL_ 值的列表,请参阅 MSDN page here

function GetShellFolder(CSIDLFolder : integer) : string;
begin
  SetLength(Result, MAX_PATH);
  SHGetSpecialFolderPath(0, PChar(Result), CSIDLFolder, false);
  SetLength(Result, StrLen(PChar(Result)));
  if (Result <> '') then
    Result  := IncludeTrailingBackslash(Result);
end;

如果您支持较早版本的 Windows(XP 及更低版本),您的文本显示就是这种情况,您可以改用 SHGetFolderPath

function GetFolderPath(Wnd: HWnd; CSIDLFolder: Integer): string;
begin
  SetLength(Result, MAX_PATH);
  Result := SHGetFolderPath(Wnd, CSIDLFolder, nil, 0, PChar(Result);
  SetLength(Result, StrLen(PChar(Result)));
end;

如果您只支持 Vista 及更高版本,则应改用 SHGetKnownFolderPath,并将其传递给 KNOWNFOLDERID

就注册表问题而言,Windows Vista 和 7 对非管理员用户可以写入的位置的限制要大得多,其中发生的地方之一是 HKLM 和 HKCR。以前在这些蜂箱中的许多物品现在都在 HKCU 中,或者在那里镜像。

【讨论】:

  • 问题不在于使用哪个CSIDL 而不是如何将其转换为路径?在我看来,罗伯特似乎已经知道如何将 CSIDL 转换为路径。还是我读错了?
  • 我认为你读错了。他的文字似乎表明他没有读取路径(他在推测位置),因此在 Win7 上的数据位于错误位置的用户遇到问题。他说他无法使用他找到的解决方案,因为它来自 .NET,而且他正在使用 Delphi。
  • 我将问题中的代码视为当前正在使用的代码。然后是对CSIDL_COMMON_APPDATACSIDL_LOCAL_APPDATA 的引用。罗伯特正在询问使用哪个。至少我是这么读的。我认为罗伯特正在使用 JEDI 库中的GetSpecialFolderLocation。我认为罗伯特使用的是 XP 机器,并且无法识别 MS 在 Vista 中重新组织的配置文件文件夹。他认为不同的路径表明的远不止这些。
  • @KenWhite。谢谢你。请在原帖中查看我最近的更新。
【解决方案3】:

如果是在 CSIDL_APPDATA、CSIDL_COMMON_APPDATA 和 CSIDL_LOCAL_APPDATA 特殊文件夹之间进行智能选择,这样做的逻辑是什么?

是的,仅此而已。您的代码已按预期运行。

CSIDL_APPDATA (FOLDERID_RoamingAppData) 用于多台机器上调用线程的当前用户帐户(可以模拟)可访问的数据(即“漫游”数据)。

CSIDL_LOCAL_APPDATA (FOLDERID_LocalAppData) 用于仅本地计算机上调用线程的当前用户帐户可访问的数据(即“本地”数据)。

CSIDL_COMMON_APPDATA (FOLDERID_ProgramData) 用于仅本地计算机上的任何用户帐户可访问的数据(不是“漫游”数据)。

【讨论】:

    猜你喜欢
    • 2011-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-03
    相关资源
    最近更新 更多