Finding a Windows user's "true" application data folder?

Robert Oschler picture Robert Oschler · Oct 7, 2012 · Viewed 10.5k times · Source

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:

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.

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.

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:

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;

Answer

David Heffernan picture David Heffernan · Oct 7, 2012

The .net code you link to uses Environment.SpecialFolder.ApplicationData which 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.

Take a look at the documentation for FOLDERID_RoamingAppData. It says:

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.

The different behaviour that you have observed is nothing more than the expected difference between XP and Vista/7/8.

On my Windows machine,

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).


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.

That's not uncommon. Quite often applications configure default settings in HKLM and then copy them to HKCU when 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.