Reading the file from per-user CSIDL_APPDATA has the issue that you assume
(e.g. the administrator) installed the app from a different account. This
it.
"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message
Generally, the strategy goes like this:
Try to read the file from CSIDL_APPDATA
If that fails, read the file from CSID_COMMON_APPDATA
If that fails, either tell the user there is an unrecoverable problem, or
have a set of
hardwired defaults that sort-of work.
When writing a file, always write to CSIDL_APPDATA. If you want the
manufacturer and
product as directories, it is your responsibility to create them. So you
would do
//----------------
// in stdafx.h
#define _WIN32_IE 0x500
#include <shlobj.h>
//-----------------
CString path;
LPTSTR p = path.GetBuffer(MAX_PATH);
HRESULT hr = ::SHGetFolderPath(CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
p);
if(SUCCEEDED(hr))
{ /* succeeded */
path.ReleaseBuffer();
...your code here
} /* succeeded */
else
{ /* failed */
path.ReleaseBuffer();
...failure code here
} /* failed */
which gives you the path
C:\Documents and Settings\username\Application Data
for the login username.
To that path you append \Manufacturer and try to create the directory. If
it succeeds,
fails because the directory already exists, you can go to the next step,
otherwise you
have to report an error and do some kind of recovery.
To the name
C:\Documents and Settings\username\Application Data\Manufacturer
you append \ProductName and try to create the directory. If it succeeds,
or fails because
the directory already exists, you can go to the next step. Otherwise you
have to report
an error and do some kind of recovery.
[Repeat as required, e.g, for version # of the product, etc.]
Finally, you have a full path to where you want to create the file; append
the file name
and create the file. Note this is a per-user file. So during the install
process, the
installer can create dialogs that provide custom parameterization to the
site, which is
stored in the (read-only from anywhere else) common-appdata folder (the
same techniques of
subdirectories apply here). So any app that starts up gets the default
per-site settings
established at install time.
Now there is a question: what happens if the admin changes something but
the local appdata
folders have the original data from the install? In this case,
particularly for XML, what
you do is read per-site settings from the common-appdata folder, always,
and save
user-modifiable settings to the user-appdata folder.
In the multi-user environment of Windows, you simply cannot have any
individual users
modifying the common appdata in any way; this affects all users.
Note that once you write this subroutine, it is usable everywhere. While
I've not done it
for XML, I've done it for other setting strategies, including (shudder)
.INI files.
joe
****
On Tue, 3 Nov 2009 15:58:08 -0800, "David Ching"
<dc@remove-this.dcsoft.com> wrote:
If per-user is OK, then that will always work, elevated or not. Issue
then
may be that xml file will be installed to the per-user folder of the user
that is installing (could be an IT Admin) and not the user that will be
running it; in that case, user running it won't have the xml file! That's
why I suggested installer put it in allusers and have per-user updates
take
precedence.
-- David
"DanB" <abc@some.net> wrote in message
news:GnZHm.8758$Cc6.1617@newsfe07.iad...
Hi David,
Thanks. I may have made it sound like I need access to all users, but I
don't if I get this right. I don't want to have to run elevated and
trigger the UAC. This came to a head when I was patching a new feature
and
wanted to copy in that new xml. It copied without elevation but to the
wrong place. The wrong place happened to be all users. And if I were
required to be elevated to write this folder, something was wrong in
vista.
But even then I would think if I'm doing it by the rules the user app
data
should be in a place 'I' can get to, do what I need, and without
elevation. And like I said, I don't care where this folder is. I'd like
it
by the rules and were the installer puts it, and I can find it.
My objective is to use user-app-data by the rules, not to work around
them. I just want the 'right' place, a no special privileges place at
that. Per user is fine.
As far as working with the clients on pre release, they know that they
may
have to do special stuff sometimes, and I'm not looking to fix that.
This
is about our next full msi release. It is scheduled for the first of the
year but I would really like to avoid spending the next two months just
chasing this down. :)
Best, Dan.
David Ching wrote:
"DanB" <abc@some.net> wrote in message
news:JMXHm.42$Wd1.24@newsfe15.iad...
Hi David,
Thanks. So how do others do it? i.e. use the window installer to get
their product in the 'right' places? (And I'll cross the msi group)
Your installer (.msi in your case, but it doesn't have to be, it could
be
an ordinary .exe) can access allusers/appdata because it is run as
elevated. When you double click it, you get the prompt to click OK (and
if you are running from a non-admin account, you must supply admin's
username/password). That's what makes it elevated.
If I stick with the way I'm doing it, (../allusers/appdata/...) it
works
fine even if my data is split between two folders. I just can't
'programmaticly' write to that folder, i.e. copy a new file in, as I
don't have a way to find it other than engage the client with stuff
they
should not have to do. But reading and writing the shipped files works
fine.
When the client want to copy settings from an old computer I will have
to have them hunt it down as my 'open settings folder' is not useful.
I will also spend the morning researching this....
Would it work to write the new xml file into a per-user folder, not
allusers, but e.g. /users/david? Your app will work on this folder,
always. Your app would need to do this again when a different user ran
your app, but it might work. The .msi file will put the original xml
file into the allusers folder, and your app will write updated ones to
the per-user folder. And your app will read the one from per-user
folder
if available, or if not, the one from allusers (since I believe reading
from allusers is OK).
Short of that, when your app needs to update the xml file in the
allusers
folder, what you can do is have it launch another .exe that has a
manfiest set to requireAdministrator (that will like the .msi) prompt
you
to click OK and if not running from an Admin account, prompt for
admin's
username/password. Again, like the .msi, it will have free access to
allusers. But then an Admin must be available to supply
username/password, may not be an option if your app is deployed in
enterprise.
Also, the VS msi project set the app folder
[ProgramFilesFolder][Manufacturer]\[ProductName]
But it leaves the user appdata folder unassigned. Could it be as
simple
as finding the correct 'virtual' path for the user folder assignment
for
the MSI build?
That's the per user folder, not allusers, so I don't think it is
relevant.
When I think it is right I'll send the test CSIDL program off to
someone
to see. For whatever reason both our vista machines install and work
fine from 'all users'...
Test it yourself by running your app from a Limited (non-Admin) account
on your own PC.
Regards,
David
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm