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

Rob*_*ler 10 windows delphi winapi special-folders appdata

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

C:\Users\Bob\AppData\Roaming\
Run Code Online (Sandbox Code Playgroud)

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

C:\Documents and Settings\Bob\Application Data\
Run Code Online (Sandbox Code Playgroud)

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

由于缺乏更好的词,有没有办法为用户获取"真正的"应用程序数据,以便我可以更好地导航这种情况?如果是在CSIDL_APPDATA,CSIDL_COMMON_APPDATA和CSIDL_LOCAL_APPDATA特殊文件夹之间进行智能选择的问题,那么这样做的逻辑是什么?正如您所知,我正在寻找一个能够根除正确的应用程序数据文件夹的通用功能,无论用户运行的Windows版本或其特定的PC配置如何.

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

如何获取当前用户的"Application Data"文件夹的路径?

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

Dav*_*nan 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)
Run Code Online (Sandbox Code Playgroud)

评估为

C:\Users\heff\AppData\Roaming
Run Code Online (Sandbox Code Playgroud)

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


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

这并不罕见.应用程序通常配置默认设置HKLM,然后HKCU在首次运行应用程序时将其复制到.在不知道有关设置的更多细节的情况下,很难对您问题的这一方面发表评论.


Ken*_*ite 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;
Run Code Online (Sandbox Code Playgroud)

如果您支持早期的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;
Run Code Online (Sandbox Code Playgroud)

如果你只支持Vista及更高版本,你应该使用SHGetKnownFolderPath它,然后传递它KNOWNFOLDERID.

就注册管理机构问题而言,Windows Vista和7对非管理员用户可以写入的位置限制更多,其中一个地方是HKLM和HKCR.过去在这些蜂巢中的许多物品现在都在HKCU中,或者在那里被反映出来.


Rem*_*eau 5

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

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

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

CSIDL_LOCAL_APPDATA(FOLDERID_LocalAppData)用于仅在本地计算机上调用线程的当前用户帐户可访问的数据(hense"local"数据).

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