take a screenshot of a desktop created using createdesktop api - windows

i am using the createdesktop api to create a desktop and i would like to take a screenshot or send input mouse/keyboard without dispalying the desktop to the user.any ideeas on how to implement this???

The short answer that I've found is that you can't. You can't take a screenshot of an inactive desktop because there are no paint calls because there are no visible windows to redraw.
You can do a SwitchDesktop() call, screen shot, then SwitchDesktop() back. The user won't notice it, but you likely won't get much in the screen shot because in this short time the windows haven't had time to redraw.
Another thing is, you have to make a new thread to call SetThreadDesktop(). If you use your main thread to do so, it will fail when using a GUI application. SetThreadDesktop() fails when you have a window in the current desktop.
SysInternals has an application to manage multiple desktops (like the linux desktop switch). When your about to pick a desktop to switch to it will show you a thumbnail of the desktop. This thumbnail is not live, it is captured by the last known full redraw when the user is in that desktop. In short, if SysInternals can't do a live screenshot I doubt any of us will.
This is of course based on my own research of this exact feature. If someone has actually gotten it to work I'd love to know so I can't use it too!

Edit: This won't work for invisible desktops, I've looked to my old code, and I see that I needed that for catching screenshot of active desktop (which was not 'WinSta0\Default'), to get handle of active user desktop I've used OpenInputDesktop.
+1 ThievingSix you are right.
Sorry everyone for my misunderstanding.
You need to use SetThreadDesktop (if you are creating desktop by CreateDestkop, then you have handle for it which you pass to SetThreadDesktop). After switching desktop for thread, you can catch screenshot. Good idea would be revert to previous desktop for thread (to not 'break' other/future code).
var
lOldDesktop: HDESK;
begin
lOldDesktop:= GetThreadDesktop(GetCurrentThreadId);
try
if not SetThreadDesktop(ADesktop) then // pass handle to your desktop, or dekstop handle obtained from OpenInputDesktop
{error handle, like RaiseLastOSError or Exit(False)};
// your screenshot/input/mouse code here
finally
if lOldDesktop<> 0 then // GetThreadDesktop can fail (I don't know condition when this GetThreadDesktop(GetCurrentThreadId) could fail)
SetThreadDesktop(lOldDesktop); // revert thread to previous desktop
end;
end;
This code should run in non-main thread, as ThievingSix pointed because SetThreadDesktop can fail in that case. Safe way is spawn thread to make screenshot.
PS. I'm not sure if this will work with "send input mouse/keyboard" (it should), but for screenshot works.
Edit:
More on sessions, window stations, desktops here http://blogs.technet.com/b/askperf/archive/2007/07/24/sessions-desktops-and-windows-stations.aspx
Desktop tool (SysInternals) - http://technet.microsoft.com/en-us/sysinternals/cc817881

Related

Intercepting a window's attempt to steal global focus on Windows

I'm a developer and a long-time Windows user with an obsession about making my system as convenient to use as possible.
Yesterday I thought about something that has always annoyed me in Windows and that I've taken for granted, and I realized that I have a better idea for how it could work, and I'm now wondering whether it's possible to tweak Windows to work like that.
The thing that annoys me is when windows steal focus. For example, I could be running an installer for some program. While it's working, I'll switch to my browser and browse, maybe entering some text into an email in my browser. Then suddenly the installer finishes and its window steals the focus. Now I'm in the middle of writing an email, so I might press a key that happens to be bound to a button on that installer, and then that button gets invoked, doing some action that I never intended to happen!
This is doubly annoying to me because I'm using a multiple-desktop program called DexPot, and when a window steals focus, it also brings itself to the desktop I'm currently on, which can be really annoying, because then I have to put it back into its original desktop.
How my ideal solution to this problem would work: Every time a window tries to steal focus, we intercept that, and don't let it. We show something like a toaster message saying "Foobar installer wants focus, press Win-Whatever to switch to it". If and when you press the key combo, it switches to the window.
The question is: Is there an easy way to tweak Windows to make this happen? I know very little about Windows programming. I do know AHK and if it's possible with that, that'd be great.
No, there isn't an easy way to add this behavior, but Windows tries to do this automatically.
In theory apps shouldn't be able to steal the foreground while you're actively using another app. Unfortunatly there are some scenarios where Windows can't tell the difference between legitimate user actions that should change the foreground and unwanted foreground-theft. The window manager generally tightens up the holes a bit with each new version of Windows, but also needs to make sure that apps can come to the foreground when the user wants them to, even if that desire is expressed indirectly.
For example, a process launched by the current foreground process can put a window into the foreground. This is necessary so that when a user launches a window from Explorer the newly launched process can open its main window. This permission only lasts until the next user input, so if an application is slow to launch and you start working on an email the app may lose its foreground permissions before it can use them.
See the SetForegroundWindow function documentation for a list of requirements for a process to be able to set a window into the foreground.
There are also apps which specifically make use of these requirements to steal the permission (by joining the foreground queue or synthsising user input to themselves), but I suspect in your installer scenario it is accidental.
I'm not sure what exactly is going on, but I suspect that the problem comes from the installer running as a service and accidentally stealing the foreground permission when it tries to launch the app on your current desktop.
It would be theoretically possible for an external process to hook into the foreground system to override this and show your confirmation toast, but it would be tricky to get right and would require significant low level code (I'd probably start with a CbtHook). It would not be possible in a scripting package like AHK (assuming you mean AutoHotKey) but would need to be native C/C++ code injected into every running process.

How to write a program that runs another GUI program inside it

I am not sure how to ask the question so here is a picture of some idea that came to mind
So for example, when you run my "custom launcher" it displays a window with a couple buttons on the side which you can assign values to. When you click on a button, the appropriate program will run in the big panel on the right (in window mode).
This is all from the user's perspective of course. They will just see that the program they want to run appears in that panel. The actual implementation may have nothing to do with "one program running inside another program"
My own use case is limited to windows desktop platforms only, but if it is possible to generalize it that would be nice as well.
Is this actually possible? Can I write such a program that will run another program inside a panel? The program that's launched may be someone else's, such as MS paint or calculator.
Just to expand on my comment above, here is an approach that may work for you: Fake it :)
When you launch the program, intercept all windows messages to the program that control it's position on screen. That way it 'appears' to be fixed in place, but in reality it's still attached to the normal Windows desktop.
Here's some light reading for you:
Windows Event Hooks
A hook is a mechanism by which an application can intercept events,
such as messages, mouse actions, and keystrokes. A function that
intercepts a particular type of event is known as a hook procedure. A
hook procedure can act on each event it receives, and then modify or
discard the event.
I would recommend against it in a commercial application because you are modifying the behavior of software you don't own - that software may make assumptions about what its parent window is, but for experimentation there's the SetParent Win32 function.

What happens 'behind' the windows lock screen?

I have been working on windows automation and monitoring.
What exactly happens when I lock the screen of a windows machine?
I am working with Windows 7 at the moment, are there big differences to the behavior if I switch to Vista or the server versions?
Is there still a desktop that can be accessed via api's?
I know that i can still send key strokes and mouse clicks to specific windows (via ControlSend and ControlClick), but there seems to be no "desktop" itself.
Could someone shed some light on this whole thing or point me at a readable source where I could get an overview over the topic?
Basically what happens is that Windows switches to the secure desktop, makes it the current one, so input is now associated with it.
The old desktop remains where it was: all the HWNDs on the desktop are still there, and any thread attached to that desktop can still access those HWNDs, get their location, and so on. You can still send messages to windows on this desktop, so long as the thread sending the message is also on that desktop.
However, since the desktop is now inactive, it cannot receive input. GetForegroundWindow will return NULL (IIRC), and you can't use SendInput any longer, since input now belongs to [a thread on] a different desktop; no controls on that inactive desktop can receive focus.
Note that sending keypress messages to a control that doesn't have focus can sometimes cause unexpected behavior, since the app or control generally never expects to receive keyboard input without getting the focus first. (This can be problematic for controls that set up some sort of input context in WM_SETFOCUS and clear it up in WM_KILLFOCUS, for example.)
In short, the UI is still there: you can do certain queries against it, but you can no longer automate it as you could on a regular desktop by sending input, and some other functions that relate to focus or input may fail.
I'm not super familiar with AutoHotKey, but the name and description of functionality suggests that it's heavily reliant on the underlying Win32 SendInput API. This won't work at all for keyboard input when a desktop is inactive.
For a reasonable overview of how desktops work and how they relate to winstations, the locked desktop, and so on, check out the Desktop article on MSDN.
One issue that I've run into in the past with desktops and automation is: how to I leave a long-running test that's using some form of user input automation (mouse, keyboard simulation), but still lock my PC so that someone can't just walk by and interfere with it. Once you lock the PC, the desktop is inactive, and so the automation stops working. A similar issue happens if the screensaver kicks in: the desktop switches, and the automation fails.
One solution is to use two PCs: let's call them Main and Test: from Main, open a remote terminal services client onto the Test machine, and then run the automated test on the test machine, but from a terminal services client window on the Main machine. Now the cool part: you can minimize that TSC window, or even lock the Main machine (or let the screensaver kick in), and that virtual session will continue working, thinking that it is still active - it's just that nobody is paying it any attention. This is one way to create a "connected" session with an active desktop, but one that no-one can interfere with, because it's protected behind the locked desktop of the Main machine.
I don't know the details, but I believe the lock screen constitutes a separate "desktop" and maybe also a separate "window station" (as I understand it a window station is merely a container for desktops). The MSDN section on window stations should hopefully be useful: http://msdn.microsoft.com/en-us/library/windows/desktop/ms687098%28v=vs.85%29.aspx
In order to access a desktop, you will need to use the regular windows api's from a thread that is on that desktop. SetThreadDesktop would probably be the easiest way to do that in C, as long as the desktop isn't on a different window station.
Unfortunately, this is already difficult for a regular privileged application, and using AutoHotkey complicates it even more. Since you don't have control over threads or over process initialization, you will probably have to create a new process in the other desktop (you can do this using the CreateProcess API, which appears to have a wrapper available for AHK to which you can supply a desktop name: http://www.autohotkey.com/forum/topic1952.html). Your process will need special privileges to do this; I'm not sure that even running as Administrator is enough.

Create a Program that Sits in The Windows Taskbar and, When Activated, Stops the Screensaver From Starting

I don't really know where to begin. Let's start with the stupid questions:
What language should I use for this? What is suited for the task at hand?
Next, the real ones:
Is there a way to stop the screensaver from starting, short of changing the cursor position? If not, will changing the cursor position even work?
SetThreadExecutionState will prevent the screensaver from coming on or the machine from automatically going to sleep if you pass the ES_CONTINUOUS and ES_DISPLAY_REQUIRED flags.
I wrote an app awhile ago that does exactly what you are asking for. It runs as an icon in the System Tray, not the Taskbar, and uses a global message hook to disable the WM_SYSCOMMAND/SC_SCREENSAVE notification from reaching any applications. If that notification does not reach the DefWindowProc() function, the screen saver will never run.
Your program does not need to be visible in the task bar at all.
You don't even need a program at all, if you can disable the screensaver in the registry.
What you want to do can perhaps be achieved by sending a MOUSE_MOVE event to the desktop window. If you want to use C# (the only language I am current with right now), you can look at this article, but maybe a simple C program using the WinAPI is better suited for this task.
.NET will easily allow you to put an application in the system tray (checkout the NotifyIcon object in System.Windows.Forms.Controls).
I believe you can use the SetCursorPos (http://msdn.microsoft.com/en-us/library/ms648394(VS.85).aspx) API call to prevent the screen saver, just make sure you set them to the current location so you don't actually move the mouse.

How to determine that a screensaver is running?

One solution that one could suggest is to periodically look for a special 'Screen-saver' desktop, and if it's present then count it as a running screensaver.
But apparently this is not the case for all screensavers as with some the mentioned desktop is always present.
Are there more reliable solutions for this?
See the WINAPI function SystemParametersInfo() with the SPI_GETSCREENSAVERRUNNING parameter. It's the only documented way to detect whether the screen saver is currently running. (You can also find out if a screen saver is even enabled, get and set the timeout value, and start the screen saver using this function.)
I think the key is to identify the screensaver by its window class ("WindowsScreenSaverClass"). I found this page
How do I start, detect and stop screen savers? that has some code examples and explanations.
HOW TO: Determine If Screen Saver Is Running by Using Visual Basic 6.0
I know this is for VB6, but it's bound to be a good place to start.
This is my implementation of screen saver event detection.
Notes:
SPI_GETSCREENSAVERRUNNING detects Windows Event id 4802 and 4803 which weren't accurate in my case, see my problem hence user idle time calculation is added
GetLastInputInfo apparently doesn't work if process is a service.
search processes for a process with .scr in its .MainModule.FileName

Resources