Recommended installation folders
Many applications that used to write into their own installation folder under C:\Program Files have run into problems when Windows Vista came out. Under Windows Vista and later, it appears that C:\Program Files and its subfolders are read-only, whereas they used to be writable.
Here is the news: This isn't Windows Vista or Windows 7; it has been this way in all Windows NT versions since NT 3.1 back in 1993, and including NT4, 2000, and XP. The only reason most people (and developers) didn't notice this, is that the default login account had Administrator privileges and could therefore write under Program Files.
What changed in Vista is that Microsoft introduced "split" access tokens for Administrators. From Vista onwards, Administrator-level accounts run with a double access token: the usual Admin token with many privileges, but also a normal, much more restricted access token. When an Administrator account logs in under Vista or later, the effective token is the restricted one; only after the UAC prompt for elevated privileges is the full Admin token used, and then only for the current process (and its descendants). The result is that the effective rights of Administrator users are now the same as those of restricted users, which also implies read-only access under Program Files.
Bearing that in mind, the recommended installation locations for application files have always been as follows.
- Program files and read-only data files for 32-bit applications
- Program files and read-only data files for 64-bit applications
- Program files and read-only data files for native applications
- System-wide, user-visible read/write files
- System-wide, user-hidden read/write files
- Per-user visible read/write files
- Per-user hidden read/write files
- Physical locations
- How to apply this to your application
Program files and read-only data files for 32-bit applications
In subfolders of the 32-bit version of C:\Program Files:
InstallMate folder | Target System\Program Files (32-bit)\...etc... |
---|---|
XP path (32-bit system) | C:\Program Files\...etc... |
XP path (64-bit system) | C:\Program Files (x86)\...etc... |
Vista/7 path (32-bit system) | C:\Program Files\...etc... |
Vista/7 path (64-bit system) | C:\Program Files (x86)\...etc... |
Symbolic path | <ProgramFilesFolder>\...etc... |
In your 32-bit code | SHGetFolderPath(CSIDL_PROGRAM_FILES)\...etc... |
In your 64-bit code | SHGetFolderPath(CSIDL_PROGRAM_FILESX86)\...etc... |
Program files and read-only data files for 64-bit applications
In subfolders of the 64-bit version of C:\Program Files:
InstallMate folder | Target System\Program Files (64-bit)\...etc... |
---|---|
XP path (32-bit system) | n/a |
XP path (64-bit system) | C:\Program Files\...etc... |
Vista/7 path (32-bit system) | n/a |
Vista/7 path (64-bit system) | C:\Program Files\...etc... |
Symbolic path | <ProgramFiles64Folder>\...etc... |
In your 32-bit code | n/a |
In your 64-bit code | SHGetFolderPath(CSIDL_PROGRAM_FILES)\...etc... |
Program files and read-only data files for native applications
In subfolders of the native version of C:\Program Files:
InstallMate folder | Target System\Program Files (native)\...etc... |
---|---|
XP path (32-bit system) | C:\Program Files\...etc... |
XP path (64-bit system) | C:\Program Files\...etc... |
Vista/7 path (32-bit system) | C:\Program Files\...etc... |
Vista/7 path (64-bit system) | C:\Program Files\...etc... |
Symbolic path | <ProgramFilesXFolder>\...etc... |
In your code | SHGetFolderPath(CSIDL_PROGRAM_FILES)\...etc... |
System-wide, user-visible read/write files
Under Users\Public\Public Documents or equivalent:
Note: All users can create and write new files and read existing files, but standard Users cannot change, rename, or delete files, unless they were created under their own account.
InstallMate folder | Target System\Users\Public\Public Documents |
---|---|
XP path | C:\Documents and Settings\All Users\Shared Documents |
Vista/7 path | C:\Users\Public\Public Documents |
Symbolic path | <CommonDocumentsFolder> |
In your code | SHGetFolderPath(CSIDL_COMMON_DOCUMENTS) |
System-wide, user-hidden read/write files
Under ProgramData\Company\Product:
Note: All users can create and write new files and read existing files, but standard Users cannot change, rename, or delete files, unless they were created under their own account.
InstallMate folder | Target System\ProgramData\<Publisher>\<ProductName> |
---|---|
XP path | C:\Documents and Settings\All Users\Application Data\Company\Product |
Vista/7 path | C:\ProgramData\Company\Product |
Symbolic path | <CommonAppDataFolder>\<Publisher>\<ProductName> or <CommonProductAppDataFolder> |
In your code | SHGetFolderPath(CSIDL_COMMON_APPDATA)\Company\Product |
Per-user visible read/write files
Under <UserName>\[My ]Documents (for example, Word documents, Excel spreadsheets, etc.):
InstallMate folder | Target System\Users\Current User\My Documents |
---|---|
XP path | C:\Documents and Settings\<UserName>\Documents |
Vista/7 path | C:\Users\<UserName>\My Documents |
Symbolic path | <PersonalFolder> |
In your code | SHGetFolderPath(CSIDL_PERSONAL) |
Per-user hidden read/write files
Under <UserName>\AppData\Company\Product (for example browser caches, email storage, per-user settings):
InstallMate folder | Target System\Users\Current User\AppData (Roaming)\<Publisher>\<ProductName> |
---|---|
XP path | C:\Documents and Settings\<UserName>\Application Data\Company\Product |
Vista/7 path | C:\Users\<UserName>\AppData\Roaming\Company\Product |
Symbolic path | <AppDataFolder>\<Publisher>\<ProductName> or <ProductAppDataFolder> |
In your code | SHGetFolderPath(CSIDL_APPDATA)\Company\Product |
Note: The <AppDataFolder> used in the table above refers to the roaming application data folder, i.e., the folder that "moves" with the user between computers if the user's account is set up for roaming. This is the folder that you should normally use if you install user-specific application data.
The non-roaming per-user equivalent is the <LocalAppDataFolder>, which does not move with the user to different computers:
InstallMate folder | Target System\Users\Current User\AppData (Local)\...etc... |
---|---|
XP path | C:\Documents and Settings\<UserName>\Application Data\Local Settings\...etc... |
Vista/7 path | C:\Users\<UserName>\AppData\Local\...etc... |
Symbolic path | <LocalAppDataFolder>\...etc... |
In your code | SHGetFolderPath(CSIDL_LOCAL_APPDATA)\...etc... |
In general, you should use the roaming folder <AppDataFolder> for installation purposes. Only use the local version <LocalAppDataFolder> for files that are absolutely meant to be local to the computer. For example, each user's Temp folder appears under <LocalAppDataFolder>.
Physical locations
The exact folder names have changed a bit over time, but the above categories have been present in one form or another since NT 3.1 in 1993. Any naming changes are dealt with by the installer if you use the Symbolic path variables indicated above. See:
Note: Windows 95/98/Me are different and only approximate the NT model. Moreover, those Windows versions have no concept of security and allow access to all aspects of the system. That's what most users and developers grew up with.
How to apply this to your application
So, what you should do depends on your application model and you should ask yourself the following questions:
- If the target computer is shared by different users (i.e., different login accounts), do you need to keep the read/write files of one user separate from all other users? For example, if you were deploying Microsoft Word, then the answer would be Yes -- you don't want user A to have access to user B's private correspondence.
- Must the user be able to select the files in question, for example through a File > Open... or a File Save As... command, or are they more or less hidden implementation details of your application? For example, Microsoft Word document files are user-visible, but Internet Explorer's cache and cookies are not, at least not in the sense that they must be accessible through File > Open... or something like that. Most email clients also use hidden per-user files to store all the mail boxes.
You then get a matrix like this for read/write files:
User-visible? | No | ||
---|---|---|---|
Yes |
*All users can create and write new files, and read existing files, but standard Users cannot change, rename, or delete files, unless they were created under their own account. Writing, renaming, or deleting non-owned files requires Power User or Administrator rights on Windows XP and earlier, or elevated rights on Windows Vista and later.
As a slight variation, some applications start with read-only files that may have to be modified for each user. This may be an Access database or perhaps user preferences. In that case, the usual approach is copy-on-write: The application starts with the system-wide read-only template (for example, under C:\Program Files), but as soon as a user modifies it, the modified copy is written to the user's Application Data area.
Internally, the application then uses this kind of logic:
if (user's Application Data\Company\Product\TheFile exists) then use that file; else use the global read-only file;
If you do this correctly, then you don't need to tweak any folder access rights and your application will also be Windows Logo compliant.
See also:
Information on the Microsoft MSDN web site: