Is there a way to programmatically switch from the start menu to desktop. For example if you had a service thats runs once the user logs in and you wanted that service to switch to the desktop view once the user logs in? I can't seem to find a way around it. I tried virtual key press of the windows key but that didnt work?
I'm not really sure exactly what the problem you're facing is is. "programmatically switch from the start menu to desktop" can be interpreted a few different ways.
However, since you said "you wanted that service to switch to the desktop" "I tried virtual key press of the windows key", I assume you are trying to communicate with windows on the desktop from a service, which cannot be done. This is by design as a security feature. If you open task manager and do view -> select columns -> session ID, you will notice that the service runs in session 0, while 'desktop' applications run in the session of the logged on user. Applications cannot communicate via Windows messages between sessions.
There is a workaround, although more effort required than simply sending a virtual key press. The workaround is to have your service create a process in the user's session which then performs your tasks for you (your virtual key press method would work in this application, for example).
The API calls you will need to use to do this are:
CreateProcessAsUser
WTSGetActiveConsoleSessionId
WTSQueryUserToken
DuplicateTokenEx
EDIT
If you want to control the start menu, there is no easy method for that either. If you must do it, I suggest you use a tool called Spy++ (comes with visual studio - see Microsoft Visual Studio x.x\Common7\Tools, or can be downloaded). Use the Find Window feature to view the messages sent to the Windows Start button when you press it, and then you can see what messages you want to send to the button to control it in the way that you need to.
For example, you may see a WM_LBUTTONDOWN message sent to the start button. that toggles the start menu. You can then use FindWindow, perhaps with GetDesktopWindow to get a handle to the start button, and then send the messages you want to control it with SendMessage. You may also want to check if the start menu is shown by using the same procedure to get a handle to the start menu and using IsWindowVisible.
Related
I've been looking all over the internet for an answer to this, and it just doesn't seem to be directly answered, so I thought I would ask.
Case scenario: I want to take a screenshot of what is currently on the computer screen. If it's the Windows Logon screen, I want it to be that. If it's the active user's desktop, I want to to be that. If the user elevates their application, and the UAC prompt shows up, I want it to be that.
As per lots of reading and trial and error, my current setup is as follows:
Program runs as a windows service
Gets the active user's token
Runs CreateProcessAsUser with the user's token to generate another instance of itself
Takes a screenshot and transmits it back via pipes.
Right now this is working great for a logged on user, except that screenshot is black when a UAC prompt is enabled.
Also, this method obviously won't work for getting the logon screen.
Fundamentally I am wondering how exactly does TeamViewer go about achieving this sort of thing? It is able to switch between the logon screen and a user's session flawlessly, whilst also capturing UAC prompts. I am immensely curious as to how it achieves this.
Thanks everyone!
As per the advice of Davison, I have figured out how to do this, and it involves multiple steps.
Firstly, one must use CreateProcessAsUser to create a process inside the console session (obtained from WTSGetActiveConsoleSessionId). Something to note is that this process must have administrative privileges, which simply getting a handle to the user's token will not do. The way around this evidently, is to get a handle to a process running with administrative privileges, get this processes' token, duplicate it, and use that with CreateProcessAsUser. The process I used for this was Winlogon.
After this, the rest is quite simple; use OpenInputDesktop to get a handle to the desktop the user is currently seeing (it will be Default for actual desktop, and Winlogon for the UAC Prompt and login screen). After this, use SetThreadDesktop to set your processes' thread to the appropriate desktop, and capture the screen. Assuming that your Process has the privileges to create a handle to the Winlogon desktop, you will be able to capture the login screen/uac prompts and the regular user desktop.
Again, thanks to Davison, who pointed me in the right direction.
In a command line application which is single threaded, I want to know when user closes (by clicking on red cross on top right) shutdowns PC or Logoff without logging out of my application first, so that I can clear the cookies that I am storing in window's registry.
Is there any way I can know when user has done the events mentioned above and call a function within my application or call a separate EXE or a Batch file following the event ?
I need this functionality because I want to prevent a possible scenario where in Registry is full of unwanted thrash created by not logging out of application properly.
Since my application runs over command prompt likeC:\Users\admin\Desktop>Application.exe -task "ConnectServer" --ip 127.0.0.1 I am looking out for some way to either manage cookies in efficient way or to delete the cookies after catching the events mentioned above.
You could use SetConsoleCtrlHandler()
So I wanted to create a windows service that runs a few commands in a batch file.
However, while I assume I can redirect stdout from the subprocess and read out an error message, I can't seem to find out how I would get that to display to the screen.
when starting a windows service, it gives errors when the service fails to start, so ideally I would like to just use the interface that pops up the other service errors rather than popping up some window of my own or writing a log file.
I used this to get started but it doesn't seem to have anything on error processing.
http://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus
He just outputs to a debugger. I can definitely do that, but ideally the person starting the service would want to know if there was an error starting.
Yes, you can redirect the STDOUT of the spawned process. MSDN has an article on that topic:
Creating a Child Process with Redirected Input and Output
You can use ReportEvent(), EventWrite(), or TraceEvent() to write log messages to the System Event Log (which is located within Windows' Control Panel), depending on which logging API you decide to use. Refer to MSDN for more details:
Event Logging
Windows Event Log
A service is a background task, it should not display its own UIs. Use the system Event Viewer to view log messages. The popup the user sees if the service fails to start is not displayed by the service itself, but by the Service Control Manager.
Starting with Windows Vista, services do not run in the same desktop session as logged in users (Session 0 Isolation), so they cannot display their own UI anymore. If your service must display a popup message, it can use WTSSendMessage() for that. For more complex UIs, it is best to implement that as a separate non-service GUI app that runs in the user's session, and then the service can launch/communicate with that app as needed.
I am writing a service application that will run with local system credentials. I will need to know from my service if the Windows logon screen is displayed at any particular time. Is there any way to do this?
PS. The screens that can be brought up by locking the workstation:
Or by trying to switch the user:
Or after a Ctrl+Alt+Del:
PS. I need this to run on Windows XP and up.
EDIT: The only viable solution that I came up with so far is to see if LogonUI.exe process is running. The issue with this approach is how to distinguish between the actual system logon process and any other process that has that image name?
As described in the comments you are trying to detect whether or not a process in an interactive desktop session should show a message box. There being no point doing so if the interactive session is not active.
In which case I believe that your proposed solution is the wrong one. Instead you should register for session change notifications by calling WTSRegisterSessionNotification. When you do this you'll get sent WM_WTSSESSION_CHANGE messages that allow you to keep track of the current state.
Note that you do this in your desktop app rather than the service. The service still sends its messages to the desktop app. But the desktop app now knows whether or not it is worth showing them.
Update
Remy suggests a better way in the comments:
And if a separate app is being used, there is no reason to detect session changes at all, that app can simply check if its currently assigned workstation/desktop is the currently interactive workstation/desktop instead, comparing GetThreadDesktop() to OpenInputDesktop(), for instance.
All such screens are presented on a separate desktop. You may try to enumerate the user's desktops and compare it with the current (I am not sure the service in session 0 - Vista and up - can do that; if not, spawn a helper process in the user session). This however may give a false positive if an UAC desktop is up. Another corner case is a userless situation (right after boot before any user looged on).
There are several states in the windows.
Logged-Off State
When Winlogon is in the logged-off state, users are prompted to identify themselves and provide authentication information. If a user provides correct user account information and no restrictions prevent it, the user is logged on and a shell program (such as Windows Explorer) is executed in the application desktop. Winlogon changes to the logged-on state.
Logged-On State
When Winlogon is in the logged-on state, users can interact with the shell, activate additional applications, and do their work. From the logged-on state, users can either stop all work and log off, or lock their workstations (leaving all work in place). If the user decides to log off, Winlogon will terminate all processes associated with that logon session and the workstation will be available for another user. If, instead, the user decides to lock the workstation, Winlogon changes to the workstation-locked state.
Workstation-Locked State
When Winlogon is in the workstation-locked state, a secure desktop is displayed until the user unlocks the workstation by providing the same identification and authentication information as the user who originally logged on, or until an administrator forces a logoff. If the workstation is unlocked, the application desktop is displayed, and work can resume.
reference: https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa380547(v=vs.85).aspx
p.s. registering a secure attention sequence (SAS, CTRL+ALT+Delete) is included in Workstation-Locked state
Similarly, there are several desktop types on windows.
Winlogon desktop
Application desktop(=Default desktop)
Screensaver desktop
Secure desktop
I recommend you read this:
https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa375994(v=vs.85).aspx
I don't know my answers are what you want... but I hope it helps in some ways.
I have written a Windows service that allows me to remotely run and stop applications. These applications are run using CreateProcess, and this works for me because most of them only perform backend processing. Recently, I need to run applications that present GUI to the current log in user. How do I code in C++ to allow my service to locate the currently active desktop and run the GUI on it?
Roger Lipscombe's answer, to use WTSEnumerateSessions to find the right desktop, then CreateProcessAsUser to start the application on that desktop (you pass it the handle of the desktop as part of the STARTUPINFO structure) is correct.
However, I would strongly recommend against doing this. In some environments, such as Terminal Server hosts with many active users, determining which desktop is the 'active' one isn't easy, and may not even be possible.
But most importantly, if an application will suddenly appear on a user's desktop, this may very well occur at a bad time (either because the user simply isn't expecting it, or because you're trying to launch the app when the session isn't quite initialized yet, in the process of shutting down, or whatever).
A more conventional approach would be to put a shortcut to a small client app for your service in the global startup group. This app will then launch along with every user session, and can be used start other apps (if so desired) without any juggling of user credentials, sessions and/or desktops.
Also, this shortcut can be moved/disabled by administrators as desired, which will make deployment of your application much easier, since it doesn't deviate from the standards used by other Windows apps...
The short answer is "You don't", as opening a GUI program running under another user context is a security vulnerability commonly known as a Shatter Attack.
Take a look at this MSDN article: Interactive Services. It gives some options for a service to interact with a user.
In short you have these options:
Display a dialog box in the user's session using the WTSSendMessage function.
Create a separate hidden GUI application and use the CreateProcessAsUser function to run the application within the context of the interactive user. Design the GUI application to communicate with the service through some method of interprocess communication (IPC), for example, named pipes. The service communicates with the GUI application to tell it when to display the GUI. The application communicates the results of the user interaction back to the service so that the service can take the appropriate action. Note that IPC can expose your service interfaces over the network unless you use an appropriate access control list (ACL).
If this service runs on a multiuser system, add the application to the following key so that it is run in each session: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run. If the application uses named pipes for IPC, the server can distinguish between multiple user processes by giving each pipe a unique name based on the session ID.
WTSEnumerateSessions and CreateProcessAsUser.
Several people suggested WTSEnumerateSessions and CreateProcessAsUser. I wonder why no one suggested WTSGetActiveConsoleSessionId, since you said you only want to target one logged in user.
Several people sure are right to suggest CreateProcessAsUser though. If you call plain old CreateProcess the way you said, then the application's GUI will run with your service's privileges instead of the user's privileges.
That problems Session 0 , Interactive Services ,
Windows Service Allow Service To Interact With Desktop
on Windows 7 or Windows Vista
You can read this article
http://www.codeproject.com/KB/vista-security/SubvertingVistaUAC.aspx
I try explained here it's working on Windows 7
On Win2K, XP and Win2K3 the console user is logged on in Session 0, the same session the services live in. If a service is configured as interactive, it'll be able to show the UI on the user's desktop.
However, on Vista, no user can be logged on in Session 0. Showing UI from a service there is a bit trickier. You need to enumerate the active sessions using WTSEnumerateSessions API, find the console session and create the process as that user. Of course, you need also a token or user credentials to be able to do that. You can read more details about this process here.
I think as long as you have only one user logged in, it will automatically display on that user's desktop.
Anyway, be very careful when having a service start an exe.
If the write access to the folder with the exe is not restricted, any user can replace that exe with any other program, which will then be run with sytem rights. Take for example cmd.exe (available on all windows sytems). The next time the service tries to start your exe, you get a command shell with system rights...
If you launch a GUI from your service it will show up on the currently active desktop.
But only if you adjusted the service permissions: You need to allow it to interact with the desktop.
Important Services cannot directly interact with a user as of Windows Vista. Therefore, the techniques mentioned in the section titled Using an Interactive Service should not be used in new code.
This is taken from : http://msdn.microsoft.com/en-us/library/ms683502(VS.85).aspx