How to disable screen saver for video payback in Vista with password enabled?

528 views
Skip to first unread message

Kornél Pál

unread,
Apr 20, 2009, 7:30:44 PM4/20/09
to
Hi,

I would like to avoid the problem described here:
http://support.microsoft.com/kb/929526

I don't want to force the user to disable password protection I just
want to temproarily disable or avoid screen saver while playing full
screen video.

Kornél

Jialiang Ge [MSFT]

unread,
Apr 21, 2009, 12:51:11 AM4/21/09
to
Hello Korn└l

You may consider programmatically disable the screen saver when users enter
full screen mode:

http://support.microsoft.com/kb/126627

I understand that the difficult part of the question is how to detect the
full screen mode so that our app can disable the screen saver in the right
time. Please first let me know whether you are fine with the above idea. I
will then look for the possible methods to detect full screen of Windows
Media Center.

Regards,
Jialiang Ge (jia...@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

=================================================
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
msd...@microsoft.com.

This posting is provided "AS IS" with no warranties, and confers no rights.
=================================================

Kornél Pál

unread,
Apr 21, 2009, 11:19:27 AM4/21/09
to
Hi,

Thank you for your help, SystemParametersInfo with
SPI_SETSCREENSAVEACTIVE definitely works but I don't rellay like it
because that will remain in effect until the user logs off.

My problem is that you (Microsoft) believe that preventing screen saver
from activation while it is password protected is a security hole while
allowing the password protection to be disabled (either the passwort
protection or the screen saver entirely) is not a problem.

As I see SetThreadExecutionState and WM_SYSCOMMAND with SC_SCREENSAVE
and SC_MONITORPOWER (that worked on Windows XP with password protection
as well) all result in a more convenient user experience and are also
more secure because if the application crashes or forgets to re-enable
scree saver these methods will re-enable password protection unlike
SPI_SETSCREENSAVEACTIVE that will remain in effect until the user logs off.

My other problem with SPI_SETSCREENSAVEACTIVE is that I have to
periodically check SPI_GETSCREENSAVEACTIVE because other application
using the same technique may have exited and reenabled it and because I
don't want to enable when my program exits unless it was enabled before
this may result in the screen saver being disabled for the rest of the
WTS sessions lifetime.

Kornél

Jialiang Ge [MSFT] wrote:
> Hello Kornél

Jialiang Ge [MSFT]

unread,
Apr 23, 2009, 8:18:54 AM4/23/09
to
Hello Korn└l

>SPI_SETSCREENSAVEACTIVE definitely works but I don't rellay like it
>because that will remain in effect until the user logs off.

Based on my tests, it does not require user log off. It takes in effect
after the call. To re-enable screen saver:

BOOL r = SystemParametersInfo( SPI_SETSCREENSAVEACTIVE,
TRUE,
0,
SPIF_SENDWININICHANGE
);

Pavel A.

unread,
Apr 23, 2009, 11:34:35 AM4/23/09
to
Probably what the OP means is that if his app crashes before
he re-enables the screen saver, it will stay disabled until
the user logs off.

Maybe the OP needs to simulate user activity in order to keep
screen saver off.

-- pa

Kornél Pál

unread,
Apr 23, 2009, 1:00:58 PM4/23/09
to
I mean that the screen saver remains disabled until I (or any other
application) re-enable it using SPI_SETSCREENSAVEACTIVE or the user logs
off; whichever is sooner.

My previous message should contain a more detailed description why I
don't like this solution.

The point is that SetThreadExecutionState and WM_SYSCOMMAND with
SC_SCREENSAVE or SC_MONITORPOWER will be reverted if the program crashes
and also work fine with multiple applications using the same solution
because they basically state that "I need the screen" rather than
actually disable the screen saver.

SPI_SETSCREENSAVEACTIVE on the other hand sets a global flag that makes
impossible to be properly restore that flag when all the apps that want
to prevent the screensaver from activation exit. The only thing you can
do is to check it's state on program start but if it's already disabled
and the program that disabled it exits before yours you will not know
that you should re-enable the screen saver. Also if that programs
enables the screen saver on exit, your program will face the screen saver.

Another problem is that if my app crashes SPI_SETSCREENSAVEACTIVE will
remain disabled.

So I believe that this is much like a security issue than an "I need the
screen" flag and I don't really understan why are the other options
disabled while this is still enabled in Vista.

Kornél

Jialiang Ge [MSFT] wrote:
> Hello Kornél
>

leonudel...@googlemail.com

unread,
Apr 23, 2009, 4:22:37 PM4/23/09
to
On Apr 23, 6:00 pm, Kornél Pál <kornel...@newsgroup.nospam> wrote:
> So I believe that this is much like a security issue than an "I need the
> screen" flag and I don't really understan why are the other options
> disabled while this is still enabled in Vista.

It may not be disabled on purpose. (Equally, it may be, but...) Media
Center has some bugs relating to the screen-saver and this could be
another one of them.

For example, if a video lasts longer than the screensaver timeout, and
Media Center prevents the screensaver during playback (which is normal
on my machine but, from your post, I guess requires thatthe saver is
not password protected), and you didn't cause any explicit input for a
while, then as soon as the video finishes the screensaver or monitor
power-down will trigger. (Ideally MCE should simulate input so that
the screensaver/power-down happens at $timeout minutes after the video
stopped, but it doesn't. So sometimes the video stops and then the MCE
UI vanishes and the monitor turns off.) Even worse, some types of
remote controls do not trigger any kind of input themselves so even if
you did use the remote the timeout will have passed by the time the
video finishes (or when you simply push pause).

As another example, if video is paused or finished and the screensaver
kicks in -- or, I think, if just about anything takes focus away from
Media Center -- then the video will resume or restart. Incredibly
annoying. It's been like that for about 9 months now. Was like that in
XP as well... Vista fixed it, but then reintroduced the bug in the
June/July MCE roll-up, then three months later tried to fix it but
failed, and now with Windows 7 on the horizon I doubt it'll ever be
fixed. :-/

Bit of a rant but what I'm trying to say is that I wouldn't assume
anything Media Center does (or doesn't do) with the screensaver is on
purpose. It seems like it was tested on machines that had the
screensaver and power-off disabled completely. (Not a great idea for a
plasma TV...) It's a pet hate of mine as it causes me problems almost
every single time I watch TV or a movie and it seems like the issues
are being ignored.

Kornél Pál

unread,
Apr 23, 2009, 4:41:26 PM4/23/09
to
Hi,

Sorry for not mentioning explicitly before:

I am using my own application on Windows Vista Ultimate, I don't use
Media Center edition or Media Center application but the screen saver
thing described in the KB article applies to Windows Vista as a whole
not specific to Media Center.

Kornél

Jialiang Ge [MSFT]

unread,
Apr 28, 2009, 5:05:44 AM4/28/09
to
Hello Korn��l

If you're worried about the process crashing, you may consider a tiny exe
that just calls SPI_SETSCREENSAVEACTIVE and then waits for the other,
potentially buggy process to end (whether by normal exit or crash). You
could make the tiny one pretty darn small (probably 4k-8k) by avoiding
linking the CRT. With such a small program, you should be able to be pretty
sure that it will not be likely to crash.

Another idea is that, can the program trigger an event (like a mouse move)
that resets the screen-saver's timer? Then they don't have to change user
settings at all, and there's no need for the second process.

Kornél Pál

unread,
Apr 28, 2009, 12:26:02 PM4/28/09
to
Hi,

Unfortunately moving the mouse cursor using SetCursorPos just doesn't
reset screen saver timer (Windows Vista, password required for screen
saver).

I used C# with a timer that results in a fancy infinite diagonal mouse
movement:
private void timer1_Tick(object sender, EventArgs e)
{
Point pos = Cursor.Position;
Cursor.Position = new Point(pos.X + 1, pos.Y + 1);
if (Cursor.Position == pos)
Cursor.Position = new Point(0, 0);
this.Text = Cursor.Position.ToString();
}

This calls SetCursorPos.

For SPI_SETSCREENSAVEACTIVE I've originally done what you have
described: a separate exe without CRT. I also use a timer described
later. This works of course, but this is the worst thing to do and is
the most unsecure of all possible solutions. (OK, modifying the registry
setting is more unsecure.)

My problem is not just a possible crash but working with other programs.

If two applications doing the same is used, the first disables the
screen saver, the second sees no screen saver enabled. If I close the
first before the second that will restore the screen saver. This could
be solved by a timer, checking for screen saver, disabling it and
restore it if it has been disabled either at startup or by the timer.

This may work but if there is a race condition and it is possible to
leave the WTS session with screen saver disabled.

My problem is that you (Microsoft) believe that permanently disabling
the screen saver (you even can modify the registry) is safe and secure
while temporarily preventing form activation is unsafe and unsecure. I
believe the contrary.

Korn�l

Jialiang Ge [MSFT] wrote:
> Hello Korn�l

leonudel...@googlemail.com

unread,
Apr 28, 2009, 5:05:19 PM4/28/09
to
On Apr 28, 5:26 pm, Kornél Pál <kornel...@newsgroup.nospam> wrote:
> Unfortunately moving the mouse cursor using SetCursorPos just doesn't
> reset screen saver timer (Windows Vista, password required for screen
> saver).

It's a lot more work, and I don't know if it makes sense to do it
from .Net, but simulating mouse or keyboard input using a hook should
work. At least, MSDN says that input injected into the system in this
way is the same as if it had come from a mouse or keyboard driver.

http://msdn.microsoft.com/en-us/library/ms997537.aspx

I don't know for sure that it will solve the problem, or that it's the
best way to solve it, but it seems worth investigating if nothing else
works.

Jialiang Ge [MSFT]

unread,
Apr 29, 2009, 2:07:45 AM4/29/09
to
Hi Korn��l

Please try P/Invoking SendInput instead. It works well on my side. Here is
my test code:

[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
const int INPUT_MOUSE = 0;

[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
ushort wVk;
ushort wScan;
uint dwFlags;
uint time;
IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
uint uMsg;
ushort wParamL;
ushort wParamH;
}

[StructLayout(LayoutKind.Explicit)]
struct INPUT
{
[FieldOffset(0)]
public int type;
[FieldOffset(4)] //*
public MOUSEINPUT mi;
[FieldOffset(4)] //*
public KEYBDINPUT ki;
[FieldOffset(4)] //*
public HARDWAREINPUT hi;
}

[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, ref INPUT pInputs, int
cbSize);

Timer t = new Timer();
t.Interval = 10000;
t.Tick += new EventHandler(t_Tick);
t.Start();

void t_Tick(object sender, EventArgs e)


{
Point pos = Cursor.Position;
Cursor.Position = new Point(pos.X + 1, pos.Y + 1);
if (Cursor.Position == pos)
Cursor.Position = new Point(0, 0);

//this.Text = Cursor.Position.ToString();

INPUT input = new INPUT();
input.type = INPUT_MOUSE;
input.mi = new MOUSEINPUT();

input.mi.dwExtraInfo = IntPtr.Zero;
// mouse co-ords: top left is (0,0), bottom right is (65535,
65535)
// convert screen co-ord to mouse co-ords...
Random ran = new Random();
input.mi.dx = ran.Next(0, 2000);
input.mi.dy = ran.Next(0, 3000);
input.mi.time = 0;
input.mi.mouseData = 0;
input.mi.dwFlags = 0x0001 | 0x8000; // MOVE | ABSOLUTE

int cbSize = Marshal.SizeOf(typeof(INPUT));
uint r = SendInput(1, ref input, cbSize);

Infro

unread,
Apr 29, 2009, 12:51:29 PM4/29/09
to
use SystemParametersInfo with SPI_GETSCREENSAVESECURE
and SetExecutionThread with ES_CONTINUOUS | ES_DISPLAYREQUIRED


Pavel A.

unread,
Apr 29, 2009, 4:24:14 PM4/29/09
to
Infro wrote:
> use SystemParametersInfo with SPI_GETSCREENSAVESECURE
> and SetExecutionThread with ES_CONTINUOUS | ES_DISPLAYREQUIRED

Probably you mean SetThreadExecutionState:
http://msdn.microsoft.com/en-us/library/aa373208.aspx

"This function does not stop the screen saver from executing"

Regards,
-- pa

Kornél Pál

unread,
May 4, 2009, 8:03:17 AM5/4/09
to
Hi Jialiang,

Thank you very much for your SendInput sample. This works for me as well.

After evaluating and considering the issue and the possible solutions I
still believe that the problem is that Microsoft believes that
permanently disabling the screen saver (the registry can even be
modified) is safe and secure while temporarily preventing form

activation is unsafe and unsecure. I believe the contrary.

I would like to ask you to consider re-enabling WM_SYSCOMMAND with
SC_SCREENSAVE and/or addin a new flag in SetThreadExecutionState that
could temporarily prevent screen saver from activation and if all the
applications terminate that need the display without user interaction
screen saver could automatically be re-enabled.

Best regards,
Kornél Pál

I also include a sample of my wrapper process for using with mplayer.exe
(http://www.mplayerhq.hu/) as an example in case someone is interested:

/* Copyright (C) 2008 Kornél Pál <http://www.kornelpal.hu/> */
/* Licensed under the MIT/X11 license. */

#define WINVER 0x0400

#include <windows.h>

#ifdef RtlZeroMemory
#undef RtlZeroMemory
DECLSPEC_IMPORT VOID WINAPI RtlZeroMemory(PVOID Destination, SIZE_T Length);
#endif
#ifdef RtlMoveMemory
#undef RtlMoveMemory
DECLSPEC_IMPORT VOID WINAPI RtlMoveMemory(PVOID Destination, CONST PVOID
Source, SIZE_T Length);
#endif

#define MPLAYER_NAME TEXT("mplayer.exe")
#define MPLAYER_NAME_LENGTH (sizeof(MPLAYER_NAME) / sizeof(TCHAR))

DWORD mainCRTStartup()
{
DWORD exitCode;
BOOL restoreScreenSaver;
BOOL screenSaverEnabled;
LPTSTR commandLine;
BOOL inDoubleQuote;
HANDLE processHeap;
DWORD bufferLength;
DWORD length;
LPTSTR fileName;
LPTSTR fileChar;
STARTUPINFO startupInfo;
PROCESS_INFORMATION processInformation;
HANDLE timerHandle;
LARGE_INTEGER dueTime;
HANDLE handles[2];

commandLine = GetCommandLine();
inDoubleQuote = FALSE;
while (*commandLine > TEXT(' ') || (*commandLine && inDoubleQuote)) {
if (*commandLine == TEXT('\"'))
inDoubleQuote = !inDoubleQuote;
#ifndef UNICODE
if (IsDBCSLeadByte(*commandLine))
commandLine++;
#endif
commandLine++;
}
while (*commandLine && (*commandLine <= TEXT(' ')))
commandLine++;

processHeap = GetProcessHeap();
if (!processHeap)
return -1;

bufferLength = 512;
fileName = HeapAlloc(processHeap, 0, bufferLength * sizeof(TCHAR));
if (!fileName)
return -1;

for (;;) {
length = GetModuleFileName(NULL, fileName, bufferLength);
if (!length) {
HeapFree(processHeap, 0, fileName);
return -1;
}
if (length < bufferLength)
break;

bufferLength += 512;
fileName = HeapReAlloc(processHeap, 0, fileName, bufferLength *
sizeof(TCHAR));
if (!fileName)
return -1;
}

fileChar = fileName + length - 1;
while (fileChar >= fileName && *fileChar != TEXT('\\') && *fileChar !=
TEXT('/'))
fileChar--;
fileChar++;

length = fileChar - fileName;
if (bufferLength < length + MPLAYER_NAME_LENGTH) {
fileChar = fileName;
fileName = HeapReAlloc(processHeap, 0, fileName, (length +
MPLAYER_NAME_LENGTH) * sizeof(TCHAR));
if (!fileName) {
HeapFree(processHeap, 0, fileChar);
return -1;
}
}
RtlMoveMemory(fileName + length, TEXT("mplayer.exe"),
MPLAYER_NAME_LENGTH * sizeof(TCHAR));

exitCode = -1;
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
restoreScreenSaver = FALSE;
if (SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0,
&restoreScreenSaver, 0) && restoreScreenSaver)
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);

RtlZeroMemory(&startupInfo, sizeof(startupInfo));
RtlZeroMemory(&processInformation, sizeof(processInformation));

startupInfo.cb = sizeof(startupInfo);
if (CreateProcess(fileName, commandLine, NULL, NULL, TRUE, 0, NULL,
NULL, &startupInfo, &processInformation)) {
HeapFree(processHeap, 0, fileName);
CloseHandle(processInformation.hThread);

timerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
if (timerHandle) {
handles[0] = processInformation.hProcess;
handles[1] = timerHandle;

dueTime.QuadPart = -300000000LL; /* 30 seconds */
SetWaitableTimer(timerHandle, &dueTime, 0, NULL, NULL, FALSE);
while (WaitForMultipleObjects(2, handles, FALSE, INFINITE) ==
WAIT_OBJECT_0 + 1) {
if (SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0,
&screenSaverEnabled, 0) && screenSaverEnabled) {
restoreScreenSaver = TRUE;
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
}

SetWaitableTimer(timerHandle, &dueTime, 0, NULL, NULL, FALSE);
}

CloseHandle(timerHandle);
} else
WaitForSingleObject(processInformation.hProcess, INFINITE);
GetExitCodeProcess(processInformation.hProcess, &exitCode);
CloseHandle(processInformation.hProcess);
} else
HeapFree(processHeap, 0, fileName);

SetThreadExecutionState(ES_CONTINUOUS);
if (restoreScreenSaver &&
(!SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &screenSaverEnabled,
0) || !screenSaverEnabled))
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE, NULL, 0);

return exitCode;
}

Jialiang Ge [MSFT]

unread,
May 5, 2009, 11:53:14 PM5/5/09
to
Hi Korn��l

I understand your concerns. I will convey them to the product group. You
are also welcome to add your supplements to make Microsoft products easier
and more powerful to use by submitting a ticket in our feedback site:

https://connect.microsoft.com/VisualStudio

As we strive to capture any and all product feedback so as to ensure that
we are continuously developing Microsoft products to meet customer needs,
feedback such as yours is always taken very seriously. It is appreciated
that you can paste the suggestion's link here after you submit the ticket
in https://connect.microsoft.com/VisualStudio, so that other community
members can benefit from it.

Have a nice day!

Reply all
Reply to author
Forward
0 new messages