Where should I store application specific settings? - vb6

I've been asked to update a VB6 application that's been running on WinXP for the last 6 years. The client wants to use Windows 7. Up until now, the app stored its settings in an INI file located in the application directory. One key difference between XP and 7 is that you can't write to C:\Program Files\AppFolder anymore.
I am trying to figure out where on the file system should I store settings? Given that the application is still required to run on WinXP, I am kind of confused.
On WinXP, I have the following:
C:\Documents and Settings\profilename\Application Data
C:\Documents and Settings\profilename\Local Settings\Application Data
On Windows 7, I have the following:
C:\Users\profilename\AppData\Local
C:\Users\profilename\AppData\LocalLow
C:\Users\profilename\AppData\Roaming
Each one of these folders have subfolders that seem to store settings/files for various products
So 2 questions:
Given all these folders, where do I store my settings?
I am assuming that there is a nifty Windows API call that would give me the proper location of this folder. And I am hoping it works on both XP and 7. Is my assumption correct? If so, a link would be much appreciated.

There are a number of special folders you can use, on XP/Vista/Windows 7:
The CSIDL_APPDATA folder is the one you will likely be most interested in. Data stored here is available to roaming users at whatever machine they log in to. This is the best place to store simple configuration data. All users have write access to this (and the last) folder. Note that none of the above folders are for user-generated data! That would properly belong under the My Documents hierarchy.
EDIT: As Cody Gray suggests in the comments, also consider CSIDL_LOCAL_APPDATA for application data that will always be local to the current machine, but is set aside on a per user basis. The data in this folder is not available on a roaming basis, so it should be data that the user will likely not miss if they log in to a different machine.
I shamelessly copied the explanation above from a good article by Karl Peterson, explaining this for VB6 programmers. Karl also has a ready-to-use class that will help you find the directories, but IMHO he's overcomplicated things this time. Bob Riemersma has a better way in one line, using the Shell object, as below. EDIT Bob's comment below explains why it's best to use late binding for this rather than early binding.
Const ssfCOMMONAPPDATA = &H23
Const ssfLOCALAPPDATA = &H1c
Const ssfAPPDATA = &H1a
Dim strAppData As String
strAppData = _
CreateObject("Shell.Application").NameSpace(ssfAPPDATA).Self.Path
In my opinion it's fine to continue to use INI files in these directories.

See the question "Does Microsoft have a best practices document regarding the storage of app data?" for some helpful info.

Maybe you just save your settings in Windows Registry?
That's very easy. Using SaveSeting and GetSetting is much easier than creating INI file.
And there is no trouble in compatibility, from WinNT to Windows 8.

Related

Where is the guideline that says you shouldn't write to the Program Files area?

Many questions on SO say "Windows developer guidelines" or "windows design guidelines" say that you shouldn't write temporary or program data to the Program Files area, but as far as I can tell none of them actually link to a piece of documentation that says as much. Searching the MSDN has yielded me no results. Windows will make the area read-only, so it can be enforced by the OS, but that doesn't mean developers didn't try to write there anyway (e.g., when porting older, XP and earlier based programs forward.)
I realize that it seems odd to ask about it this late into Windows development (since, as a commenter below pointed out, has been enforced by the OS for more than a decade), but a document that says so is sometimes necessary to satisfy people.
With that in mind, Does Microsoft have a document published stating we shouldn't write application data to the Program Files area, and if so, where is it?
From Technical requirements for the Windows 7 Client Software Logo Program:
Install to the correct folders by default
Users should have a consistent and secure experience with the default
installation location of files, while maintaining the option to
install an application to the location they choose. It is also
necessary to store application data in the correct location to allow
several people to use the same computer without corrupting or
overwriting each other's data and settings.
Windows provides specific locations in the file system to store
programs and software components, shared application data, and
application data specific to a user:
Applications should be installed to the Program Files folder by default. User data or application data must never be stored in this
location because of the security permissions configured for this
folder (emphasis added)
All application data that must be shared among users on the computer should be stored within ProgramData
All application data exclusive to a specific user and not to be shared with other users of the computer must be stored in
Users\<username>\AppData
Never write directly to the "Windows" directory and or subdirectories. Use the correct methods for installing files, such as
fonts or drivers
In “per-machine” installations, user data must be written at first run and not during the installation. This is because there is no
correct user location to store data at time of installation. Attempts
by an application to modify default association behaviors at a machine
level after installation will be unsuccessful. Instead, defaults must
be claimed on a per-user level, which prevents multiple users from
overwriting each other's defaults.
And I'm quite sure that there's similar stuff for every Windows version of the NT family going back to Windows NT 4 or even earlier.
See also this question.
Edit: the original link in this post to the Windows 7 Logo program exists no more. Here you find the current link to the Certification requirements for Windows Desktop Apps. See Section 10, Apps must install to the correct folders by default
In later versions of windows (Vista, 7 and of course server versions) access permission are restricted for "special folders" including "Program Files". Even if your program is elevated to have sufficient privileges to write to this folder it is still a bad idea.
I don't know of any guidelines that state this but there is a list of special folders and what they are meant for. The fact that there is a special folder for nearly all types of data I can image means there is no need to use the program files folder.

In Windows is any folder alternative to ProgramData?

I'm writing a desktop app and need a folder which...
Exists in Windows 7 and Vista
Is common to all users (for store config data).
Application can save data on it, without Admin privileges (not like "ProgramData").
is standard (I don't want to create another app specific folder in "C:", the Desktop or other place alike.)
"Program Files" is not an option, of course.
Can you suggest an appropriate folder, or better use the Registry?
The recommended way to do this is to create a folder at install time, dedicated to your application, underneath "ProgramData" (i.e. CSIDL_COMMON_APPDATA/FOLDERID_ProgramData).
As you already know, the CSIDL_COMMON_APPDATA folder is read only for standard users. So your install program needs to give the folder that it creates an ACL that permits the access that you require.
This is the solution that meets all the criteria laid out in your bullet points.
You mention the registry. There is no area of the registry that is shared between all users and yet writeable by standard users. Whilst you can use ACLs to grant more permissive access rights to the registry, it is really not the done thing. Please forget that I even mentioned this possibility!
IF your app is .NET then use CommonApplicationData - you can get the real location by calling GetFolderPath.
EDIT - as per comments:
You need to setup ACL correctly - for sample source code on how to do this see http://www.codeproject.com/Tips/61987/Allow-write-modify-access-to-CommonApplicationData
What about Public User directories? For Example: C:\Users\Public\Libraries or C:\Users\Public\Documents
I've noticed these folder on several of my Windows 7 machines. I'm not sure if it is always there, but might be an option. I was hoping for something like an %appdata% for the Public User, but the closest thing I found was Public\Libraries.
(As a side note, it appears C:\Users\Public\Desktop does require admin to write to.)
what about using %APPDATA%/Company/Product for the directory?

Does Windows 7 restrict folder access as Vista does?

I noticed that in my application, most compatibility problems were caused by 'access denied' for some folders, such as:
Application Data [C:\ProgramData]
Desktop [C:\Users\Public\Desktop]
Documents [C:\Users\Public\Documents]
Favorites [C:\Users\Public\Favorites]
Start Menu [C:\ProgramData\Microsoft\Windows\Start Menu]
Templates [C:\ProgramData\Microsoft\Windows\Templates]
Does Windows 7 have the same problem as Vista?
With help from the members of Stack Overflow, I know that on Vista I can use CSIDL_APPDATA to enable the file access without UAC problems or 'access denied' errors.
Is this also valid for Windows 7?
It's not a "problem", it's a feature. It's called User Account Control (UAC), and it's one of the ways that system security was tightened under Windows Vista. Windows 7 indeed retains a similar security model.
There's absolutely no reason that your application should need to mess with system folders in the first place. As you've already learned, Windows provides a number of locations for applications to store data, both temporarily and permanently. Microsoft has been recommending for a long time that you take advantage of these folders: they were the preferred location for storing data even under previous versions of Windows. The fact that you ignored this advice, yet your application continued to work, was actually the bug. The fact that later versions of Windows finally closed that security vulnerability, thus breaking your application, should be neither unexpected nor unappreciated.
You can find more information about where to store your data on this page. Also see this blog article, which attempts to summarize the array of technical documentation into a handy table. And as always, Raymond Chen provides a simple, yet instructive, overview of the differences between the locations:
The most important difference between My Documents and Application Data is that My Documents is where users store their files, whereas Application Data is where programs store their files.
In other words, if you put something in CSIDL_MYDOCUMENTS (My Documents), you should expect the user to be renaming it, moving it, deleting it, emailing it to their friends, all the sorts of things users do with their files. Therefore, files that go there should be things that users will recognize as "their stuff". Documents they've created, music they've downloaded, that sort of thing.
On the other hand, if you put something in CSIDL_APPDATA (Application Data), the user is less likely to be messing with it. This is where you put your program's supporting data that isn't really something you want the user messing with, but which should still be associated with the user. High score tables, program settings, customizations, spell check exceptions...
There is another directory called CSIDL_LOCAL_APPDATA (Local Settings\Application Data) which acts like CSIDL_APPDATA, except that it does not get copied if the user profile roams. (The "Local Settings" branch is not copied as part of the roaming user profile.) Think of it as a per-user-per-machine storage location. Caches and similar non-essential data should be kept here, especially if they are large. Other examples of non-roaming per-user data are your %TEMP% and Temporary Internet Files directories.

How do I update a VB6 app from XP to Vista?

I work on a vb6 application which is having problems with Vista, for the obvious reasons (writing to program files, and other things that are no longer allowed by default).
Where should I store application data or user's saved files?
Do I need priviledges to create folders and files, there, too?
What other common actions will cause problems?
The program has an updater which must download and register files, how do I elevate priviledges when this occurs?
Some of these questions have obvious answers, but I want to get the obvious stuff right.
Depending upon what you are doing, you might be in for a world of pain. There are no hard and fast answers to any of those questions, but from someone who is going through the same issues right now, here's what I know.
1) Where should I store application data or user's saved files?
This depends on what you are wanting to do. If you want them per user, store them in Users/AppData, if you want them for all users, store them in Common/AppData
If SHGetFolderPath(0, CSIDL_COMMON_APPDATA, -1, SHGFP_TYPE_CURRENT, sTempPath) = 0 Then
sCommonAppdata = Left$(sTempPath, InStr(1, sTempPath, Chr(0)) - 1) & "CompanyName\AppName"
End If
Change that to CSIDL_APPDATA for the Users AppData directory. Note: These map to totally different places on the filesystem for XP and Vista so when you are debugging prepare to look in different places.
2) Do I need priviledges to create folders and files, there, too?
You need Adminsitrator access to write anything in Program Files, if at all possible don't do it! We are currently running into issues that the API's for VB and the standard API's behave differently on files in Program Files.
3) What other common actions will cause problems?
There are lots of hidden gotchas. Just to name a few, you cannot communicate through IPC or Named Pipes to other applications (we have a Service that we were talking to through a Tray Notification Icon and that had to be completely re-written). Anything were you see a UAC notification is very difficult. Also you cannot write to anything in the Registry in LOCAL_MACHINE without Administrator, so you either have to stick to LOCAL_USER or raise credentials (see below).
4) The program has an updater which must download and register files, how do I elevate priviledges (sic) when this occurs?
Good luck with this, I highly recommend that you don't write it in VB6, like I said, the VB6 file api's appear to access files differently from the standard API's. If you need to elevate privileges see this post that someone kindly helped me with.
In the sort term turning off UAC and installing the ActiveX installer server will help. Long term you need to put data and configuration information in the users directory under \users or in \programdata.
In the short run it might not be necessary at all to modify your application, because
Vista comes with a set of compatibility options to allow legacy applications to run. This includes file and registry virtualization, a feature which basically redirects write operations to protected folders such as C:\Program Files to a virtual location only visible for the specific application running in a compatibility mode.
Some more details are mentioned in this article: How To Manage Windows Vista Application Compatibility in Dr. Dobb's.
Karl Peterson wrote a nice article on where to store user data & app data, with a VB6 class that retrieves the location of the special paths for you.

When - and why - should you store data in the Windows Registry?

As a developer, tools that store configuration/options in the registry are the bane of my life. I can't easily track changes to those options, can't easily port them from machine to machine, and it all makes me really yearn for the good old days of .INI files...
When writing my own applications, what - if anything - should I choose to put in the registry rather than in old-fashioned configuration files, and why?
Originally (WIN3) configuration was stored in the WIN.INI file in the windows directory.
Problem: WIN.INI grew too big.
Solution (Win31): individual INI files in the same directory as the program.
Problem: That program may be installed on a network and shared by many people.
Solution(Win311): individual INI files in the user's Window directory.
Problem: Many people may share a windows folder, and it should be read-only anyway.
Solution (Win95): Registry with separate sections for each user.
Problem: Registry grew too big.
Solution (WinXP): Large blocks of individual data moved to user's own Application Data folder.
Problem: Good for large amounts of data, but rather complex for small amounts.
Solution (.NET): small amounts of fixed, read-only data stored in .config (Xml) files in same folder as application, with API to read it. (Read/write or user specific data stays in registry)
Coming at this both from a user perspective and a programmers perspective I would have to say there really isn't a good exceuse to put something in the registry unless it is something like file associations, or machine specific settings.
I come from the school of thought that says that a program should be runnable from wherever it is installed, that the installation should be completely movable within a machine, or even to another machine and not affect the running of it.
Any configurable options, or required dlls etc, if they are not shared should reside in a subdirectory of the installation directory, so that the whole installation is easily moved.
I use a lot of smaller utility like programs, so if it cant be installed on a usb stick and plugged into another machine and just run, then its not for me.
When - You are forced to due to legacy integration or because your customer's sysadmin says "it shall be so" or because you're developing in an older language that makes it more difficult to use XML.
Why - Primarily because the registry is not as portable as copying a config file that is sitting next to the application (and is called almost the same).
If you're using .Net2+ you've got App.Config and User.Config files and you don't need to register DLL's in the registry so stay away from it.
Config files have their own issues (see below), but these can be coded around and you can alter your architecture.
Problem: Applications needed configurable settings.
Solution: Store settings in a file (WIN.INI) in the Windows folder - use section headings to group data (Win3.0).
Problem: WIN.INI file grew too big (and got messy).
Solution: Store settings in INI files in the same folder as the application (Win3.1).
Problem: Need user-specific settings.
Solution: Store user-settings in user-specific INI files in the user's Window directory (Win3.11) or user-specific sections in the application INI file.
Problem: Security - some application settings need to be read-only.
Solution: Registry with security as well as user-specific and machine-wide sections (Win95).
Problem: Registry grew too big.
Solution: User-specific registry moved to user.dat in the user's own "Application Data" folder and only loaded at login (WinNT).
Problem: In large corporate environments you log onto multiple machines and have to set EACH ONE up.
Solution: Differentiate between local (Local Settings) and roaming (Application Data) profiles (WinXP).
Problem: Cannot xcopy deploy or move applications like the rest of .Net.
Solution: APP.CONFIG XML file in same folder as application - , easy to read, easy to manipluate, easy to move, can track if changed (.Net1).
Problem: Still need to store user-specific data in a similar (i.e. xcopy deploy) manner.
Solution: USER.CONFIG XML file in user's local or roaming folder and strongly-typed (.Net2).
Problem: CONFIG files are case-sensitive (not intuitive to humans), require very specific open/close "tags", connection strings cannot be set at run-time, setup projects cannot write settings (as easily as registry), cannot easily determine user.config file and user settings are blown with each new revision installed.
Solution: Use the ITEM member to set connection strings at runtime, write code in an Installer class to change the App.Config during install and use the application settings as defaults if a user setting is not found.
Microsoft policy:
Before windows 95, we used ini files for application data.
In the windows 95 - XP era, we used the registry.
From windows Vista, we use ini files although they are now xml based.
The registry is machine dependent. I have never liked it because its getting to slow and it is almost imposible to find the thing you need. That's why I like simple ini or other setting files. You know where they are (application folder or a user folder) so they are easy portable, and human readable.
Is the world going to end if you store a few window positions and a list of most recently used items in the Windows registry? It's worked okay for me so far.
HKEY-CURRENT-USER is a great place to store trivial user data in small quantities. That's what it's for. It seems silly not to use for its intended purpose just because others have abused it.
Registry reads and writes are threadsafe but files are not. So it depends on whether or not your program is single threaded.
Settings that you want to have available in a user's roaming profile should probably go in the registry, unless you actually want to go to the effort of looking for the user's Application Data folder by hand. :-)
If you are developing a new app and you care about portability you should NEVER store data in windows registry since other OS don't have a (windows) registry (duh note - this may be obvious but gets often overlooked).
If you're only developing for Win platforms ... try to avoid it as much as possible. Config files (possibly encrypted) are a way better solution. There's no gain in storing data into the registry - (isolated storage is a much better solution for example if you're using .NET).
Slightly off-topic, but since I see people concerned about portability, the best approach I've ever used is Qt's QSettings class. It abstracts the storage of the settings (registry on Windows, XML preference file on Mac OS and Ini files on Unix). As a client of the class, I don't have to spend a brain cycle wondering about the registry or anything else, it Just Works (tm).
http://doc.trolltech.com/4.4/qsettings.html#details
Personally I have used the registry to store install paths for use by the (un)install scripts. I'm not sure if this is the only possible option, but seemed like a sensible solution. This was for an app that was solely in use on Windows of course.
Usually, if you don't put settings in registry, you use it mostly to get current Windows settings, change file associations, etc.
Now, if you need to detect if your software is already installed, you can make a minimal entry in registry, that's a location you can find back in any config. Or search a folder of given name in Application Data.
If I look at my Document and Settings folder, I see lot of softwares using the Unix dot notation for setting folders:
.p4qt
.sqlworkbench
.squirrel-sql
.SunDownloadManager
.xngr
.antexplorer
.assistant
.CodeBlocks
.dbvis
.gimp-2.4
.jdictionary
.jindent
.jogl_ext (etc.)
and in Application Data, various folders with editor names or software names. Looks like being the current trend, at least among portable applications...
WinMerge uses a slightly different approach, storing data in registry, but offering Import and Export of options in the config dialog.
I believe that Windows Registry was a good idea, but because of great abuse from application developers and standard policies not encouraged/mandated by Microsoft grew into an unmanageable beast. I hate using it for the reasons you've mentioned, there are however some occasions that it makes sense using it:
Leaving a trace of your application after your application has been uninstalled (e.g. remember user's preferences in case the application is installed again)
Share configuration settings between different applications - components
In .NET there really is NOT ever a need.
Here are 2 examples that show how to use Project proerties to do the this.
These examples do this by Windows User Project Properties, but the same could/can be done by Application as well.
More here:
http://code.msdn.microsoft.com/TheNotifyIconExample
http://code.msdn.microsoft.com/SEHE
(late to the discussion but) Short Answer: Group Policy.
If your customer's IT department wants to enforce settings related to Windows or the component(s) you're writing or bundling in, such as a link speed, or a custom error message, or a database server to connect to, this is still typically done via Group Policy, which makes its ultimate manifestation as settings stored in the registry. Such policies are enforced from the time Windows starts up or the user logs in.
There are tools to create custom ADMX templates that can map your components' settings to registry locations, and give the administrator a common interface to enforce policies (s)he needs to enforce while showing them only those settings that are meaningful to enforce this way.

Resources