views:

1372

answers:

4

Inside a service, what is the best way to determine a special folder path (e.g., "My Documents") for a specific user? SHGetFolderPath allows you to pass in a token, so I am assuming there is some way to impersonate the user who's folder you are interested in.

Is there a way to do this based just on a username? If not, what is the minimum amount of information you need for the user account? I would rather not have to require the user's password.

(Here is a related question.)

A: 

This information is stored in the registry in the key "HKEY_USERS\S-1-5-21-616815238-485949776-2992451252-3228\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders".

The "S-1-5-21-616815238-485949776-2992451252-3218" is the GUID of the user. You need to get this GUID to find the corresponding key and read it.

In this example they use SHGetFolderPath function you mention and there is a list with all special folders which might be helpful.

NOTE: Microsoft discourages to use the registry key, since it is still there just for backward compatibility

m_pGladiator
Does this work on all "recent" versions of Windows (2000 on up)?
Kurt
I'm not sure, but since the function is supported by MS it should work. In practice I read info only for HKEY_CURRENT USER, not for others. Also you can read the registry like INI files
m_pGladiator
I assume the function works, but I was wondering whether the registry key path was the same...
Kurt
Here's an article from Raymond Chen at Microsoft on exactly why you should NOT to that. http://blogs.msdn.com/oldnewthing/archive/2003/11/03/55532.aspx
James Curran
Please, please, please, do not read it from the registry!
Bob King
I just read the article from the blog. Thanks James Curran! I never knew this. And MS now have lower reputation for me than before. They should put a note in the registry that these keys are deprecated and that's it. But MS are MS...
m_pGladiator
+8  A: 

Please, do not go into the registry to find this information. That location might change in future versions of Windows. Use SHGetFolderPath instead.

http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx

Edit: It looks like LogonUser will provide the token for the other user that you need.

Frederik Slijkerman
This doesn't really answer his question, though, unless you can provide a way to get the folder path for a user other than the current one.
Nick
Correct, I've edited the answer.
Frederik Slijkerman
+3  A: 

You might try calling ImpersonateLoggedOnUser() to modify a user token for another user, and then passing that to SHGetFolderPath(). Based on the doc for ImpersonateLoggedOnUser(), it looks like you can call LogonUser() to get a token for a specific user.

Just from reading around, I'd guess that the user in question must be logged on in some form in order for this to work. I recall one page stating that the user's registry hive must be mounted in order for this to work (which makes some sense I suppose).

Andy
+1  A: 

I would mount the user's registry hive and look for the path value. Yes, it's a sub-optimal solution, for all the reasons mentioned (poor forwards compatibility, etc.). However, like many other things in Windows, MS didn't provide an API way to do what you want to do, so it's the best option available.

You can get the SID (not GUID) of the user by using LookupAccountName. You can load the user's registry hive using LoadUserProfile, but unfortunately this also requires a user token, which is going to require their password. Fortunately, you can manually load the hive using RegLoadKey into an arbitrary location, read the data, and unload it (I think).

Yes, it's a pain, and yes, it's probably going to break in future versions of Windows. Perhaps by that time MS will have provided an API to do it, back-ported it into older versions of Windows, and distributed it automatically through Windows update... but I wouldn't hold my breath.

P.S. This information intended to augment the information provided in your related question, including disclaimers.

Nick