This answer will probably be controversial, because it isn't strictly answering the question in the title. But it is nevertheless the correct answer to the question. The question explicitly asked is what is known as an XY problem. You have encountered a problem, figured out a possible solution in your head, and then run into trouble implementing that solution, so you've asked for help. The issue is that the solution you've figured out in your head is not the correct one.
My program depends on information that changes depending on which user is logged in. An example would be the location of AppData.
This is normal. You do not, however, solve it by detecting which user is logged in. That won't do you any good anyway. Say you know the name of the user: how are you now going to use that to figure out the AppData folder? I suppose you're going to try and compose a path manually, based on your knowledge of the folder's location in a default installation of Windows: C:\Users\<the user name>\AppData\
. But you've just blundered. What happens if the user has mapped their profile directory someplace else? What if the user name doesn't match the name of the directory in the Users directory (e.g. if the Administrator account has been renamed)?
The real solution to this problem is altogether simpler. You simply ask Windows for the path of the AppData folder. Let the operating system do its job keeping track of the logged in user.
Normally, in Windows, you would call the SHGetKnownFolderPath
function, or its moral equivalent. In the .NET Framework, that functionality is wrapped by the Environment.GetFolderPath
method. Simple, and guaranteed to be correct.
You will want to specify either SpecialFolder.CommonApplicationData
(the AppData folder for all users), SpecialFolder.ApplicationData
(the roaming AppData folder for the current user), or SpecialFolder.LocalApplicationData
(the non-roaming AppData folder for the current user).
My program also needs Administrative privileges. If I run the program as Administrator, the program thinks the Administrator is the currently logged in user.
Because it is. If you're running the program as Administrator, then for all intents and purposes, the program will be run as Administrator. That means returning Administrator as the name of the current user, returning the Administrator's AppData folder, and so on and so forth. This is quite logical, it is what enables the program to do Administrator-specific things.
But beyond that, it is bad practice (in all but the most unusual of cases) to have an entire application that requires Administrative privileges. Generally, there are only one or two actions taken by an application that truly require Administrative privileges. For example, I have a little utility that I wrote. None of its basic functions require Administrative privileges, but it has a feature to install itself so that it is launched on startup for all users. Clearly that requires Administrative privileges, but that's only a one-time speciality feature. You don't want the entire app to require Administrative privileges just for that specialized function. What if the current user can't get Administrative privileges? They should still be able to use the software, just with the Administrator-specific functionality disabled or otherwise inaccessible.
And this fits with Windows's model for process elevation. There is no way to temporarily elevate the current process. You have to start a new elevated process, do whatever it is that requires Administrative privileges, and then quit that process. I have written detailed instructions here on how to do that. Of course, they are in C#, but trivially translated to VB.NET.
Is there any other way I can get the currently (active) logged in user? I've tried SystemInformation.UserName.ToString and My.User.Name.ToString. Both give the wrong user.
Like I said above, the information is not "wrong". You said it yourself: they are returning the "currently (active)" user: Administrator. The one you requested the app to be run as.
With the solution I proposed above, your app, running normally, would not be run as Administrator. That would increase security, and it would ensure that you get information applicable to the currently logged in user. When you need to perform actions that require Administrator privileges, you spin off a second elevated process, do the work, and then exit that process. The elevated process acts as Administrator, for all intents and purposes, which is almost always what you want.
For what it's worth, I frequently see questions like yours from people who are trying to write an installer (don't do that, just use one of the many excellent installers already available). Their installer requires Administrative privileges, obviously, so they set it to request elevation on startup. So far, so good. Except that they want to write data to a specific user's AppData folder during the installation. Now they have a problem, because (1) they can't get that path, and (2) there might not even be another logged in user. The solution, and the one officially recommended by the Windows Logo guidelines, is to do this type of initialization on first-run. In other words, the first time that the installed application is run by a normal user. Then you get the AppData folder you expect.