How to resolve location of %UserProfile% programmatically in C++? - c++

I'd like to find the directory of the current user profile programmatically in C++.

SHGetSpecialFolderLocation is the best way to get at most of the special paths on Windows. Passed CSIDL_PROFILE it should retrieve the folder you are interested in.
If you are actually interested in the contents of the %UserProfile% environment variable you could try ExpandEnvironmentStrings

Simplest way on Windows & Linux:
char *szBuff;
szBuff=std::getenv("USERPROFILE"); //Returning value of %USERPROFILE%

To cover all user profile scenarios in Windows Vista and up there is SHGetKnownFolderPath. Here is the link to the docs page on it and related functions.

Related

Win32: Programmatically Iterate Through All Users' Standard Directories

Hi my question is what is the best way to iterate through every standard directory location for every user on a computer using the win32 api (docs, music, pics etc) (or qt if possible). I have found these guys:
SHGetKnownFolderPath
GetProfilesDirectory
GetUserProfileDirectory. The GetProfilesDirectory and GetUserProfileDirectory functions are obvious in how to use but don't return a path for the individual standard folders which could be a problem if I need to get a directory from a non-stanard location i.e. D:\Documents for a user whose profile directory is C:\Users\Josh. The SHGetKnownFolderPath function can do what I need it looks like however I don't know how to get an access token for a user not logged in. Is there any way to do what I want with the win32 api maybe with SHGetKnownFolderPath and access tokens for inactive users? Perhaps a third party library? I'm also using Qt but don't think that's relevant I couldn't find such libraries for Qt that do what I want...

Dynamically get link to Desktop on PC for any user

Is there a way to get the path to Desktop C:\Users\Username\Desktop for any user? I'll like to store it in a variable. Currently, I have mine hardcoded in a function
Use SHGetKnownFolderPath. See the linked Microsoft documentation.

How to get paths to user desktops from a service?

I need to enumerate paths to desktop folders for all users on a local Windows system from a service application. The catch is that some users may not be logged in at the time. So is there any API, or some other method to do that?
EDIT1: For those who didn't read the first paragraph let me repeat -- I do not have a token to a user account, a user may not be logged in at the time.
EDIT2: I need this to remove a shortcut from user desktops before a feature supported by my application is turned off, or the app is uninstalled.
Here's the best method I was able to come up so far. So I'd appreciate if someone with a non-English installation of Windows could check this for me?
(I'm posting just a pseudo-code for brevity.)
1 - All of the steps below are done from a local service application.
2 - To get paths to all user profiles enumerate subfolders in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList key and read ProfileImagePath value from them. It will give profile paths for each user account.
3 - To get the folder name for the desktop, read the Desktop value from the HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders key from the service app (yes, I know HKCU sounds strange, but it worked for me.) After that get the path for the %USERPROFILE% environment variable, using environment variable APIs. So you'll get two paths, something like this:
C:\Windows\system32\config\systemprofile\Desktop
and
C:\Windows\system32\config\systemprofile
Then simply isolate the 2nd string from the 1st, using case-insensitive comparison, and you'll get the folder name for the desktop, (i.e. "\Desktop" in this case.)
4 - Add the desktop folder to the path obtained in step 2 to produce the full path to that user's desktop folder.
From userenv.h : GetProfilesDirectory (win2k+, iirc)
msdn.microsoft.com/en-us/library/windows/desktop/bb762278(v=vs.85).aspx
Use this to find the directory containing all the local user account profile directories.
To find the desktop folder:
Shlobj.h : SHGetKnownFolderPath (vista+)
msdn.microsoft.com/en-us/library/windows/desktop/bb762188(v=vs.85).aspx
You'll need FOLDERID_Desktop as the known-folder id. This symbol is declared in Knownfolders.h
msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx
Using these, you might get closer to what you want without directly reading the registry. Of course this belies any elegant way of enumerating the users aside from inferring from the folder list within the
GetProfilesDirectory. Perhaps there is a more api appropriate way to enumerate the local users.
Secondly, and this depends on the purpose of your service, but perhaps by working with the 'allusers' profile, instead of each individually you won't need to know the current list of local users.

All users path?

In C# I can do the following:
DirectoryInfo di = new DirectoryInfo(System.Environment.GetEnvironmentVariable("ALLUSERSPROFILE"));
Which will get me the path to the all users profile.
In C++ I can use the SHGetFolderPath, but it does not seem to have a CSLID for all users.
Is there an equlivant function that I can blow the %ALLUSERSPROFILE% out to its path value?
Use SHGetFolderPath with CSIDL_COMMON_APPDATA. Or SHGetKnownFolderPath since Vista with FOLDERID_ProgramData.
Alternatively, use the .NET native Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
Use ExpandEnvironmentStrings to expand the %ALLUSERSPROFILE% string. This method is part of Kernel32.dll.
For most purposes, you should be able to use SHGetFolderPath with one of the CSIDL_COMMON_... values (see here for a complete list) to get the subdirectory of the all users' path that you're interested in. (For Windows Vista and above, you can use SHGetKnownFolderPath with one of the FOLDERID_Public... values; see here.)
Note that in certain security situations that folder might not even be a real folder. There not being a CSIDL_ for it is always a strong hint that you're off the beaten path.
Are you sure you're not better off with _APPDATA?
You could use the getenv CRT function to get the value of the ALLUSERSPROFILE environment variable in much the same way as you are for C#.

How can I get the path of a Windows "special folder" for a specific user?

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 whose 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.)
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.
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).
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.
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