查找 Windows 用户的“真实”应用程序数据文件夹?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12771473/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Finding a Windows user's "true" application data folder?
提问by Robert Oschler
I have a Delphi 6 application that, like most Windows applications, reads/writes data to the user's "local application data" folder. I use the code below to determine that folder. Up until now, that code worked for most of my users. I have encountered a user whose local application data is not in the expected folder:
我有一个 Delphi 6 应用程序,与大多数 Windows 应用程序一样,它可以将数据读/写到用户的“本地应用程序数据”文件夹中。我使用下面的代码来确定该文件夹。到目前为止,该代码适用于我的大多数用户。我遇到了一个用户,其本地应用程序数据不在预期文件夹中:
C:\Users\Bob\AppData\Roaming\
Usually the local app data folder resolves to:
通常本地应用程序数据文件夹解析为:
C:\Documents and Settings\Bob\Application Data\
What is odd about this user's particular situation is that several registry keys normally found in HKEY_LOCAL_MACHINE are actually located in HKEY_CURRENT_USER. They are running on Windows 7.
该用户的特殊情况的奇怪之处在于,通常在 HKEY_LOCAL_MACHINE 中找到的几个注册表项实际上位于 HKEY_CURRENT_USER 中。它们在 Windows 7 上运行。
For lack of a better word, is there a way to get the "true" application data for a user so I can navigate this situation better? If it's a matter of intelligently choosing between the CSIDL_APPDATA, CSIDL_COMMON_APPDATA and CSIDL_LOCAL_APPDATA special folders, what is the logic for doing so? As you can tell I'm looking for an all-purpose function that can root out the correct application data folder regardless of the version of Windows the user is running or their specific PC configuration.
由于缺乏更好的词,有没有办法为用户获取“真实”的应用程序数据,以便我可以更好地应对这种情况?如果是在 CSIDL_APPDATA、CSIDL_COMMON_APPDATA 和 CSIDL_LOCAL_APPDATA 特殊文件夹之间进行智能选择,那么这样做的逻辑是什么?正如您所知,我正在寻找一种通用功能,无论用户运行的 Windows 版本如何或其特定的 PC 配置如何,都可以根除正确的应用程序数据文件夹。
I found this Stack Overflow post that seems to have the answer but it is using function from the .NET library and I am using Delphi 6. If this solution answers my question, can someone tell me a quick way to replicate it in Delphi:
我发现这篇 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;
采纳答案by David Heffernan
The .net code you link to uses Environment.SpecialFolder.ApplicationDatawhich is exactly the same as CSIDL_APPDATA. So your code is already equivalent to the .net code to which you link. And these both refer to the same location as FOLDERID_RoamingAppData.
您链接到的 .net 代码使用Environment.SpecialFolder.ApplicationData的与CSIDL_APPDATA. 因此,您的代码已经等同于您链接到的 .net 代码。这些都指的是与 相同的位置FOLDERID_RoamingAppData。
Take a look at the documentation for FOLDERID_RoamingAppData. It says:
看一看文档FOLDERID_RoamingAppData。它说:
Default Path %APPDATA% (%USERPROFILE%\AppData\Roaming) Legacy Default Path %APPDATA% (%USERPROFILE%\Application Data)
The "Default Path" is what you will see on Vista or later. The "Legacy Path" is what you see on XP.
“默认路径”是您将在 Vista 或更高版本上看到的内容。“传统路径”是您在 XP 上看到的内容。
The different behaviour that you have observed is nothing more than the expected difference between XP and Vista/7/8.
您观察到的不同行为只不过是 XP 和 Vista/7/8 之间的预期差异。
On my Windows machine,
在我的 Windows 机器上,
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
evaluates to
评估为
C:\Users\heff\AppData\Roaming
In other words, your code is already doing the right thing. You do not need to make any changes to it at all. Carry on using GetSpecialFolderLocation(CSIDL_APPDATA).
换句话说,您的代码已经在做正确的事情。您根本不需要对其进行任何更改。继续使用GetSpecialFolderLocation(CSIDL_APPDATA)。
What is odd about this user's particular situation is that several registry keys normally found in HKEY_LOCAL_MACHINE are actually located in HKEY_CURRENT_USER.
该用户的特殊情况的奇怪之处在于,通常在 HKEY_LOCAL_MACHINE 中找到的几个注册表项实际上位于 HKEY_CURRENT_USER 中。
That's not uncommon. Quite often applications configure default settings in HKLMand then copy them to HKCUwhen the application is first run. Without knowing more details of the settings in question it's hard to comment on that aspect of your question.
这并不少见。应用程序经常配置默认设置HKLM,然后HKCU在应用程序首次运行时将它们复制到。在不了解相关设置的更多细节的情况下,很难对您问题的这一方面发表评论。
回答by Remy Lebeau
If it's a matter of intelligently choosing between the CSIDL_APPDATA, CSIDL_COMMON_APPDATA and CSIDL_LOCAL_APPDATA special folders, what is the logic for doing so?
如果是在 CSIDL_APPDATA、CSIDL_COMMON_APPDATA 和 CSIDL_LOCAL_APPDATA 特殊文件夹之间进行智能选择,那么这样做的逻辑是什么?
Yes, it is just a matter of that. Your code is already working as expected.
是的,这只是一个问题。您的代码已经按预期工作。
CSIDL_APPDATA(FOLDERID_RoamingAppData) is for data that is accessible to the calling thread's current user account (which can be impersonated) on multiple machines (hense "roaming" data).
CSIDL_APPDATA( FOLDERID_RoamingAppData) 用于调用线程的当前用户帐户(可以模拟)在多台机器上访问的数据(hense“漫游”数据)。
CSIDL_LOCAL_APPDATA(FOLDERID_LocalAppData) is for data that is accessible to the calling thread's current user account on the local machine only (hense "local" data).
CSIDL_LOCAL_APPDATA( FOLDERID_LocalAppData) 用于仅在本地计算机上调用线程的当前用户帐户可访问的数据(“本地”数据)。
CSIDL_COMMON_APPDATA(FOLDERID_ProgramData) is for data that is accessible to any user account on the local machine only (not "roaming" data).
CSIDL_COMMON_APPDATA( FOLDERID_ProgramData) 用于仅可由本地计算机上的任何用户帐户访问的数据(不是“漫游”数据)。
回答by Ken White
You can use this (a wrapper). You'll need to add ShlApi to your uses clause. Pass it CSIDL_APPDATAjust like your sample above does. For a list of the various CSIDL_values, see the MSDN page here
您可以使用它(包装器)。您需要将 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;
If you're supporting earlier of Windows (XP and below), which your text appears is the case, you can use SHGetFolderPathinstead:
如果您支持较早版本的 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;
If you're only supporting Vista and higher, you should use SHGetKnownFolderPathinstead, and pass it a KNOWNFOLDERID.
如果您只支持 Vista 及更高版本,则应SHGetKnownFolderPath改为使用,并将KNOWNFOLDERID.
As far as the registry issue, Windows Vista and 7 are much more restrictive about the places a non-Admin user can write to, and one of the places that occurs is in HKLM and HKCR. Many of the items that used to be in those hives are now in HKCU, or are mirrored there.
至于注册表问题,Windows Vista 和 7 对非管理员用户可以写入的位置的限制要多得多,其中发生的位置之一是 HKLM 和 HKCR。过去在这些蜂巢中的许多物品现在都在 HKCU 中,或者在那里进行了镜像。

