Link to home
Start Free TrialLog in
Avatar of edmoore
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
Avatar of edmoore
edmoore

ASKER

Just to make it clear - I'm asking how to implement the idea I suggested.  Maybe I was a bit vague - maybe it's just me?
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
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_GETSCREENSAVEACTIVE,
                           0,
                           @b,
                           0) <> true then exit;
   if not b then exit;
   PostMessage(GetDesktopWindow, 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\WINDOWS.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_GETSCREENSAVERRUNNING,
                           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" :-))
Avatar of edmoore

ASKER

OK, Holger, thanks - that's great.  Post it as an answer and collect your points!

Ed
function IsScreenSaverRunning: LongBool;
var Dummy: Integer;
begin
  SystemParametersInfo(SPI_SCREENSAVERRUNNING, 1, @Result, 0);
  SystemParametersInfo(SPI_SCREENSAVERRUNNING, Integer(Result), @Dummy, 0);
end;

Reject if you want.

Edmore, Holger !

SORRY!!! Reject my answer!!!

Avatar of edmoore

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
ASKER CERTIFIED SOLUTION
Avatar of Holger101497
Holger101497

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
After first line I set SPI_SCREENSAVERRUNNING = 1

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...
You are mistaken.

> Why do you have to restore something you don't change?
I change by
  SystemParametersInfo(SPI_SCREENSAVERRUNNING, 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_SCREENSAVERRUNNING, 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...

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_GETSCREENSAVEACTIVE, 0, @b, 0) <> true then exit;
  if not b then exit;
  PostMessage(GetDesktopWindow, 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(GetDesktopWindow, 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
> 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.

Avatar of edmoore

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
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.ProcessMessages;
 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)