0

Could someone tell me, why my program writes/reads files to/from both folders after I installed it using VS Setup Projects? On first start, when I launch the program and save something in my program to a file, it writes it to:

C:\Users\UserName\AppData\Local\VirtualStore\Program Files (x86)\Company Name\Program Name\"

After setup "run on system start", I restart the computer and the Program starts, but this time it reads and writes from/into this folder:

C:\Users\UserName\AppData\Local\VirtualStore\Windows\SysWOW64

So that it loads wrong values or nothing on second start. It looks like it depends on how I start the Program, via Desktop Symbol or by Autorun on Systemstart.

How can I prevent this and how do I let the program always read/write from the same folder? I would prefer to save the files always in the root folder, where the exe is (C:\Program Files(x86)\CompanyName\ProgramName).

I think the problem is somewhere in VS Setup Projects or it is because it is a 32bit Application running on a 64bit System. I already looked for solutions in other questions, but it didn't help, instead it didn't read anything. Hope someone can help me, thank you!

That's how I write a file: File.WriteAllText(@"mailstate2", "true"); I don't give a path... I just want it to be saved in the root folder...

Sardar Agabejli
  • 423
  • 8
  • 32
  • 6
    The problem is, you're trying to write software in a way that's been frowned upon for **years**. You program *shouldn't* be writing new files into `C:\Program Files (x86)` on any kind of regular basis. Read up on the different file system locations and what's *meant* to be stored in each one. – Damien_The_Unbeliever Jun 09 '17 at 15:08

2 Answers2

6

You've actually got a couple different things going on here. All are related to how windows runs programs and protects critical portions of the filesystem from malicious tampering.

First off, programs can be started from any directory. If you don't specify a specific location to write the file to, then it will be written relative to whichever directory the program was started from. You can test this by setting up a shortcut to your program and changing the shortcut's 'Start in' property. So, the 'Start in' folder is different in your desktop shortcut from what is used by Autorun.

Second, only Elevated users and processes can actually modify certain windows directories. These include the Program Files, Program Files (x86), and Windows folders, amongst others. If an un-elevated process attempts to write a file into one of these directories, windows automatically redirects them to the same folder under the windows VirtualStore directory. This allows legacy programs that used to read-write from these protected locations to keep working while still protecting executables from being overwritten by malware. In any case, this silent redirection is why your program winds up writing to very strange locations.

Depending on what kind of data you're looking to write there are several locations that would be appropriate to write your data that don't involve the virtual store.

  • If it is data that your user might want to copy to another computer or back up, then it might be appropriate to make a folder in his Documents folder, though personally I hate how many programs do that to me. If you find yourself doing this ask yourself if there's some way you can give the user the option of where to store this data. Maybe through a preference page or first-run configuration.
  • If it is preferences type data that individual computer users may want to customize independently from each other, but they don't need to see or be aware of, then using the user's AppData folder (C:\Users\username\AppData\) is appropriate. Note that the AppData folder contains three different sub-folders: Roaming, Local, and LocalLow. Here's an excellent SuperUser topic on the differences between them.
  • If it is application data that needs to be preserved irrespective of users, then the ApplicationData folder (C:\ProgramData) is appropriate, but you might need to set the permissions on any files\directories you create in there to give all users access to them. Also note that there are security concerns that go along with doing so.

Here's a couple useful links that a quick google search pulled up that might get you started thinking in the right direction.

ashbygeek
  • 759
  • 3
  • 20
  • Whoops, yup. Thanks for the catch! I have fixed it in my answer. – ashbygeek Jun 10 '17 at 01:21
  • 1
    *"If it is data that your user might want to copy to another computer or back up, then…*" consider letting the user choose where to store this data. Defaulting to the Documents folder is correct, but allow more computer-literate users the choice. – Cody Gray - on strike Jun 10 '17 at 10:58
  • 1
    Also, be mindful of the difference between roaming and non-roaming data when you store preferences in `AppData`. Your answer doesn't mention that. – Cody Gray - on strike Jun 10 '17 at 10:59
  • Good points @CodyGray. I've never written anything that needed to make the distinction between Roaming and Non-Roaming so it didn't even cross my mind. I'll update my answer with a note and a link to a pertinent topic on the different AppData options and I'll add your suggestion about the documents folder too. – ashbygeek Jun 10 '17 at 11:18
1

Damien has the main point here: you must be elevated (admin) to write/update files in shared common folders like AppData and program files (and many others too). The other issue is the virtualization that's done so that your program doesn't simply crash when it violates security by doing that - it writes to a virtual store. This is the kind of thing a search will show you:

https://www.curlybrace.com/words/2010/09/09/windows-vista7-file-system-virtualization/

The simple solution to this is to give your program an elevation manifest if it needs to run elevated to write/update files in the AppData folder. This kind of thing:

https://blogs.msdn.microsoft.com/nikhiln/2007/04/19/using-manifests-to-elevate-an-application-in-vista/

although Visual Studio should give you IDE support for a manifest so that your code has requestedExecutionLevel level=“requireAdministrator. It will ask for elevation when it starts, as do all programs on UAC systems that require it.

The presence of a manifest also turns off virtualization, so your app will crash instead of being redirected to virtualstore (if you violate file writes to restricted locations).

If you require limited users to be able to run your app then choose another location for your files, which ashbygeek has referred to.

PhilDW
  • 20,260
  • 1
  • 18
  • 28
  • Would it be enough to run the program as administrator? Now I solved this by savng to "C:\ProgramData\ProgramName\" – Sardar Agabejli Jun 09 '17 at 18:00
  • 1
    Not really enough because if there is a similar issue again with something else you'll get the same problem. If now you don't need admin to run the app because you've moved the file then you should still have a manifest with requestedExecutionLevel = asInvoker because that tells Windows you don't require elevation, and you won't get any virtualstore issues - instead you'll crash, which is what you want, believe it or not :), because that's what caused your original problem. If you'd crashed you'd say "oh, a security issue". – PhilDW Jun 09 '17 at 20:44