The Wild West
Back in those DOS and Win9x days you could pretty much dump files anywhere since there was no real filesystem security. On Windows 2000 and then on its minor update Windows XP, people carried on working in "DOS Mentality" by just making all users members of an elevated rights group such as Administrators or Power Users.
This gave Microsoft a black eye because users logged on with such accounts who used the Internet had opened a gaping hole for malware to come in and wreak havoc. A lot of email spam comes from zombied Windows XP machines even today.
In response this was modified beginning in Windows Vista through user Account Control (UAC). With UAC even if you were silly enough to have users log on as an Administrators account (Power Users was removed entirely) your session was no longer elevated. Instead elevated rights require special actions that raise a dialog on a Secure Desktop that malware can't just hijack and blat messages at to "click approval."
However when combined with NT security (pretty much the same model since at least NT 4.0) users can't just dump files and folders willy-nilly anymore. Lots of secured filesystem locations became off limits. This meant installed programs (in Program Files) began to either fail or run afoul of appcompat filesystem virtualization.
What To Do?
Well, there are lots of writeable locations. Each user has a Desktop, a Documents, and even AppData locations in which he can create, modify, delete, and do other things with folders and files. These work fine if the programmer takes any time to make use of them. But these don't work well for files "shared" among different users of the same PC.
Instead Windows has a CommonAppData special folder with special security on it. The DOS-visible name of this file can vary: on recent versions of Windows an English-language system calls this ProgramData.
The security on CommonAppData/ProgramData is such that a folder or file created within it has a special "Owner Access" applied to it. If user Joe creates a folder there he has full access, and all other users have basically read access. However since Joe "owns" it he can change the folder's security without elevation, and this altered security will be inherited by any folders or files created within it.
In order to avoid collisions between applications using ProgramData the convention is to create a "company" subfolder there, and within that create "product" or "application" subfolders to contain the folders and files of a given application that all users need access to.
How To Do It?
Windows Explorer, also known as Shell32, knows how to locate ProgramData by invariant code and can return the path to your programs. These "codes" are numeric values, assigned names prefixed ssf/CSIDL_ such as ssfCOMMONAPPDATA.
That gets you to the folder's path, and you can use MkDir to create subfolders, so you're nearly there!
To alter the security I've posted SetSec.bas before, but nobody seems to be using it. In an attempt to simplify this I have written ProgramData.bas as a "wrapper" for it. This gets things down to a simple function call.
Demo
The attached archive contains a simple program AnyUserUpdate.vbp, which doesn't do much.
The program looks for an application common data path and creates it as required, altering security at each created level to "Full Access" for members of the "Users" group. This is very liberal access and not correct for all situations, but it emulates the Wild West of those DOS/Win9x days to simplify programming for people. "Users" differs from "Everyone" in the post-XP era (starting in Windows Vista, "Everyone" no longer includes "Guest" accounts).
Once the demo program has this common folder and its path, it loads Text.txt into a TextBox for possible user editing.
When the program ends it checks for changes to the TextBox. If changes have been made it writes the altered Text.txt back out to disk, then logs the change to Log.txt (timestamp and user name) and exits.
![Name: FolderStructure.png
Views: 165
Size: 12.3 KB]()
All of the work required is now down to a one-liner:
Beyond ProgramData
A ProgramData subfolder is a good place for data common to all users. That might be program settings INI files, Jet MDB databases, or any other files common to all users that your application's program(s) need to be able to create, alter, or delete.
However you often have per-user settings and such too. These should go into a similar folder structure underneath ssfLOCALAPPDATA, but that's easy enough since there is no need to use SetSec.bas to alter security there. However you might want to add a new function to ProgramData.bas to look-up/create such a path too.
Installed Programs
If you use an installer to put your program(s) into Program Files you can still use ProgramData. For example maybe your program ships with an initial empty Jet MDB that all users will be updating.
Just have your program use ProgramData.Path() as above. Then check to see whether your XXX.MDB exists there, and if not copy XXX.MSB from App.Path to this ProgramData path. Then open the database as you normally would, but in the ProgramData path instead of in App.Path.
It's as easy as that!
Back in those DOS and Win9x days you could pretty much dump files anywhere since there was no real filesystem security. On Windows 2000 and then on its minor update Windows XP, people carried on working in "DOS Mentality" by just making all users members of an elevated rights group such as Administrators or Power Users.
This gave Microsoft a black eye because users logged on with such accounts who used the Internet had opened a gaping hole for malware to come in and wreak havoc. A lot of email spam comes from zombied Windows XP machines even today.
In response this was modified beginning in Windows Vista through user Account Control (UAC). With UAC even if you were silly enough to have users log on as an Administrators account (Power Users was removed entirely) your session was no longer elevated. Instead elevated rights require special actions that raise a dialog on a Secure Desktop that malware can't just hijack and blat messages at to "click approval."
However when combined with NT security (pretty much the same model since at least NT 4.0) users can't just dump files and folders willy-nilly anymore. Lots of secured filesystem locations became off limits. This meant installed programs (in Program Files) began to either fail or run afoul of appcompat filesystem virtualization.
What To Do?
Well, there are lots of writeable locations. Each user has a Desktop, a Documents, and even AppData locations in which he can create, modify, delete, and do other things with folders and files. These work fine if the programmer takes any time to make use of them. But these don't work well for files "shared" among different users of the same PC.
Instead Windows has a CommonAppData special folder with special security on it. The DOS-visible name of this file can vary: on recent versions of Windows an English-language system calls this ProgramData.
The security on CommonAppData/ProgramData is such that a folder or file created within it has a special "Owner Access" applied to it. If user Joe creates a folder there he has full access, and all other users have basically read access. However since Joe "owns" it he can change the folder's security without elevation, and this altered security will be inherited by any folders or files created within it.
In order to avoid collisions between applications using ProgramData the convention is to create a "company" subfolder there, and within that create "product" or "application" subfolders to contain the folders and files of a given application that all users need access to.
How To Do It?
Windows Explorer, also known as Shell32, knows how to locate ProgramData by invariant code and can return the path to your programs. These "codes" are numeric values, assigned names prefixed ssf/CSIDL_ such as ssfCOMMONAPPDATA.
That gets you to the folder's path, and you can use MkDir to create subfolders, so you're nearly there!
To alter the security I've posted SetSec.bas before, but nobody seems to be using it. In an attempt to simplify this I have written ProgramData.bas as a "wrapper" for it. This gets things down to a simple function call.
Demo
The attached archive contains a simple program AnyUserUpdate.vbp, which doesn't do much.
The program looks for an application common data path and creates it as required, altering security at each created level to "Full Access" for members of the "Users" group. This is very liberal access and not correct for all situations, but it emulates the Wild West of those DOS/Win9x days to simplify programming for people. "Users" differs from "Everyone" in the post-XP era (starting in Windows Vista, "Everyone" no longer includes "Guest" accounts).
Once the demo program has this common folder and its path, it loads Text.txt into a TextBox for possible user editing.
When the program ends it checks for changes to the TextBox. If changes have been made it writes the altered Text.txt back out to disk, then logs the change to Log.txt (timestamp and user name) and exits.
All of the work required is now down to a one-liner:
Code:
Path = ProgramData.Path(App.CompanyName & "\" & App.ProductName)
Beyond ProgramData
A ProgramData subfolder is a good place for data common to all users. That might be program settings INI files, Jet MDB databases, or any other files common to all users that your application's program(s) need to be able to create, alter, or delete.
However you often have per-user settings and such too. These should go into a similar folder structure underneath ssfLOCALAPPDATA, but that's easy enough since there is no need to use SetSec.bas to alter security there. However you might want to add a new function to ProgramData.bas to look-up/create such a path too.
Installed Programs
If you use an installer to put your program(s) into Program Files you can still use ProgramData. For example maybe your program ships with an initial empty Jet MDB that all users will be updating.
Just have your program use ProgramData.Path() as above. Then check to see whether your XXX.MDB exists there, and if not copy XXX.MSB from App.Path to this ProgramData path. Then open the database as you normally would, but in the ProgramData path instead of in App.Path.
It's as easy as that!