Win32: Programmatically Iterate Through All Users' Standard Directories - c++

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

Related

C:\ file scan with C++, access denied to specific files

Ok so I have written a code with recursive function that scans my (or any other) C:\ disc.
Using chdir() I'm changing the active directory to C:\ and using system("dir >> C:\Test\"filename") to get the files in that directory written in .txt and then reading it to know what I have. After that I'm checking for additional directories with temp.substr("<DIR>") and calling the function again just with longer path for that specific directory.
The code itself works as it should but I've ran to some directories that I can't access such as Administrator or specific folders in Windows. The only way I've found around them is by adding exeptions to the code so that it just avoids those folders. I'd like to know if there is a way to get a list of folders/files that I don't have access to from cmd since it would make my code a lot more precise or a way to access those directories.
While C++ file API does not have any idea about file permissions and such other than you'll fall when you try to read a file you don't have permissions to, C++ do have access to the Windows API. The Windows API are system calls that gives you access to native OS functionalities, such as calls to GetFileSecurity.
Note that using Windows API means your code would need to take extra steps to ensure portability if you want to run it on non Windows platforms.
The process (your program) runs with certain privileges, normally the users one. The access rights in Windows aren't as simple as "Administrator is god". Even if your user account is member of the "Administrators" group, you can not simply access everything. It usually depends if the OWNER of a file system object grants privileges to other groups and users.
A member of the "Administrators" group might be able to gain access by overriding security settings, but I would advise against that.
You might need elevated privileges and even might need to run your application under a SYSTEM account, it very much depends on what you are trying to achieve.
For more details I suggest to read the "Best practices for Security API" here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms717796(v=vs.85).aspx
and especially the chapter "Running with Special Privileges".

Xml file are saved in two different path

I created application that store some data to XML file. The issues is with the path of the XML saving. Am using TinyXML to save the data in vc++.
When I deploy this application, it installs in "C:\Program files(x86)\applicationname " and when I run the application the XML file is saving in
"C:\Users\UserName\AppData\Local\VirtualStore\Program Files (x86)\ApplicationName ".
I have made this application to work on system startup. So when I restart this application,
the xml file is stored in different path "C:\Users\UserName\AppData\Local\VirtualStore\windows\sysWOW64"
I want my XML to be stored in the path where I installed or should be stored in appdata, application name
What should I do to store XML file in one places where application is installed?
doc.SaveFile( "test.xml" ); // xml saving code in tinyxml library
Firstly, this has nothing to do with C++, as the C++ code is probably working. Same with XML and tinyxml and even visual-c++.
It seems that windows redirects those write accesses to a user-specific "VirtualStore\Program Files", but I'll leave it to you to research the actual semantics of that. On startup, when there is no user, this path obviously differs, since the former user is not logged in.
Now, in order to get a fixed path, you can use the function GetModuleFileName() to find out the location of your executable and use that path to locate Smartmeter.xml. However, the problem you are facing now is that programs installed under "Program Files" don't magically gain write access rights to their install directory. This is to protect one user from messing with data of another user.
I think that what you are doing is writing a program that runs in the background, which would be called a "service" under MS Windows. What is still unclear is what you want to achieve with this file and also what you are planning to do overall, and these are things that decide the future steps. In any case, take a look at the possibilities that services provide, maybe there is something that fits your needs.

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.

Is there any method to know whether a directory contain a sub directory?

I am woking in c++.
Is there any method to know whether a directory contain a sub directory?
CFileFind seems have to search through total files.
It is time consuming if the only subdirectory is at the end of the list and the there are lots of files.
for example: directory A contains 99995 files and one subdirectory at the end of FindNextFile List. had I try 99995 times, then say: yes, it contains subdirectory?
Raymond Chen from Microsoft has written a post that probably applies here: Computing the size of a directory is more than just adding file sizes. In essence, he explains that information like the size of a dir cannot be stored in the dir's entry, because different users might have different permissions, possibly making some of the files invisible to them. Therefore, the only way to get the size the user should see is to calculate it upon request from the user.
In your case, the answer probably stems from the same reasoning. The list of directories available to your app can only be determined when your app asks for it, as its view of the root directory might be different than another app's, running with different credentials. Why Windows store directories along with files I don't know, but that's a given.
Since Win32 is as close as you'll get to the file system in user mode, I'd avoid any higher level solutions such as .NET, as it might only simplify the interface. A driver might work quicker, but that out of the scope of my knowledge.
If you are using the .Net framework you could use Directory.GetDirectories and check is the size of the array is 0. Do not know how if this will give you speed.
If you have control over the directories you could apply a naming convention so that directories that have sub directories are named one way and directories with out sub directories are named another.
You can try using the boost filesystem library.
A class by name directory_iterator [ declared in boost/filesystem/operations.hpp ] has many functions which can be used for listing files, finding whether the file is a sub-directory ( is_directory -- I guess this is what you are looking for ) etc..
Refer the following link for more information.
link text
It seems you are using MFC [ just saw that you are using CFileFind ], didn't see that earlier.
Sorry, Didn't have much info. You may have to use FindFirstFile/FindNextFile.
Whether this can be done very fast is entirely platform-dependent.
On Win32 you use FindFirstFile/FindNextFile or wrappers on top of those like MFC CFileFind and they list items in some order that can't be forced to list directories first.

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