Where to store Application Data in Windows 7 and Vista - c#

My application needs to, like most, store data. The application was previously used on XP only where it would store the data in Program Files. Now that our customers are moving to Windows 7 I had to upgrade it so that it stored the data in a new folder. I opted for the ApplicationData folder as I thought I would be allowed access without needing UAC at all.
Now on some Windows 7 machines this is fine, but on others access to the folder fails, presumably because of permissions, but when ran with Administrator privelidges the program works fine.
Am I using the wrong folder or are these cases outliers? In either case what is the best practice for this kind of thing?
I am using the following C# SpecialFolder to get the AppData folder location.
System.Environment.SpecialFolder.ApplicationData

System.Environment.SpecialFolder.ApplicationData is per-user and roams. That doesn't sound like what you want. You appear to want machine wide settings and so should use System.Environment.SpecialFolder.CommonApplicationData.
Because CommonApplicationData is shared between all users, the default access control is limited. By default standard users cannot write in this location. The recommended practise is to create a sub-folder of CommonApplicationData at installation time and assign it suitably permissive access control settings.

David is right.
As far I know, there's also some difference if you deploy your app via ClickOnce or Installer: the first allows a few subset of permissions than the normal installer.
I must confess I'm not an expert on that.
Of sure, Program Files is the worst place to store data, even since XP.

Related

System-wide setting in Windows 7 and 8 - Registry is no longer useful?

I want to track a setting system-wide on the target machine- it is a run time counter that keeps track of how many times my client runs my software. I decided to put this value in the registry, but I really want to track how many times it is run for the whole system, not just for the current user account.
I would expect to use HKLM to track this at a machine level, but UAC doesn't like this nowdays.
Is there a correct way to read and write a setting that is machine-wide?
HKLM isn't for this type of use (since Windows XP at least).
Use the %PROGRAMDATA% folder instead (which you can also get via the WinAPI function SHGetKnownFolderPath with FOLDERID_ProgramData (SHGetFolderPath with CSIDL_APPDATA on Windows versions prior to Vista). It's specifically designed for application data that is global to all users of the machine. (On Windows 7, this is the C:\ProgramData folder by default.) Your application should create a directory beneath there and store the counter information in a file in that location instead.
(It also means you don't have to defeat the purpose of UAC by allowing public write access to the registry in inappropriate locations.)
From Environment.SpecialFolder Enumeration:
CommonApplicationData The directory that serves as a common repository for application-specific data that is used by all users.
Have a "CommonApplicationData\Your Company Name\Your Product Name" folder created in your setup program and change the ACL for the folder to allow limited user full control permissions (the inherited permission is read only for limited users). You can do this via the LockPermissions MSI table, or if your setup program does not support LockPermissions, create a custom action to change the ACL.
You also need to handle potential edit conflicts created by fast user switching.

Where is the correct place to store my application specific data?

I'm developing a small C# Winforms game and one of the things I'm wanting to do is save application specific data. However, I'm struggling a bit to understand the correct place this should be stored.
As far as I can see there are several types of data an application might store and accordingly different places for it to be held:
1. Application properties
- Settings such as where the application stores it's data, who the last logged in user was, the default window size, position etc. Is this information suppose to go into app.settings, or perhaps into the registry?
2. Global application data
- This might include sprites and other game assets that are used by every user that runs the application on this machine. Where would this common data be stored? It's worth noting that in my particular case this data will not be provided with a default install and users will be allowed to add their own game assets which should be then available to any other user on the same computer.
3. User specific application data
- This would include a users saved game files, their specific application preferences and their profile information. Where should I be storing this?
Ideally I wish my application to be compatible with Windows XP, Vista, 7 and of course the upcoming Windows 8 - I don't know if this changes the methods but hopefully it will assist with providing advice.
This is my first foray into this kind of development and I would appreciate some 'best practice' advice.
Question 2:
I suggest using a subfolder in Environment.SpecialFolder.CommonAppData (maps to C:\ProgramData on Windows7 by default). This is a hidden folder.
Question 3:
Put those files into Environment.SpecialFolder.AppData(maps to C:\Users\[USERNAME]\AppData\Roaming by default, hidden folder), if you expect that the user does not intend to backup / modify those. Some games also put their save games into Environment.SpecialFolder.MyDocuments, probably because it is easier for users to find them there.
Example code:
var directory = Environment.GetFolderPath(Environment.SpecialFolder.AppData);
using (FileStream fs = File.Create(Path.Combine(directory, "myAppDirectory", "myFile.txt")))
{
// write data
}
For a complete list of special folders on Windows follow the link
SIDENOTES
Users are allowed to move around those directories, so make sure you use the code provided above
There is a bug in Windows 7 x64 regarding CommonAppData directory and the bug gets more severe in Windows 8 x64 CP. I've blogged about this: problems after moving CommonAppData directory on Windows 7 x64 and Windows 8 x64
Application properties - Most application data you described should be specific to each user and put in Environment.SpecialFolder.ApplicationData (the %appdata% environment variable). I would generally avoid putting data in the registry as it is hard to find, edit, and fix. If you do not want data to be associated with the user when they are roaming (maybe the files are big or connected to the computer in someway) then you can put it in Environement.SpecialFolder.LocalApplicationData (the `%localappdata% environment variable).
Global application data - I would put global application data in Environment.SpecialFolder.CommonApplicationData ( the %programdata% environment variable)
User specific application data - Same as #1, except when the data is intended to be easily found by the user (e.g. saved games) in which case it should go in Environment.SpecialFolder.MyDocuments, which has no associated environment variable.
As yas4891 points out you can reliably get these folder paths using Environment.GetFolderPath() using one of the Environment.SpecialFolder` values listed here.

Where should I store a Computer wide license/Computer wide settings?

I've been looking for all most a day now. Is there any place to store a Computer-wide license. I don't want to use the Registry, so don't suggest that.
This license will be installed during the program's runtime, so what I need is a place to store computer wide settings that can have read/write access without running as Admin.
I've looked online, and Microsoft, in their infinite 'wisdom' for security apparently locked down all methods of saving application wide settings.
In Windows 7 I use the hidden ProgramData folder. I have just checked and it is available to users, they just can't see it by default.
I normally use it for storing .ini files in for applications.
Hope that helps

Windows 7 Compatibility Issue in .NET

When we create a SetUp & Deployment project for our application in .net, the default folder for our application to be installed is being set as C:\Program Files.....
Our application will run perfectly if we are using a Windows XP machine. But if we are using a Windows Vista or Windows 7 machine, the application wont run perfectly, especially if we are performing any file operations in our application...
Can anyone find a solution for this problem? Is there any means to penetrate this User Account Control and File Access Controls of Windows 7? or can any1 give a choice to change the default installation folder from [ProgramFilesFolder]\[Manufacturer]\[ProductName] to some other folder?
If your application writes to any files under its install folder (i.e. under Program Files if default path is used), then it is badly written. You shouldn't try to circumvent OS security mechanisms to protect the user from badly written apps; you should rather fix your app so that it works correctly.
And it is, of course, not a .NET issue at all. Any application doing the same thing, no matter which language/framework it's written in, will have the same problem.
You should still install your application in Program Files folder. there are good reasons to have it there - a single copy for all users, in a well known locked place where nobody but an admin can tamper with your binaries.
However, any file operation you are doing should be in one of the standard Windows locations for user-writable files. There are several such folders, depending on the file usage model. You can read more about these in the following SO questions :
My winform app uses xml files to store data, where should I store them so Vista users can write to them?
Vista and ProgramData
Data shared among all users should go in C:\ProgramData (use Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) to find out where it actually lives -- it can be different between Windows versions).
Data specific to the user should be in SpecialFolder.ApplicationData. If the user has a roaming profile, this is shared between machines.
Data specific to the user that's also specific to the machine should be in SpecialFolder.LocalApplicationData.
If you really need to put something in your program's installation directory, you need to do this with Administrator privileges.
You should either do this by prompting for elevation the first time that the program is run. Preferably, you should do this during installation (because you're already elevated).
First of all, you should not set your app to install under C:\Program Files\..., you should instead set it to %PROGRAMFILES%\... While these will usually equate to the same thing, they can be different on a 64 bit system, or they can be wildly different if the system has been set that way.
As already mentioned, don't try to circumvent the UAC, it is there for a reason, and your program is no more special than any other program on the system. Instead what you should do is set your app manifest to demand administrative level permission upon launch (which if granted bypasses the file system virtualization, although the user can decline it or possibly not even have the rights to launch something as admin). The other thing you can do is set the ACLs on the folder that your app sits in, and give all users on the machine read/write access to that folder (this would have to be done at install time).
Or you can do things the proper way and store your data files in the %APPDATA% folder, which you have full rights to, although these folders are specific to each individual user of the system.
I'd suggest start here http://channel9.msdn.com/pdc2008/PC51/
That will give you a good foundation.

Why can't my C# app create files in Windows 7?

I have a C# app that creates a settings file for itself to store the current state of certain visual elements. This app works just fine on any machine that isn't running Windows 7, but on those machines we get an error that the settings file can't be created because the user doesn't have permission. Now, I could fix this issue by going to each computer, logging in as the administrator and giving the user read and write access on the program folder for the application that we've installed, but there has to be a better way.
It seems like in XP, you got write access on the folders you created by default, but that isn't the case anymore. Is there a setting I need in the setup package to make this work?
The point is that you shouldn't be storing settings files in the program folder. Microsoft have advised against this for a long time, but started making things stricter with Vista IIRC.
Use Environment.SpecialFolders.ApplicationData (etc) to find the most appropriate place to put settings. Or use the .NET settings infrastructure which does this automatically for you.
are you trying to create files in the installation folder? you should be using the user data folder for data and not the installation folders. Use the Environment.SpecialFolders.ApplicationData folder to get a folder you can write to.
You're probably running as an administrator on your non-Windows 7 machine which an write anywhere. Be sure to save any per user instance data in their AppData folder (roaming if it should follow them from computer to computer, or local if its a cache or local to taht machine only). If you need to share settings between users, use the C:\ProgramData folder with the appropriate permissions.
A program shouldn't try to store settings in its installation directory.
Be sure to use the SpecialFolders along with Environment.GetFolderPath to get the right locations needed. You should never hard code paths because they can be different between versions AND languages. (I know in the German version of XP it wasn't Program Files but Programme!)
this app works just fine on any machine that isn't running Windows 7
Wrong! It only works on those machines if you run as administrator. I think you'll find your program is broken on Windows XP as well if you try to run it on just about any business computer rather than a home computer.
Instead, this kind of information needs to go in one of the special Application Data folders.
This is a security flaw in your program because your program is writing information to the program directory (which is, and should be, protected.) If it's a situation of correcting the root cause, consider using the SpecialFolder enumeration or the static members on Application like like CommonAppDataPath to write your information to a more appropriate location.
Assuming the typical approach to writing a file via a path, this is a trivial fix and there's no good "expediency" reason to not correct the root cause. If you're not sure about how to manipulate the path, consider using Path.Combine(). It does it for you.
In general, you shouldn't be writing program data to any folder underneath Program Files (even if you created the folder). You should use the Environment.GetFolderPath(...) to figure out where to put your application specific data. You can pass in one of many enums defined here -- you probably want Environtment.SpecialFolder.CommonApplicationData
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
I do not see how any of this is an actaul answer. I need to be able to write a report and have it saved the users documents folder the same folder I used to read the xml files I am writing the report from.

Categories