edmoore
asked on
Detect when screensaver activates
Seems to be my day asking questions - but with the help of E-E my programming has come on leaps and bounds and the encouragement of my school IT Manager means that I'm busily writing quite-handy ( :) ) little apps during these long summer holidays (tough life, eh?)
I had the idea of an app that detected when the screensaver activated, waited a few minutes and then if the screensaver hadn't turned off, logged-off the user to stop people forgetting to log-off and consequently having trouble logging on the next day.
I had a look at SystemParametersInfo, with GETSCREENSAVERACTIVE (which is great for disabling c-a-d) but this only seems to find out whether screen-saving is enabled in display control panel....
TIA,
Ed
I had the idea of an app that detected when the screensaver activated, waited a few minutes and then if the screensaver hadn't turned off, logged-off the user to stop people forgetting to log-off and consequently having trouble logging on the next day.
I had a look at SystemParametersInfo, with GETSCREENSAVERACTIVE (which is great for disabling c-a-d) but this only seems to find out whether screen-saving is enabled in display control panel....
TIA,
Ed
Hi Ed,
a simple solution is to make your own screensaver and then invoke whatever screensaver you want to see on screen from within it.
A screensaver is just an EXE-file with another extension (SCR) and can be executed in the ordinary way (createprocess...).
The idea is that your (nonvisual) screensaver would get the handle of the visual screensaver and run a loop to detect if the process attached to the handle is stopped.
If not it would log off in the ordinary way (ExitWindowsEx...) after the desired time.
Not the most beautiful solution, but easy enough to implement in 15-20 mins or so...
If you need further assistance; mail me...
Regards,
/// John
a simple solution is to make your own screensaver and then invoke whatever screensaver you want to see on screen from within it.
A screensaver is just an EXE-file with another extension (SCR) and can be executed in the ordinary way (createprocess...).
The idea is that your (nonvisual) screensaver would get the handle of the visual screensaver and run a loop to detect if the process attached to the handle is stopped.
If not it would log off in the ordinary way (ExitWindowsEx...) after the desired time.
Not the most beautiful solution, but easy enough to implement in 15-20 mins or so...
If you need further assistance; mail me...
Regards,
/// John
erajoj: It takes a lot more to write a "good" screen saver than just renaming it!
For one thing, it must make sure it covers the task bar, it should provide a "config-dialog" when "Configure" is clicked and last but definitely not least, it should display a litttle preview in the desktop-properties window (in the little monitor). I spent more than 2 of hours writing one (a very simplistic one) two weeks ago and I have a good URL abut it... maybe I'll post it if I can find it...
But apart from that:
edmoore, I'm pretty optimistic I can help you find a solution, but I don't have the time right now to write a working program...
Here's something from the Delphi FAQ:
How do I turn the Windows Screen Saver on in code?
Answer:
The following function tests to see if the WIndows Screen Saver is
available, and if so, turns it on:
function TurnScreenSaverOn : bool;
var
b : bool;
begin
result := false;
if SystemParametersInfo(SPI_G ETSCREENSA VEACTIVE,
0,
@b,
0) <> true then exit;
if not b then exit;
PostMessage(GetDesktopWind ow, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
result := true;
end;
but I guess you already knew that, right?
The truly interesting part is from Delphi\Source\RTL\Win\WIND OWS.PAS:
const
{ Parameter for SystemParametersInfo() }
{$EXTERNALSYM SPI_GETBEEP}
SPI_GETBEEP = 1;
.
{$EXTERNALSYM SPI_GETSCREENSAVEACTIVE}
SPI_GETSCREENSAVEACTIVE = $10;
. (now this is the good part :-)
{$EXTERNALSYM SPI_SCREENSAVERRUNNING}
SPI_SCREENSAVERRUNNING = 97;
.
That should do it, shouldn't it?? I would imagine that
SystemParametersInfo(SPI_G ETSCREENSA VERRUNNING ,
0,
@b,
0) <> true then exit;
returns what you're looking for in b :-))))
Good luck and let me know if that's all you need so I can post an "official answer" :-))
For one thing, it must make sure it covers the task bar, it should provide a "config-dialog" when "Configure" is clicked and last but definitely not least, it should display a litttle preview in the desktop-properties window (in the little monitor). I spent more than 2 of hours writing one (a very simplistic one) two weeks ago and I have a good URL abut it... maybe I'll post it if I can find it...
But apart from that:
edmoore, I'm pretty optimistic I can help you find a solution, but I don't have the time right now to write a working program...
Here's something from the Delphi FAQ:
How do I turn the Windows Screen Saver on in code?
Answer:
The following function tests to see if the WIndows Screen Saver is
available, and if so, turns it on:
function TurnScreenSaverOn : bool;
var
b : bool;
begin
result := false;
if SystemParametersInfo(SPI_G
0,
@b,
0) <> true then exit;
if not b then exit;
PostMessage(GetDesktopWind
result := true;
end;
but I guess you already knew that, right?
The truly interesting part is from Delphi\Source\RTL\Win\WIND
const
{ Parameter for SystemParametersInfo() }
{$EXTERNALSYM SPI_GETBEEP}
SPI_GETBEEP = 1;
.
{$EXTERNALSYM SPI_GETSCREENSAVEACTIVE}
SPI_GETSCREENSAVEACTIVE = $10;
. (now this is the good part :-)
{$EXTERNALSYM SPI_SCREENSAVERRUNNING}
SPI_SCREENSAVERRUNNING = 97;
.
That should do it, shouldn't it?? I would imagine that
SystemParametersInfo(SPI_G
0,
@b,
0) <> true then exit;
returns what you're looking for in b :-))))
Good luck and let me know if that's all you need so I can post an "official answer" :-))
ASKER
OK, Holger, thanks - that's great. Post it as an answer and collect your points!
Ed
Ed
function IsScreenSaverRunning: LongBool;
var Dummy: Integer;
begin
SystemParametersInfo(SPI_S CREENSAVER RUNNING, 1, @Result, 0);
SystemParametersInfo(SPI_S CREENSAVER RUNNING, Integer(Result), @Dummy, 0);
end;
Reject if you want.
var Dummy: Integer;
begin
SystemParametersInfo(SPI_S
SystemParametersInfo(SPI_S
end;
Reject if you want.
Edmore, Holger !
SORRY!!! Reject my answer!!!
SORRY!!! Reject my answer!!!
ASKER
"Rejection" sounds like such a strong term - sorry vladika - your answer was very helpful as well, but I had already promised the points to Holger. Shame E-E doesn't let you give two "corrects"! (now there's an idea....)
Ed
Ed
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
After first line I set SPI_SCREENSAVERRUNNING = 1
My second line restore previous SPI_SCREENSAVERRUNNING value
I must do it, isn't it? :)
My second line restore previous SPI_SCREENSAVERRUNNING value
I must do it, isn't it? :)
Why do you have to restore something you don't change?
Ed doesn't want to start the screen saver, he just want to DETECT IF it is running. The state of the screen saver should not be changed and therefore, nothing has to be restored either...
Ed doesn't want to start the screen saver, he just want to DETECT IF it is running. The state of the screen saver should not be changed and therefore, nothing has to be restored either...
You are mistaken.
> Why do you have to restore something you don't change?
I change by
SystemParametersInfo(SPI_S CREENSAVER RUNNING, 1, @Result, 0);
I set SPI_SCREENSAVERRUNNING = 1
and previous SPI_SCREENSAVERRUNNING value went into Result.
Previous value maybe 0, maybe 1.
So, I must restore this value.
And I restore it by
SystemParametersInfo(SPI_S CREENSAVER RUNNING, Integer(Result), @Dummy, 0);
If you did not restore previous state, you will have some by-effect.
For example disabling CTRL-ALT-DEL, maybe more...
> Why do you have to restore something you don't change?
I change by
SystemParametersInfo(SPI_S
I set SPI_SCREENSAVERRUNNING = 1
and previous SPI_SCREENSAVERRUNNING value went into Result.
Previous value maybe 0, maybe 1.
So, I must restore this value.
And I restore it by
SystemParametersInfo(SPI_S
If you did not restore previous state, you will have some by-effect.
For example disabling CTRL-ALT-DEL, maybe more...
ok, *might* be true, but I'll have to check the API when I'm back home. The code I posted is from the official Delphi FAQ:
if SystemParametersInfo(SPI_G ETSCREENSA VEACTIVE, 0, @b, 0) <> true then exit;
if not b then exit;
PostMessage(GetDesktopWind ow, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
Following your point, this code would first disable the screen saver before trying to turn it on - strange, huh?
Now I don't say you're wrong before checking... but it would be a serious problem... I guess ed wants to check for the status of the screen saver in a timer and he'd probably be very unhappy if the screen saver is turned off/off and back on/off every 30 seconds :-)))
Also, why would we have the PostMessage(GetDesktopWind ow, WM_SYSCOMMAND, SC_SCREENSAVE, 0); command??
Let's hear ed's opinion - I guess he's tried the code already and it sounded like it worked.
If you're right, he'd notice right away because the screen saver wouldn't work any more (being turned off as soon as the function is called)
P.S.: Just a formality: SPI_SCREENSAVERRUNNING is a constant and it's value is 97
if SystemParametersInfo(SPI_G
if not b then exit;
PostMessage(GetDesktopWind
Following your point, this code would first disable the screen saver before trying to turn it on - strange, huh?
Now I don't say you're wrong before checking... but it would be a serious problem... I guess ed wants to check for the status of the screen saver in a timer and he'd probably be very unhappy if the screen saver is turned off/off and back on/off every 30 seconds :-)))
Also, why would we have the PostMessage(GetDesktopWind
Let's hear ed's opinion - I guess he's tried the code already and it sounded like it worked.
If you're right, he'd notice right away because the screen saver wouldn't work any more (being turned off as soon as the function is called)
P.S.: Just a formality: SPI_SCREENSAVERRUNNING is a constant and it's value is 97
> Following your point, this code would first disable the screen saver before trying to turn it on - strange, huh?
No, It is not my point.
SPI_GETSCREENSAVEACTIVE only query whether screen saving is enabled or not.
SPI_SETSCREENSAVEACTIVE only set the state of the screen saver. (not running it)
BUT!!!
SPI_SCREENSAVERRUNNING query and set params at the same time!!!
Also I think you will not find SPI_SCREENSAVERRUNNING description in API.
I found in API only that SPI_SCREENSAVERRUNNING is internal parameter and all.
No, It is not my point.
SPI_GETSCREENSAVEACTIVE only query whether screen saving is enabled or not.
SPI_SETSCREENSAVEACTIVE only set the state of the screen saver. (not running it)
BUT!!!
SPI_SCREENSAVERRUNNING query and set params at the same time!!!
Also I think you will not find SPI_SCREENSAVERRUNNING description in API.
I found in API only that SPI_SCREENSAVERRUNNING is internal parameter and all.
ASKER
OK, I got it to work but Delphi 2 didn't like SPI_SCREENSAVERRUNNING (wasn't listed in the windows.pas Holger came up with either - maybe that's D3?) but when I stuck 97 in instead it worked fine...
Incidentally, what do think is the best way to first, keep checking if the screensaver is on, and then wait say 10 minutes. I was going to use a timer, but are they particularly resource-intensive?
Ed
Incidentally, what do think is the best way to first, keep checking if the screensaver is on, and then wait say 10 minutes. I was going to use a timer, but are they particularly resource-intensive?
Ed
As far as I know, a timer is the best way to wait for a longer time and Borland probably implemented them very efficiently by using the windows-functions that are available - they use a "windows timer event" - whatever that is.
The only way of waiting without a timer looks like this:
procedure Delay(ms : longint);
var TheTime : LongInt;
begin
TheTime := GetTickCount + ms;
while GetTickCount < TheTime do
Application.ProcessMessage s;
end;
but I really can't imagine that that's more efficient, since the loop keeps going and going and going... I think if you set your timer interval to 20000 ms or so, that should be quite ok. Check the ressource-meter and I'm pretty sure your process will have less than 1% CPU-time (if you use NT, you can check CPU time for individual programs)
The only way of waiting without a timer looks like this:
procedure Delay(ms : longint);
var TheTime : LongInt;
begin
TheTime := GetTickCount + ms;
while GetTickCount < TheTime do
Application.ProcessMessage
end;
but I really can't imagine that that's more efficient, since the loop keeps going and going and going... I think if you set your timer interval to 20000 ms or so, that should be quite ok. Check the ressource-meter and I'm pretty sure your process will have less than 1% CPU-time (if you use NT, you can check CPU time for individual programs)
ASKER