find一个Windows用户的“真实”的应用程序数据文件夹?

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

C:\Users\Bob\AppData\Roaming\ 

通常,本地应用程序数据文件夹parsing为:

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

这个用户特殊情况的奇怪之处在于通常在HKEY_LOCAL_MACHINE中find的几个registry项实际上位于HKEY_CURRENT_USER中。 他们在Windows 7上运行。

缺乏一个更好的词,有没有办法让用户“真正”的应用程序数据,所以我可以更好地浏览这种情况? 如果是在CSIDL_APPDATA,CSIDL_COMMON_APPDATA和CSIDL_LOCAL_APPDATA特殊文件夹之间进行智能select,那么这样做的逻辑是什么? 正如您所看到的,我正在寻找一种通用function,无论用户正在运行的Windows版本或其特定的PCconfiguration如何,都可以find正确的应用程序数据文件夹。

我发现这个堆栈溢出post似乎有答案,但它使用.NET库中的函数,我正在使用Delphi 6.如果这个解决scheme回答我的问题,有人可以告诉我一个快速的方法来复制它在Delphi中:

我怎样才能得到当前用户的“应用程序数据”文件夹的path?

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

您链接到的.net代码使用与CSIDL_APPDATA完全相同的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 。 在不了解有关设置的更多细节的情况下,很难评论您的问题。

你可以使用这个(一个包装)。 您需要将ShlApi添加到您的使用条款中。 像上面的示例一样传递它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,或在那里镜像。

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

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

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

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

CSIDL_COMMON_APPDATAFOLDERID_ProgramData )适用于只能在本地计算机上访问的数据(不是“漫游”数据)。