Cannot send keys to screensaver in windows 10 - windows

How can I send keys to a screensaver in Windows 10. I have tried to install my own screensaver and have disabled logon screen so I only need a keypress to show my desktop. I Guess a part of the problem is use of different desktop, but even With the code shown in the link bellow I cannot figure out how to send a key Message to the screensaver. Any suggestions?
http://www.delphipraxis.net/1059352-post7.html

This is an XY Problem. You are asking how to send keys to a screensaver to deactivate it, so it does not interfere with simulated mouse clicks you want to send to another app. That is the wrong question to ask. You should be asking how to disable the screensaver from running in the first place while your app is busy interacting with the other app.
You say you have disabled the screensaver password. In which case, you can have your app handle the WM_SYSCOMMAND message. If the message's wParam value has the SC_SCREENSAVE flag enabled, discard the message without passing it to the default message handler. Then the screensaver will not run. This only works if your app is in the foreground at the time (SC_SCREENSAVE is only sent to the foreground window), and only if the screensaver password is disabled, though:
If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification—even if fails to pass it to DefWindowProc.
If you need to handle the message while your app is not in the foreground, you can use a global message hook via SetWindowsHookEx() to change WM_SYSCOMMAND/SC_SCREENSAVE messages into WM_NULL when being sent to any HWND in the system.
An alternative approach (only if the screensaver is not already running) is to use SystemParametersInfo() to set SPI_SETSCREENSAVEACTIVE to TRUE to make the system think that a screensaver is already running so it wont start another one (you can use SPI_GETSCREENSAVERRUNNING to check if one is running). This is an old-school way to avoid a screensaver from starting, however on Vista+ onwards with added security policies and such, this probably does not work as well as it once did.
Another alternative is to disable the screensaver in the Registry while your app is busy*. Set the HKEY_CURRENT_USER\ControlPanel\Desktop\ScreenSaveActive value to 0 (just make sure to restore it before your app exits).
*This technique is even used by Windows itself (Vista+) if the user dismisses the screensaver immediately after it starts. Windows assumes the user is annoyed with the screensaver, so the screensaver gets disabled, and is then re-enabled a few minutes later.

I had given up on this but i stumbled over the following code that Works
function KillScreenSaverFunc(Handle: hwnd; Temp: LongInt): Boolean; stdcall;
begin
PostMessage(Handle, WM_CLOSE, 0, 0);
KillScreenSaverFunc := TRUE;
end;
procedure KillScreenSaver;
var
myHDESK:hdesk;
begin
myhdesk := OpenDesktop(Pchar('Screen-saver'), 0, FALSE,
DESKTOP_READOBJECTS or DESKTOP_WRITEOBJECTS);
if myhdesk<>0 then begin
EnumDesktopWindows(myhdesk, #KillScreenSaverFunc, 0);
CloseDesktop(myhdesk);
end;
end;

Related

SetWindowsHookEx(WH_SHELL, ...): What is the meaning of event HSHELL_WINDOWREPLACED?

If I register a hook via SetWindowsHookEx(WH_SHELL, ShellProc, ...), what is the meaning of event HSHELL_WINDOWREPLACED? (My Google-fu fails me. I have searched high and low!)
Win32 Docs:
SetWindowsHookEx(): https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw
ShellProc (callback): https://learn.microsoft.com/en-us/windows/win32/winmsg/shellproc
The offical docs read: A top-level window is being replaced. Weirdly, they also say: Windows 2000: Not supported. Does that mean only supported before or after Win2K?
I created a test driver to watch a Microsoft Windows session, but I was never able to trigger this mysterious event.
I also found a similar event here:
RegisterShellHookWindow: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registershellhookwindow
... that says:
HSHELL_WINDOWREPLACING: A handle to the window replacing the top-level window.
HSHELL_WINDOWREPLACED: A handle to the window being replaced.
Related:
How can I be notified when a new window is created on Win32?
Why HSHELL_WINDOWDESTROYED, HSHELL_WINDOWCREATED?
In this instance, the term "replace" refers to the occasions when a window stops responding to messages ("hangs") and, after a certain period, Windows hides it and replaces it on-screen with a faded-out copy (called a "ghost window").
Windows does this so that, even when the app is not processing messages, the user can interact with the ghost window to move it around and try to close it.
The wParam value is the handle of the hung window (the one being replaced) and the lParam value is the handle of the ghost window (its replacement).
If the window starts responding again, the notification is sent again, with the window handles swapped around.

Why does WM_CLOSE/DESTROY only partially close my Notepad window?

My scenario is that a program calls my DLL and I use Process.Start(notepad) to start a Notepad window on Windows 10 x64. I don't save the process ID of the started process. Then sometime later, a program calls my DLL again, and I find the Notepad window handle (by matching title strings).
The problem is that when I use the handle to send the window a WM_CLOSE or DESTROY message, the job isn't completed. The window does disappear from my screen. It does disappear from the taskbar. But when I look at windows with Alt-TAB, there it is. It's not really gone; it's just hidden from the taskbar. I'm using this Win32 API call to try to close the window.
[DllImport ("user32.dll", SetLastError = true)]
public static extern bool CloseWindow (IntPtr hWnd);
(1) What am I doing wrong?
(2) Are my expectations out of line? Is it even possible for me (as a DLL running under one process) to order Notepad in another process to close?
I suppose, having the Notepad handle in hand, that I could bring it to the foreground and send Alt+F4 to its keyboard buffer somehow to fake it into thinking that I was typing characters to it. But, that seems like the long way around.
(3) How can I programmatically tell apps to close their windows without bringing them to the foreground and sending them keystrokes, or without sending them mouse clicks on the X close button?
I've looked at other posts on the forum, but they mostly talk about terminating the process with the process APIs - a brute force kill method that isn't really what I want to do. (Besides, I want to close the single window that I'm interested in, not a whole process that might be running a dozen different windows like MS Word...)
I'm using [CloseWindow] to try to close the window.
CloseWindow doesn't close a window -- it minimizes it.
Instead, send the window a WM_CLOSE message:
SendMessage(h, WM_CLOSE, 0, 0);
Try doing this:
SendMessage (hWnd, WM_SYSCOMMAND, SC_CLOSE, 0); // or PostMessage perhaps better
This is what Windows sends when you click on the Close box and is much more likely to work in a wider range of apps since the app will then believe that it has been closed by the user and should act accordingly.

How to know if the user force quit app?

In my mac application I am supporting full screen by changing system resolution of the device. And I am resetting back to old resolution if the user switches from full screen to windowed mode or if user quits the app and I need to handle force quit case also.
1. Is there any API or callback which tells the application if the user presses cmd+opt+esc(force quit).
2. Any other way to handle this?
I know in NSApplicaction there is an option to disable force quit([NSApplication setPresentationOptions: NSApplicationPresentationDisableForceQuit]) but instead of disabling it I want to handle force quit event.
The general consensus is that force quit sends a SIGKILL ("consensus" as I don't know any Apple documentation that states this, but it is the logical answer). A SIGKILL cannot be caught so you cannot do cleanup directly. An alternative is to run a helper application which monitors you main app and does the cleanup, the main app can terminate the helper on normal exit. See also this question.

Receive screensaver notification

I want to receive a notification in my C++ application when a screensaver is about to start. I tried listening to WM_SYSCOMMAND messages with wParam == SC_SCREENSAVE which some people think should do the trick.
That didn't work. Spy++ even showed that my window didn't receive any WM_SYSCOMMAND message. Interesting thing is when I turned off the monitor I did receive the message with wParam == SC_MONITORPOWER. Am I understanding it wrong? Or did I just miss something?
Edit: For testing I used the default windows screensaver (the one with windows logo).
It appears that I will receive the SC_SCREENSAVE message only when my window has focus. The way around this is to set global hook. That would require me to put the callback function in a separate DLL and there is also this scary message about hooks slowing down the system so I decided to drop the idea of responding to screensaver start.
This is a relatively complex task (although it would be nice if it were easy).
Some of these tests you'll find online only work if your window is in focus. If it's running in the background it may not receive such messages.
Other tests rely on a screensaver program running (check the currently set screensaver, and then watch the process list to see if it's active) but don't work if you go into powersave mode, or if your screensaver is a black screen (ie, no program, just monitor off).
I don't believe there's an ideal way to do this. You might want to go back to the beginning and think more carefully about why you need to detect this state, and what you are trying to accomplish. You might need a different solution.
Probably my answer comes too late.
The MSDN handles screensavers under "Legacy".
On a notebook they waste battery and on a PC they are also useless.
It is better to turn the monitor off than letting it show a screensaver.
As you don't explain exactly what you want to do I don't know if you really need the notification BEFORE the saver starts or if it is enough to get notified when it already has just started.
In the latter case it is easy.
Write a thread that periodically checks:
BOOL b_SaverRunning;
SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &b_SaverRunning, 0);

How do I send key strokes to a window without having to activate it using Windows API?

I have made an application already that sends commands to an activated window. I want to be able to use the computer while my process is running because as soon as I switch focus to another window the key strokes being sent via send keys will go to the window I just switched to.
Currently I use FindWindow, IsIconic, and ShowWindow from the Windows API. I have to check to see if the window is there with FindWindow and set my object to the specific window that is returned with that call, I then check if it's minimized with IsIconic and call ShowWindow if it is, and then finally I have to call Interaction.AppActivate to set focus to that window. All of this is done before I even send key strokes. Seems like there should be a way to just send key strokes without having to show the window and activate it. The big thing is while my application is running the key strokes I can't do anything on my computer.
Alright, this is kind of disappointing I'm sure, but you fundamentally cannot do this with 100% reliability.
Windows assumes that the active window is the one getting keyboard input. The proper way to fake keyboard input is with SendInput, and you'll notice that it sends messages to the active window only.
That being said, you can SendMessage WM_KEYUP, WM_CHAR, and WM_KEYDOWN messages and (depending on the WndProc receiving them) maybe get away with it. But remember, its going to break under some circumstances, period.
Sounds like you are using keybd_event() or SendInput(), which both send keystrokes to the currently active window. To direct keystrokes to a specific window, regardless of whether that widnow is focused or not, you need to find its HWND handle first, and then post appropriately-formatted WM_KEYUP/DOWN and WM_CHAR messages directly to it.
once you have the windows HWND, you can directly SendMessage() the WM_KEYDOWN and WM_KEYUP messages to its message queue. The window does not have to be active.
However, understand that this depends on how the target application processes keyboard input. There are several different ways to handle it.
WM_KEYUP/WM_KEYDOWN is most common and some applications only process one or the other (usually WM_KEYDOWN).
WM_CHAR is also fairly common
Some programs use GetAsyncKeyState, GetKeyState, or GetKeyboardState. This is extremely unusual, but effectively prevents keypress injection with SendMessage(). If this is the case fall back to keybd_event() which is directly handled by the keyboard driver. Of course the window will have to be active

Resources