查找Windows用户的“真实”应用程序数据文件夹?

时间:2012-10-07 18:18:12

标签: windows delphi winapi special-folders appdata

我有一个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的:

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;

3 个答案:

答案 0 :(得分:8)

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

查看FOLDERID_RoamingAppData的文档。它说:

Default Path        %APPDATA% (%USERPROFILE%\AppData\Roaming)
Legacy Default Path %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。如果不了解有关设置的更多详细信息,则很难对您问题的这一方面发表评论。

答案 1 :(得分:5)

你可以使用它(一个包装器)。您需要将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,或者在那里被反映出来。

答案 2 :(得分:5)

  

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

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

CSIDL_APPDATAFOLDERID_RoamingAppData)用于在多台计算机上调用线程的当前用户帐户(可以模拟)访问的数据(hense“漫游”数据)。

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

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