10

我有一个 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。如果这个解决方案回答了我的问题,有人可以告诉我在 Delphi 中复制它的快速方法:

如何获取当前用户的“应用程序数据”文件夹的路径?

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

3 回答 3

8

您链接到使用的 .net 代码与 .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应用程序首次运行时。在不了解相关设置的更多详细信息的情况下,很难对问题的这方面发表评论。

于 2012-10-07T18:42:29.107 回答
5

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

是的,这只是一个问题。您的代码已经按预期工作。

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

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

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

于 2012-10-08T22:21:12.553 回答
5

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

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 中,或者在那里镜像。

于 2012-10-07T18:41:12.133 回答