Minimize all open windows? - winapi

I need to perform the same task as WindowsKey + M through code, ie. minimize all open windows. This must be done through the Win32 API, not .Net.
I tried the following in FreeBasic, but nothing happens:
Dim hWndConsole As HWND
'Shell_TrayWnd = class name of taskbar
Dim WindowName as String = "Shell_TrayWnd"
hWndConsole = FindWindow(0, strptr(WindowName))
ShowWindow(hWndConsole, SW_MINIMIZE) 'outta my sight
Does someone know how to do this?
Thank you.
Edit: Here's the working solution:
#include "Windows.bi"
Dim hWndConsole As HWND
'Shell_TrayWnd = class name of taskbar
Dim WindowName as String = "Shell_TrayWnd"
Dim res as LRESULT
CONST minall = 419
hWndConsole = FindWindow( "Shell_TrayWnd",null)
res = postMessage(hWndConsole, WM_COMMAND, minall, null )

This seems like a bit of a hack to me, but the following does seem to accomplish what you are looking for (in C):
HANDLE hwnd = FindWindow( "Shell_TrayWnd", NULL );
LRESULT res = SendMessage( hwnd, WM_COMMAND, (WPARAM)419, 0 );

When you have the handle of a window, you can make it minimize with the WM_SYSCOMMAND message. E.g.:
SendMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
So all you would need to do is enumerate the top-level windows (with the EnumWindows command) and send that command to the windows you want to minimize (which wouldn't be all top-level windows - probably only visible, overlapped windows without the WS_EX_TOOLWINDOW extended style should be minimized like this).

Putting this out as an option, not a recommendation - simulating the keyboard events for Win-M:
keybd_event(VK_LWIN, 0, 0, 0);
keybd_event('M', 0, 0, 0);
keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);

Related

Windows API: Simple window does not redraw correctly

I'm working on a Lua binding for Windows API. So far I've been able to create a basic window with a list box control:
require('Alien')
package.path = 'libs\\?.lua;libs\\?\\init.lua;' .. package.path
local function printf(...) io.write(string.format(...)) end
Windows = require('Windows')
local W = Windows
print("loaded OK")
print("Command line=", W.GetCommandLine())
local windowClassName = "testWindow"
local windowClass, window
local hInstance = assert(W.GetModuleHandle(nil))
assert(W.WM_CREATE)
assert(W.WM_CLOSE)
assert(W.WM_DESTROY)
assert(W.DefWindowProc)
assert(W.DestroyWindow)
assert(W.PostQuitMessage)
local msgID = {}
for k, v in pairs(Windows) do
if k:match('^WM_') then msgID[v] = k end
end
local function wndProc(hWnd, msg, wParam, lParam)
local id = msgID[msg] or ('%08X'):format(msg)
printf('wndProc(%08X, %20s, %08X, %08X\n',
hWnd,id, wParam, lParam)
if msg == W.WM_CREATE then
printf("window %08X create\n", hWnd)
elseif msg == W.WM_CLOSE then W.DestroyWindow(hWnd)
elseif msg == W.WM_DESTROY then W.PostQuitMessage(0)
else return W.DefWindowProc(hWnd, msg, wParam, lParam)
end
return 0
end
local wndProcCB = alien.callback(wndProc,
assert(W.LRESULT), assert(W.HWND),
assert(W.UINT), assert(W.WPARAM), assert(W.LPARAM))
windowClass = assert(W.WNDCLASSEX:new {
cbSize = assert(W.WNDCLASSEX.size),
style = bit.bor(W.CS_HREDRAW, W.CS_VREDRAW),
lpfnWndProc = assert(wndProcCB),
cbClsExtra = 0,
cbWndExtra = 0,
hInstance = assert(hInstance),
hIcon = nil,
hCursor = nil,
hbrBackground = assert(W.COLOR_APPWORKSPACE)+1,
lpszMenuName = nil,
lpszClassName = assert(windowClassName),
hIconSm = nil,
})
assert(W.RegisterClassEx(windowClass))
local dwExStyle = bit.bor(
W.WS_EX_TOOLWINDOW,
W.WS_EX_OVERLAPPEDWINDOW)
local dwStyle = bit.bor(
W.WS_OVERLAPPEDWINDOW,
W.WS_CLIPSIBLINGS,
W.WS_CLIPCHILDREN)
window = assert(W.CreateWindowEx(
assert(dwExStyle), --dwExStyle
assert(windowClassName), --lpClassName
"Test Window", --lpWindowName
assert(dwStyle), --dwStyle
assert(W.CW_USEDEFAULT), --x
assert(W.CW_USEDEFAULT), --y
420, 314, --width, height
nil, nil, assert(hInstance), nil)) --hWndParent, hMenu, hInstance, lpParam
local SWP_SHOW_ONLY = bit.bor(
W.SWP_ASYNCWINDOWPOS,
W.SWP_SHOWWINDOW,
W.SWP_NOACTIVATE,
W.SWP_NOMOVE,
W.SWP_NOSIZE,
W.SWP_NOZORDER)
W.SetWindowPos(assert(window), nil, 0, 0, 0, 0, assert(SWP_SHOW_ONLY))
local msg = assert(W.MSG:new())
while W.GetMessage(msg, 0, 0, 0) do
W.TranslateMessage(msg)
W.DispatchMessage(msg)
end
It creates and displays a window, but the window doesn't redraw correctly. From the console output I can see lots of WM_PAINT, WM_ERASEBKGND, WM_NCPAINT etc, which I pass on to DefWindowProc, but it seems to be not handling them.
Example screenshots:
When the window first appears, it either takes the image of whatever was behind it (as in this case) or appears solid gray. As it's dragged around, it keeps that image and anything that drags over it leaves behind a ghost image. (Can be seen on the titlebar, where I have a small white button following the active window around.) If I drag it off screen a bit, it starts to get even more glitchy but never successfully repaints itself.
I've tried various methods of handling WM_PAINT, WM_ERASEBKGND, etc but none have had any effect. Examples don't show these messages being handled either. Am I doing something wrong, or is there something else I need to be doing?
Well, I found the issue (I hope) with the help of Rohitab API Monitor. It was indeed a problem with the Lua binding: it had DefWindowProc declared as taking four int parameters. That's mostly fine, until we get a WM_ERASEBKGND message with a wParam (a handle to a device context) which is > 0x7FFFFFFF, and the call to DefWindowProc fails at converting that to an int and passes the wrong value. So the window never renders certain items to the correct device context. My debug logging (which wraps Windows API functions to print their parameters to the console) didn't catch this either, since it was logging the value before it got mangled.
Changing the declaration to use uint seems to have resolved it. (And maybe I can use API Monitor's definition files for my bindings, since the ones I have seem to be somewhat inaccurate.)

What is wrong with PrintWindow?

What is wrong with the following code? Why does PrintWindow return 0?
HWND hwnd = GetDesktopWindow();
CHK(hwnd);
HDC hdc = GetWindowDC(hwnd);
CHK(hdc);
if (hdc)
{
HDC hdcMem = CreateCompatibleDC(hdc);
CHK(hdcMem);
if (hdcMem)
{
RECT rc;
CHK(GetWindowRect(hwnd, &rc));
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top);
CHK(hbitmap);
if (hbitmap)
{
SelectObject(hdcMem, hbitmap);
CHK(PrintWindow(hwnd, hdcMem, 0)); //HERE return 0
DeleteObject(hbitmap);
}
DeleteObject(hdcMem);
}
ReleaseDC(hwnd, hdc);
}
PrintWindow is a fairly thin operation. What it really does is post a WM_PRINTmessage to the queue for the window in question, in this case the desktop, and hopes that that window will respond to WM_PRINT correctly if at all (see here and here).
I repro'd your behavior but I'm not 100% sure why it's failing either. Perhaps you cannot call PrintWindow on an HWND that your process does not own, or perhaps the desktop does not respond to WM_PRINT messages.
The second link above includes a comment about using BitBlt instead:
Try getting a handle (HWND) to the
desktop window - and use BitBlt to
capture all the contents. Mind you -
you'll only capture what is visible on
the screen.
Maybe this helps.
It looks like GetDesktopWindow() returns a virtual HWND whose value is universally 0x0010010 on all Windows machines. This virtual HWND does not conform to usual PrintWindow behavior so the PrintWindow() returns FALSE, and GetLastError() reports no error code on this PrintWindow call.
To make PrintWindow() work, you can instead use the HWND from GetShellWindow(), which has the title "Program Manager" from the WinSpy++ figure below.
Replace:
HWND hwnd = GetDesktopWindow();
With:
HWND hwnd = GetDesktopWindow();
hwnd = FindWindowEx( hwnd, 0, _T("Progman"), _T("Program Manager") );
I'm not sure whether this gets what you want though. If you want to take a screenshot of the entire current desktop (including whatever top level windows are visible) then BitBlt is the route you want to take.
If you want to get the taskbar as well, you can still use this method but you'll have to take 2 screenshots and stitch the results together.

Increasing the size of console output display

Can we change/increase the size of console output to view large size of data in console application at once?
There seem to be different ways to Rome:
This should be the recommended way I would think, cause the name says it all: GetConsoleWindow as is demonstrated here.
A quick hack might be the windows API function SendInput. If you simulate Alt+Enter, you could probably fullscreen the active window.
Here are some propositions using API calls from user32.dll
Check out the SetConsoleScreenBufferInfoEx API. It takes a CONSOLE_SCREEN_BUFFER_INFOEX as input and that has a dwSize member which contains the size of the console screen buffer, in character columns and rows.
MSDN for SetConsoleScreenBufferInfoEx Function: http://msdn.microsoft.com/en-us/library/ms686039(v=VS.85).aspx
I once used a small hack that is first setting the console's output buffer and then trying to find the console window and resize it. It worked well on XP, I never tested it on newer Windows versions.
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
SMALL_RECT sr;
sr.Top = 0;
sr.Left = 0;
sr.Bottom = 10;
sr.Right = 79;
SetConsoleWindowInfo(h, TRUE, &sr);
TCHAR title[512];
GetConsoleTitle(title, 512);
HWND hWnd = FindWindow(NULL, title);
if(hWnd != NULL) {
HWND hWndInsertAfter = NULL;
UINT nFlags = SWP_NOSIZE | SWP_NOZORDER;
#if 0 // Don't move?
nFlags |= SWP_NOMOVE;
#endif
SetWindowPos(hWnd, hWndInsertAfter , 40, 350, 0, 0, nFlags);
SetForegroundWindow(hWnd);
}
If you are using the command prompt window, right click it's label on the task bar and click the Properties option.

Determining if a Window Has a Taskbar Button

I am looking for a way to check if a given window has a taskbar button. That is, given a handle to a window, I need a TRUE if the window is in the taskbar, and FALSE otherwise.
Conversely, I am wondering if there is a way to get a handle to the window that belongs to a given taskbar button, which I suppose would require a way to enumerate through the taskbar buttons.
(The first former is the part that I need, and the latter part is optional.)
Thanks a lot.
Windows uses heuristics to decide whether or not to give a taskbar button to a window, and sometimes there is a delay before it can decide, so doing this 100% accurately is going to be quite hard. Here's a rough start on the rules. There are modern style flags that make it easy to know, but when those styles are missing the taskbar is reduced to guessing.
First off, you will need both of the the window style flags.
LONG Style = GetWindowLong(hwnd, GWL_STYLE);
LONG ExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
Now the rules, there are three rules that are certain.
if ExStyle & WS_EX_APPWINDOW, then TASKBAR
if ExStyle & WS_EX_TOOLWINDOW, then NOT_TASKBAR
if Style & WS_CHILD then NOT_TASKBAR
The rest are guesses:
Style & WS_OVERLAPPED suggests TASKBAR
Style & WS_POPUP suggests NOT_TASKBAR especially if GetParent() != NULL
ExStyle & WS_EX_OVERLAPPEDWINDOW suggests TASKBAR
ExStyle & WS_EX_CLIENTEDGE suggests NOT_TASKBAR
ExStyle & WS_EX_DLGMODALFRAME suggests NOT_TASKBAR
I'm sure that there are other rules for guessing, and in fact that the guessing rules have changed from version to version of Windows.
Toplevel window
WS_EX_APPWINDOW -> taskbar, no matter the other styles!
OWNER must be NULL (GetWindow(window, GW_OWNER))
no: WS_EX_NOACTIVATE or WS_EX_TOOLWINDOW:
order is important.
second question: in windows xp/vista it was possible to get into the process of the taskbar and get all window ID´s:
void EnumTasklistWindows()
{
int b2 = 0;
TBBUTTON tbButton;
DWORD dwProcessId = 0, dwThreadId = 0;
HWND hDesktop =::GetDesktopWindow();
HWND hTray =::FindWindowEx(hDesktop, 0, ("Shell_TrayWnd"), NULL);
HWND hReBar =::FindWindowEx(hTray, 0, ("ReBarWindow32"), NULL);
HWND hTask =::FindWindowEx(hReBar, 0, ("MSTaskSwWClass"), NULL);
HWND hToolbar =::FindWindowEx(hTask, 0, ("ToolbarWindow32"), NULL);
LRESULT count =::SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0);
dwThreadId = GetWindowThreadProcessId(hToolbar, &dwProcessId);
shared_ptr<void> hProcess (OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId), CloseHandle);
if (NULL == hProcess.get())
{
return;
}
memset(&tbButton, 0, sizeof(TBBUTTON));
for (int i = 0; i < count; i++)
{
memset(&tbButton, 0, sizeof(TBBUTTON));
shared_ptr<void> lpRemoteBuffer (
VirtualAllocEx(hProcess.get(), NULL, sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE),
bind<BOOL>(VirtualFreeEx, hProcess.get(), _1, 0, MEM_RELEASE));
if (NULL == lpRemoteBuffer.get())
{
return;
}
SendMessage(hToolbar, TB_GETBUTTON, i, (LPARAM) lpRemoteBuffer.get());
b2 = ReadProcessMemory(hProcess.get(), lpRemoteBuffer.get(),
(LPVOID) & tbButton, sizeof(TBBUTTON), NULL);
if (0 == b2)
{
continue;
}
BYTE localBuffer[0x1000];
BYTE *pLocalBuffer = localBuffer;
DWORD_PTR ipLocalBuffer = (DWORD_PTR) pLocalBuffer;
pLocalBuffer = localBuffer;
ipLocalBuffer = (DWORD_PTR) pLocalBuffer;
DWORD_PTR lpRemoteData = (DWORD_PTR) tbButton.dwData;
ReadProcessMemory(hProcess.get(), (LPVOID) lpRemoteData, (LPVOID) ipLocalBuffer,
sizeof(DWORD_PTR), NULL);
HWND windowHandle;
memcpy(&windowHandle, (void *) ipLocalBuffer, 4);
if (windowHandle != NULL)
{
trace ("adding button: %x\n", windowHandle);
}
}
}
this not possible with windows 7 anymore. so you need to loop over all toplevel windows.
This MSDN article has some good information about when and why the Shell decides to create a taskbar button for a window:
The Shell creates a button on the taskbar whenever an application creates a window that isn't owned. To ensure that the window button is placed on the taskbar, create an unowned window with the WS_EX_APPWINDOW extended style. To prevent the window button from being placed on the taskbar, create the unowned window with the WS_EX_TOOLWINDOW extended style. As an alternative, you can create a hidden window and make this hidden window the owner of your visible window.

Programmatically prevent Windows screensaver from starting

Is there a recommended way to prevent the Windows screensaver from starting? The closest thing I've found is this article, but what I would really like to do is just tell Windows that the computer isn't idle rather than fooling with the currently set screensaver values.
For testing, I set the screensaver to 1 minute and required a password.
I tried capturing SC_SCREENSAVE and returning -1 in VB .Net. As commented, it works when there is no screensaver password but fails if the screensaver password is active. (I tried it in Windows XP). I also put this into a Timer's tick event, every 1000 milliseconds:
Static dir As Integer = 4
Cursor.Position = Cursor.Position + New Size(dir, dir)
dir = -dir
It doesn't work. The cursor jiggles back and forth and after 1 minute the screensaver flashes on for a short instance and then turns off. The screensaver turns on for only a moment, not long enough to require a password. But still, the flash is ugly.
Then I tried using user32.dll's SetCursorPos and GetCursorPos. You can look them up at pinvoke. Same result as above.
Then I peeked at the code of "JiggleMouse" mentioned elsewhere in this question. JiggleMouse uses SendInput. SendInput works! No flash of the screensaver. I put a call to SendInput inside of a Timer that triggers every 50 seconds (just less than the minimum screensaver timeout of 60 seconds). It's sufficient to move the mouse by a delta of 0,0, no real movement. That does work. The code to put in the Tick event:
Dim i(0) As INPUT
i(0).dwType = INPUT.InputType.INPUT_MOUSE
i(0).mkhi = New MOUSEKEYBDHARDWAREINPUT
i(0).mkhi.mi = New MOUSEINPUT
i(0).mkhi.mi.dx = 0
i(0).mkhi.mi.dy = 0
i(0).mkhi.mi.mouseData = 0
i(0).mkhi.mi.dwFlags = MOUSEINPUT.MouseEventFlags.MOUSEEVENTF_MOVE
i(0).mkhi.mi.time = 0
i(0).mkhi.mi.dwExtraInfo = IntPtr.Zero
SendInput(1, i(0), Marshal.SizeOf(i(0)))
This comes from pinvoke.com:
Public Declare Function SendInput Lib "user32" (ByVal nInputs As Integer, ByRef pInputs As INPUT, ByVal cbSize As Integer) As Integer
Public Structure INPUT
Enum InputType As Integer
INPUT_MOUSE = 0
INPUT_KEYBOARD = 1
INPUT_HARDWARE = 2
End Enum
Dim dwType As InputType
Dim mkhi As MOUSEKEYBDHARDWAREINPUT
End Structure
Public Structure MOUSEINPUT
Enum MouseEventFlags As Integer
MOUSEEVENTF_MOVE = &H1
MOUSEEVENTF_LEFTDOWN = &H2
MOUSEEVENTF_LEFTUP = &H4
MOUSEEVENTF_RIGHTDOWN = &H8
MOUSEEVENTF_RIGHTUP = &H10
MOUSEEVENTF_MIDDLEDOWN = &H20
MOUSEEVENTF_MIDDLEUP = &H40
MOUSEEVENTF_XDOWN = &H80
MOUSEEVENTF_XUP = &H100
MOUSEEVENTF_WHEEL = &H800
MOUSEEVENTF_VIRTUALDESK = &H4000
MOUSEEVENTF_ABSOLUTE = &H8000
End Enum
Dim dx As Integer
Dim dy As Integer
Dim mouseData As Integer
Dim dwFlags As MouseEventFlags
Dim time As Integer
Dim dwExtraInfo As IntPtr
End Structure
Public Structure KEYBDINPUT
Public wVk As Short
Public wScan As Short
Public dwFlags As Integer
Public time As Integer
Public dwExtraInfo As IntPtr
End Structure
Public Structure HARDWAREINPUT
Public uMsg As Integer
Public wParamL As Short
Public wParamH As Short
End Structure
Const KEYEVENTF_EXTENDEDKEY As UInt32 = &H1
Const KEYEVENTF_KEYUP As UInt32 = &H2
Const KEYEVENTF_UNICODE As UInt32 = &H4
Const KEYEVENTF_SCANCODE As UInt32 = &H8
Const XBUTTON1 As UInt32 = &H1
Const XBUTTON2 As UInt32 = &H2
<StructLayout(LayoutKind.Explicit)> Public Structure MOUSEKEYBDHARDWAREINPUT
<FieldOffset(0)> Public mi As MOUSEINPUT
<FieldOffset(0)> Public ki As KEYBDINPUT
<FieldOffset(0)> Public hi As HARDWAREINPUT
End Structure
Subtle. The official way to tell Windows that the system is not idle is SetThreadExecutionState. This resets the idle timer, (or turns it off, if you pass ES_CONTINUOUS ). However, even though SetThreadExecutionState resets the idle timer, it does not stop the screensaver!
SystemParametersInfo
Specifically, the SPI_SETSCREENSAVEACTIVE parameter.
Does this not work? I was surprised that I did not see it here. Note that SetThreadExecutionState will not affect the screen saver at all, just the sleeping of the display.
I use Mouse Jiggler to reset the idle state. This gets around a Group Policy that tends to start my screensaver (and lock the machine) at inopportune times: when I'm reading a long document, studying a complex chunk of code, or talking/listening/not-constantly-typing during a meeting.
As it can be slightly annoying to have the mouse jump 1px diagonally every second, I intend to use AutoHotKey to write a script that does basically the same thing, but only after a configured keyboard/mouse idle timeout, and maybe use the Shift key (or Scroll Lock) instead of a mouse move.
From MSDN:
Windows does not start the screen saver if any of the following conditions exist:
The active application is not a Windows-based application.
A CBT window is present.
The active application receives the WM_SYSCOMMAND message with the wParam parameter set to the SC_SCREENSAVE value, but it does not pass the message to the DefWindowProc function.
There's a caveat though:
Windows Vista and later: If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification.
That seems to apply even if you use the SetThreadExecutionState with ES_CONTINUOUS.
So, if it weren't for the caveat, your choices would be:
SetThreadExecutionState with ES_CONTINUOUS (as described in other answers).
Put up a computer-based training window (which requires hooks).
Don't let the WM_SYSCOMMAND with SC_SCREENSAVE be passed onto DefWindowProc. (Assuming you care only when your application is the active application.)
Install a dongle that simulates mouse jiggle.
The last option is nice in that it works even with the password protection policy.
In Windows 7+, use the Power Management API's PowerSetRequest() with PowerRequestDisplayRequired
https://msdn.microsoft.com/en-us/library/windows/desktop/dd405534(v=vs.85).aspx
In previous versions of windows, intercept the WM_SYSCOMMAND - SC_SCREENSAVE message as detailed in Eddie Parker's answer.
This blog post details what you need to do in C++.
The actual code snippet from the website:
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SYSCOMMAND:
{
switch (wParam)
{
case SC_SCREENSAVE:
return 0;
case SC_MONITORPOWER:
return 0;
}
break;
}
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
Can't believe no one has pointed out the easy and obvious solution:
#include <windows.h>
void main()
{
while(1){
INPUT input;
input.type = INPUT_MOUSE;
input.mi.dx = 1;
input.mi.dy = 1;
input.mi.mouseData = 0;
input.mi.dwFlags = MOUSEEVENTF_MOVE;
input.mi.time = 0;
input.mi.dwExtraInfo = 0;
SendInput( 1, &input, sizeof(input) );
sleep(60000);
}
}
As Adrian McCarthy mentioned from MSDN that :
If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification.
So catch the event from WM_SYSCOMMAND using UINT SC_SCREENSAVE and discarded it by returning 0 or by creating a fake mouse move ("mouse_event(MOUSEEVENTF_MOVE, 0, 1, 0, 0)") will not work properly if the user enabled password-protected screen saver option.
Use SetThreadExecutionState winAPI to tell the operating system that the thread is in use, even if the user is not interacting with the computer. These will prevent to appear screen saver and stop the machine from being suspended automatically.
There are series of flags to specify a new state for the current thread:
ES_AWAYMODE_REQUIRED (0x00000040) : Enables away mode.
ES_DISPLAY_REQUIRED (0x00000002) : Forces the display to be on by
resetting the display idle timer.
ES_SYSTEM_REQUIRED (0x00000001) : Forces the system to be in the
working state by resetting the system idle timer.
ES_CONTINUOUS (0x80000000) : Informs the system that the state being
set should remain in effect until the next call that uses
ES_CONTINUOUS and one of the other state flags are cleared.
As it's a winAPI, you can call this directly in win32 or mfc application
//To stop/start screen saver and monitor power off event
void SetKeepScreenOn(BOOL isKeepScreenOn)
{
if (isKeepScreenOn == TRUE)
{
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED /*| ES_AWAYMODE_REQUIRED*/);
}
else
{
SetThreadExecutionState(ES_CONTINUOUS);
}
}
If someone wants to use this in C#, must have to PInvoke this :
[DllImport("kernel32.dll", CharSet = CharSet.Auto,SetLastError = true)]
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
User-Defined Types:
[FlagsAttribute]
public enum EXECUTION_STATE :uint
{
ES_AWAYMODE_REQUIRED = 0x00000040,
ES_CONTINUOUS = 0x80000000,
ES_DISPLAY_REQUIRED = 0x00000002,
ES_SYSTEM_REQUIRED = 0x00000001
}
Here below is the calling procedure:
void SetKeepScreenOn(bool isKeepScreenOn)
{
if (isKeepScreenOn == true)
{
//You can combine several flags and specify multiple behaviors with a single call
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED /*| EXECUTION_STATE.ES_AWAYMODE_REQUIRED*/);
}
else
{
//To reset or allow those event again you have to call this API with only ES_CONTINUOUS
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
}
}
According to MSDN this API is safe also to use.
The system maintains a count of applications that have called SetThreadExecutionState. The system tracks each thread that calls SetThreadExecutionState and adjusts the counter accordingly. If this counter reaches zero and there has not been any user input, the system enters sleep.
If the Application crashed before resetting flag, the System will adjust and will reset automatically.
You can use SystemParametersInfo
to get the SCREENSAVETIMEOUT and then immediately set the timeout back to the same value. Do this periodically on a timer for as long as you want to prevent the screensaver from going on.
This has the effect of resetting the current countdown timer without actually changing the system setting.
You probably also want to call SetThreadExecutionState to affect the power as other answers mention.
Just reset the timeout counter with
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, nil, SPIF_SENDWININICHANGE);
From JD Design Freeware - Flipss.exe (download 12kb) is a command line utility that will set SPI_SETSCREENSAVEACTIVE for you.
"FlipSS.exe -h" to see the current state.
"FlipSS.exe /on" to set the screensaver on.
"FlipSS.exe /off" to set the screensaver off.
AutoHotkey can set SystemParametersInfo(SPI_SETSCREENSAVEACTIVE) with a 1-liner DllCall in script to easily accomplish this with a .ahk script.
AutoHotkey code to disable Screensaver:
DllCall("SystemParametersInfo", Int, 17, Int, 0, UInt, NULL, Int, 2)
AutoHotkey code to enable screensaver:
DllCall("SystemParametersInfo", Int, 17, Int, 1, UInt, NULL, Int, 2)
Reference Forum Threads:
F13Key - Toggling Screen Saver with SystemParametersInfo
SKAN - How to Disable Screen Saver Temporarily
I realize this is an old thread, but I'm faced with this issue for the first time (work machine is totally locked down, as far as changing super short sleep time, screensaver, etc. - I can't even change my desktop background). I've looked around at solutions, some seemingly way overcomplicated and some...not so much.
Some of my colleagues are using Caffeine. But that is surely some kind of spyware, etc., as it refuses to run if there is not an open internet connection.
So I found this (and modified it slightly), which is exactly what Caffeine does (except Caffeine does it every 59 seconds), without all the...at best, bloatware.
In PowerShell, execute the following 2 command lines:
$WShell = New-Object -Com "Wscript.Shell"
while(1) {$WShell.SendKeys("{F15}"); sleep 200}
Or you can make it a one-liner if you like:
while(1) {(New-Object -Com "Wscript.Shell").SendKeys("{F15}"); sleep 200}
(the latter of which seems like it would leak memory, but it does not seem to at all)
Once you run either of those, your screen will NOT lock, until you do ctrl-c, or close the Powershell window (in the latter version only, it seems, the ctrl-c may not happen until the sleep interval elapses).
Note that there is no F15 key, at least on any keyboard I've ever seen (but it's a legit windows keystroke), so there are no side effects. Now, if you your IT dept. is exceptionally paranoid, they may flag an F15 keystroke (mine is super paranoid, but they haven't noticed anything for months). If so, use something like scroll-lock instead.
Both of these 100% work on my win10 machine. Simple is good!

Resources