Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Preventing screen saver from activation

194 views
Skip to first unread message

Ivo Bauer

unread,
Mar 20, 2007, 4:00:50 AM3/20/07
to
Hi all,

Due to various reasons, I need to find a way how to prevent a Windows
screen saver from activation if, and only if my application is
running. I did some research before posting here but without a luck so
far.

I'm aware of existence of SystemParametersInfo() API that could be
called with SPI_SETSCREENSAVEACTIVE parameter to deliberately
deactivate screen saver but I don't want to change global Windows
settings - I'd rather do it on my application level.

Another possibility is to trap WM_SYSCOMMAND message and get rid of
its default processing if wParam equals to SC_SCREENSAVE. This works
fine as long as my application has focus. I also discovered that this
approach will not work on Windows Vista if the screen saver is
password-protected.

I also found the following web page

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_adv/scrnsave.asp

that suggests to have a CBT (computer based training) window in order
to prevent screen saver from being started, but as I've never used
hooks before I don't know where to start.

Any ideas will be appreciated.


--
Ivo Bauer [OZM Research]

Jens Gruschel

unread,
Mar 20, 2007, 2:22:24 PM3/20/07
to
> I'm aware of existence of SystemParametersInfo() API that could be
> called with SPI_SETSCREENSAVEACTIVE parameter to deliberately deactivate
> screen saver but I don't want to change global Windows settings - I'd
> rather do it on my application level.

Well, but it *is* something global you want to change. If you don't
change the registry as well, changing this flag is not permanent.

--
Jens Gruschel
http://www.pegtop.net

Ivo Bauer

unread,
Mar 20, 2007, 3:32:55 PM3/20/07
to
Jens Gruschel napsal(a):

Yes, I'm aware of that, but even if I choose not to update the
registry, the new setting will be preserved until next reboot which is
something I don't want to. Yes, I could re-activate the screen saver
upon exit of my application but how can I be sure that this setting
has not been changed explicitely by the user in the mean time?

My intent is to prevent the screen saver from starting if and *only*
if my application is actually running. I usually try to refrain from
changing global system settings but this case is an exception to the rule.

Remy Lebeau (TeamB)

unread,
Mar 20, 2007, 5:10:30 PM3/20/07
to

"Ivo Bauer" <ab...@zom.zc> wrote in message
news:45ff94b9$1...@newsgroups.borland.com...

> I'm aware of existence of SystemParametersInfo() API that could
> be called with SPI_SETSCREENSAVEACTIVE parameter to
> deliberately deactivate screen saver but I don't want to change
> global Windows settings - I'd rather do it on my application level.

That is exactly what happens when you use SPI_SETSCREENSAVEACTIVE.
Just make sure that you set SPI_SETSCREENSAVEACTIVE back to FALSE
before you exit the application.

> Another possibility is to trap WM_SYSCOMMAND message and
> get rid of its default processing if wParam equals to SC_SCREENSAVE.
> This works fine as long as my application has focus.

You need to use a global message hook via SetWindowsHookEx() inside a
DLL to address that issue. I did exactly that in an application I
once wrote. That way, the hook can swallow the notification
regardless of which application has the focus.


Gambit


Remy Lebeau (TeamB)

unread,
Mar 20, 2007, 5:13:43 PM3/20/07
to

"Ivo Bauer" <ab...@zom.zc> wrote in message
news:460036ef$1...@newsgroups.borland.com...

> how can I be sure that this setting has not been changed explicitely
> by the user in the mean time?

Because the user does not have access to change
SPI_SETSCREENSAVEACTIVE in the first place. Only real screen savers
(and apps that try to manipulate screen savers, like yours is) use
SPI_SETSCREENSAVEACTIVE.

If you are really worried about the setting being changed behind your
back, then simply intercept the WM_SETTINGCHANGE message and then
query SPI_GETSCREENSAVEACTIVE to see if the value has changed from
what you are expecting it to be.

> My intent is to prevent the screen saver from starting if
> and *only* if my application is actually running.

You already know how to do that.


Gambit


Ivo Bauer

unread,
Mar 20, 2007, 4:54:29 PM3/20/07
to
Remy Lebeau (TeamB) napsal(a):

> "Ivo Bauer" <ab...@zom.zc> wrote in message
>> how can I be sure that this setting has not been changed explicitely
>> by the user in the mean time?
>
> Because the user does not have access to change
> SPI_SETSCREENSAVEACTIVE in the first place. Only real screen savers
> (and apps that try to manipulate screen savers, like yours is) use
> SPI_SETSCREENSAVEACTIVE.

I didn't know that. Thanks for your explanation.

> If you are really worried about the setting being changed behind your
> back, then simply intercept the WM_SETTINGCHANGE message and then
> query SPI_GETSCREENSAVEACTIVE to see if the value has changed from
> what you are expecting it to be.

That seems to be the way to go. I'll give it a try. Thanks again.

Ivo Bauer

unread,
Mar 20, 2007, 4:54:31 PM3/20/07
to
Remy Lebeau (TeamB) napsal(a):

> That is exactly what happens when you use SPI_SETSCREENSAVEACTIVE.
> Just make sure that you set SPI_SETSCREENSAVEACTIVE back to FALSE
> before you exit the application.

Did you mean actually set it to True, didn't you? Because I would want
to re-active the screen saver if it was previously active before my
application has made the change.

>> Another possibility is to trap WM_SYSCOMMAND message and
>> get rid of its default processing if wParam equals to SC_SCREENSAVE.
>> This works fine as long as my application has focus.
>
> You need to use a global message hook via SetWindowsHookEx() inside a
> DLL to address that issue. I did exactly that in an application I
> once wrote. That way, the hook can swallow the notification
> regardless of which application has the focus.

Please correct me if I am wrong but this approach is not going to work
on Windows Vista and later versions of the OS. Here is a quote from
the MSDN article named "Handling Screen Savers":

"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."


The same article claims that presence of CBT (computer based training)
window in the system should prevent screen saver from being started.
Do you have any experience with this kind of stuff?

Thanks!

Remy Lebeau (TeamB)

unread,
Mar 20, 2007, 6:27:59 PM3/20/07
to

"Ivo Bauer" <ab...@zom.zc> wrote in message
news:46004a19$1...@newsgroups.borland.com...

> Did you mean actually set it to True, didn't you?

Nevermind. I got SPI_SETSCREENSAVEACTIVE and SPI_SCREENSAVERRUNNING
confused.

> The same article claims that presence of CBT (computer based
> training) window in the system should prevent screen saver from
> being started.

CBT is just another type of hook that is installed via
SetWindowsHookEx().

> Do you have any experience with this kind of stuff?

I have much experience with SetWindowsHookEx().


Gambit


Ivo Bauer

unread,
Mar 20, 2007, 6:18:22 PM3/20/07
to
Remy Lebeau (TeamB) napsal(a):

> CBT is just another type of hook that is installed via
> SetWindowsHookEx().
>
>> Do you have any experience with this kind of stuff?
>
> I have much experience with SetWindowsHookEx().

Great. ;-) Do you have any example (or a web link to one) that would
get me started how to install a CBT hook in order to prevent a screen
saver from being activated?

Remy Lebeau (TeamB)

unread,
Mar 20, 2007, 7:23:00 PM3/20/07
to

"Ivo Bauer" <ab...@zom.zc> wrote in message
news:4600...@newsgroups.borland.com...

> Great. ;-) Do you have any example (or a web link to one) that would
> get me started

I have posted many examples of using hooks before. Go to
http://www.deja.com and search through the newsgroup archives.

> how to install a CBT hook

Have you looked at the documentation for SetWindowsHookEx() yet? It
explains everything you need to know.


Gambit


Ivo Bauer

unread,
Mar 21, 2007, 5:37:45 AM3/21/07
to
Remy Lebeau (TeamB) napsal(a):

> I have posted many examples of using hooks before. Go to
> http://www.deja.com and search through the newsgroup archives.

I found the following CBT hook example written by Jim Kuenemann:

http://www.mustangpeak.net/download/cbthook.zip

Apparently, the presence of CBT hook is not sufficient to prevent
screen saver from activation. So I thought I would intercept the
HCBT_CREATEWND message, check if the class name of the window being
created is a screen saver class and if so, then return non-zero value
from CBTProc which should, according to MSDN documentation, cancel the
window creation. This is the code I inserted in the HCBT_CREATEWND
handler inside CBTProc:

if PCBTCreateWnd(Pointer( lParam))^.lpcs.lpszClass =
'WindowsScreenSaverClass' then
begin
Result := 1;
end;

I'm pretty sure that the above boolean expression returns True when
screen saver is about to be activated (I put a call to Windows.Beep
API right after the begin statement and I can hear a beep when it
occurs) but then the screen saver is normally activated as if the
CBTProc was returned zero.

I also tried to bypass a call to CallNextHookEx if the above boolean
condition is True and at first sight it works - the screen saver is
not activated when it should be, but I can see that Windows keeps
trying to activate the screen saver every second which results in
changing mouse cursor to crAppStart until you move the mouse or hit a
key. After couple of minutes this test app crashes the whole system -
the Explorer process needs to be restarted.

What am I doing wrong?

Russ

unread,
Mar 21, 2007, 9:48:12 AM3/21/07
to
Make sure and call disablethreadlibrarycalls(hinstance) in the
initialization of one of your global hook dll units. This is required for
Delphi system wide hooks to be stable.

Russ

"Ivo Bauer" <ab...@zom.zc> wrote in message

news:4600fcf0$1...@newsgroups.borland.com...

Remy Lebeau (TeamB)

unread,
Mar 21, 2007, 2:18:38 PM3/21/07
to

"Ivo Bauer" <ab...@zom.zc> wrote in message
news:4600fcf0$1...@newsgroups.borland.com...

> Apparently, the presence of CBT hook is not sufficient to
> prevent screen saver from activation. So I thought I would
> intercept the HCBT_CREATEWND message

Try intercepting HCBT_SYSCOMMAND instead.

> check if the class name of the window being created is a screen
saver class

That is not a reliable approach. Not all screen savers use that class
name.

> if PCBTCreateWnd(Pointer( lParam))^.lpcs.lpszClass =
'WindowsScreenSaverClass' then

You can't compare the values like that, as they are not Delphi String
types. You are comparing just the memory addresses being pointed to,
not the actuall data being pointed at. You need to use StrComp() or
similar function instead, ie:

if StrComp(PCBTCreateWnd(Pointer( lParam))^.lpcs.lpszClass,
'WindowsScreenSaverClass') = 0 then

> I'm pretty sure that the above boolean expression returns True
> when screen saver is about to be activated

Not reliably. See above.


Gambit


Ivo Bauer

unread,
Mar 21, 2007, 4:00:36 PM3/21/07
to
Russ napsal(a):

> Make sure and call disablethreadlibrarycalls(hinstance) in the
> initialization of one of your global hook dll units. This is required for
> Delphi system wide hooks to be stable.

Thanks for the suggestion, but it did not helped. The test app still
keeps crashing itself and the Explorer as well.

Russ

unread,
Mar 21, 2007, 4:06:29 PM3/21/07
to
Sorry it did not help but leave it in there in case you get you other issues
fixed. Delphi hooks are not safe without it.

Russ


"Ivo Bauer" <ab...@zom.zc> wrote in message

news:46018eea$1...@newsgroups.borland.com...

Ivo Bauer

unread,
Mar 21, 2007, 8:14:01 PM3/21/07
to
Remy Lebeau (TeamB) napsal(a):
> Try intercepting HCBT_SYSCOMMAND instead.

I've done that, please find the library source pasted below. When I
run the test app, it no longer crashes but the CBTProc never gets
called with HCBT_SYSCOMMAND code although it seems that the hook is
installed correctly.

Could you please look at it?

>> check if the class name of the window being created is a screen
> saver class
>
> That is not a reliable approach. Not all screen savers use that class
> name.

Aha, I wasn't aware of this before. Thanks for pointing that out.

>> if PCBTCreateWnd(Pointer( lParam))^.lpcs.lpszClass =
> 'WindowsScreenSaverClass' then
>
> You can't compare the values like that, as they are not Delphi String
> types.

Yes, you're right of course.

Source of the CBT hook DLL follows. The test app calls HookCBT in the
main form's constructor and UnHookCBT in the main form's destructor:

library CBTHook;

uses
Windows;

{$R *.RES}

const
CMemoryMappedFileName = 'CBTHookHandle';

function CBTProc(Code: Integer; wParam: WPARAM; lParam: LPARAM):
LRESULT stdcall;
var
LMappedMemoryHandle: THandle;
LHookHandlePtr: PHandle;
begin
Result := 0;
LMappedMemoryHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, False,
CMemoryMappedFileName);
if LMappedMemoryHandle <> 0 then
begin
LHookHandlePtr := MapViewOfFile(LMappedMemoryHandle,
FILE_MAP_ALL_ACCESS, 0, 0, 0);
if Assigned(LHookHandlePtr) then
begin
if (Code = HCBT_SYSCOMMAND) and
((wParam and $FFF0) = SC_SCREENSAVE) then


begin
Result := 1;
end;

if (LHookHandlePtr^ <> 0) then
Result := CallNextHookEx(LHookHandlePtr^, Code, wParam,
lParam);
UnMapViewOfFile(LHookHandlePtr);
end;
CloseHandle(LMappedMemoryHandle);
end
end;

procedure HookCBT; stdcall;
var
LMappedMemoryHandle: THandle;
LHookHandlePtr: PHandle;
begin
LMappedMemoryHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, False,
CMemoryMappedFileName);
if LMappedMemoryHandle <> 0 then
begin
LHookHandlePtr := MapViewOfFile(LMappedMemoryHandle,
FILE_MAP_ALL_ACCESS, 0, 0, 0);
if Assigned(LHookHandlePtr) then
begin
LHookHandlePtr^ := SetWindowsHookEx(WH_CBT, CBTProc,
hInstance, 0);
UnmapViewOfFile(LHookHandlePtr);
end;
CloseHandle(LMappedMemoryHandle);
end;
end;

procedure UnHookCBT; stdcall;
var
LMappedMemoryHandle: THandle;
LHookHandlePtr: PHandle;
begin
LMappedMemoryHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, False,
CMemoryMappedFileName);
if LMappedMemoryHandle <> 0 then
begin
LHookHandlePtr := MapViewOfFile(LMappedMemoryHandle,
FILE_MAP_ALL_ACCESS, 0, 0, 0);
if Assigned(LHookHandlePtr) then
begin
UnHookWindowsHookEx(LHookHandlePtr^);
LHookHandlePtr^ := 0;
UnmapViewOfFile(LHookHandlePtr);
end;
CloseHandle(LMappedMemoryHandle);
end;
end;

exports
HookCBT index 1,
UnHookCBT index 2;

begin
end.

Ivo Bauer

unread,
Mar 21, 2007, 8:14:03 PM3/21/07
to
Russ napsal(a):

> Sorry it did not help but leave it in there in case you get you other issues
> fixed. Delphi hooks are not safe without it.

I have simplified the original example. The good news is that the test
app no longer crashes. The bad news is that the hook does not work.
Please see my reply to Remy.

Remy Lebeau (TeamB)

unread,
Mar 21, 2007, 9:59:17 PM3/21/07
to

"Ivo Bauer" <ab...@zom.zc> wrote in message
news:4601ca50$1...@newsgroups.borland.com...

> When I run the test app, it no longer crashes but the CBTProc
> never gets called with HCBT_SYSCOMMAND code

I don't expect it to be called at all, given the code you have shown
now.

> it seems that the hook is installed correctly.

It is not.

> Source of the CBT hook DLL follows.

Your code is not using the hook properly or managing the file mapping
correctly.

> function CBTProc(Code: Integer; wParam: WPARAM; lParam: LPARAM):
> LRESULT stdcall;

You need to export that function. Otherwise, other processes will not
be able to access it.

> LMappedMemoryHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS,
False,
> CMemoryMappedFileName);

You need to use CreateFileMapping() at some point. Otherwise, you are
trying to open a mapping that never exists. You should not be
re-opening the file mapping every time the hook procedure is called.
Create/open it once when the DLL is first loaded, and then release it
when the DLL is unloaded. Every time the DLL is loaded into a new
process, that instance of the DLL needs access to a file mapping that
may or may not already exist. Once created, the exported functions
can access the data block whenever needed without all of that extra
overhead.

> if (LHookHandlePtr^ <> 0) then
> Result := CallNextHookEx(LHookHandlePtr^, Code, wParam,
> lParam);

At no point are you actually allocating any memory to hold the return
value of SetWindowsHookEx().

With that said, try something more like the following instead:

library CBTHook;

uses
Windows;

{$R *.RES}

const
CMemoryMappedFileName = 'CBTHookHandle';

type
PHHOOK = ^HHOOK;

var
MemoryMap: THandle = 0;
HookPtr: PHHOOK = nil;

function CBTProc(Code: Integer; wParam: WPARAM; lParam: LPARAM):
LRESULT; stdcall;

begin
if (Code = HCBT_SYSCOMMAND) and ((wParam and $FFF0) =
SC_SCREENSAVE) then

Result := 1
else
Result := CallNextHookEx(HookPtr^, Code, wParam, lParam);
end;

function HookCBT: BOOL; stdcall;
begin
Result := FALSE;
if (HookPtr <> nil) and (HookPtr^ = 0) then
begin
HookPtr^ := SetWindowsHookEx(WH_CBT, @CBTProc, HInstance,
0);
if HookPtr^ <> 0 then Result := TRUE;
end;
end;

function UnHookCBT: BOOL; stdcall;
begin
Result := FALSE;
if (HookPtr <> nil) and (HookPtr^ <> 0) then
begin
if UnhookWindowsHookEx(HookPtr^) then
begin
HookPtr^ := 0;
Result := TRUE;
end;
end;
end;

procedure MyDllProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
if HookPtr <> nil then
begin
UnmapViewOfFile(HookPtr);
HookPtr = nil;
end;
if MemoryMap <> 0 then
begin
CloseHandle(MemoryMap);
MemoryMap := 0;
end;
end;
end;

exports
HookCBT, UnHookCBT, CBTProc;

begin
DllProc := @MyDllProc;
DisableThreadLibraryCalls(HInstance);

MemoryMap := CreateFileMapping(INVALID_HANDLE_VALUE, nil,
PAGE_READWRITE, 0, SizeOf(HHOOK), CMemoryMappedFileName);
if MemoryMap <> 0 then
begin
HookPtr := PHHOOK(MapViewOfFile(MemoryMap, FILE_MAP_WRITE,
0, 0, 0));
if HookPtr <> nil then
begin
if GetLastError <> ERROR_ALREADY_EXISTS then
HookPtr^ := 0;
end else
begin
CloseHandle(MemoryMap);
MemoryMap := 0;
end;
end;
end.


Gambit


Ivo Bauer

unread,
Mar 22, 2007, 5:00:20 AM3/22/07
to
Remy Lebeau (TeamB) napsal(a):

>> function CBTProc(Code: Integer; wParam: WPARAM; lParam: LPARAM):
>> LRESULT stdcall;
>
> You need to export that function. Otherwise, other processes will not
> be able to access it.

Of course, I didn't realized that before.

> You need to use CreateFileMapping() at some point. Otherwise, you are
> trying to open a mapping that never exists.

I must admit I blindly simplified the example found on a web and
didn't bother to read the documentation regarding the use of memory
mapped files. Shame on me, it won't happen again.

> You should not be
> re-opening the file mapping every time the hook procedure is called.
> Create/open it once when the DLL is first loaded, and then release it
> when the DLL is unloaded.

Will do. Thanks for this suggestion.

> With that said, try something more like the following instead:

I've just tried your code and I'm impressed - it works as I would
expect and it's stable as well. Many thanks for your valuable
feedback, as always!

However, as I feared, it does not work when screen saver is password
protected - not even under Windows XP. I guess I will have to live
with that.

Russ

unread,
Mar 22, 2007, 10:50:57 AM3/22/07
to
Is the memory mapped file working in Vista? There was a discussion here
some time back that sounded rather bleak about using MMFs in Vista.

Russ

"Ivo Bauer" <ab...@zom.zc> wrote in message

news:460245ad$1...@newsgroups.borland.com...

Ivo Bauer

unread,
Mar 22, 2007, 3:12:17 PM3/22/07
to
> Is the memory mapped file working in Vista? There was a discussion here
> some time back that sounded rather bleak about using MMFs in Vista.

I admit I didn't use MMFs myself before but I have seen a lot of
people to use them in their apps. It would break a lot of existing
applications if MMFs weren't work in Vista. I've just checked MSDN
documentation regarding MMFs and it appears that they're supported by
Vista. Do you have a link to that discussion?

Ivo Bauer

unread,
Mar 22, 2007, 3:12:19 PM3/22/07
to
After some testing, it appears that /something/ is uninstalling my CBT
hook behind the scenes upon log off (fast user switching is active).
When I log on back, my test app no longer suppresses the screen saver.

I have done some experiments and found a solution/workaround. Rather
than using the demo application main form's constructor/destructor to
install/uninstall the hook, I now use overridden CreateWnd/DestroyWnd
methods for hook setup/teardown instead:

type
TForm1 = class(TForm)
protected
procedure CreateWnd; override;
procedure DestroyWnd; override;
end;

procedure TForm1.CreateWnd;
begin
inherited;
HookCBT;
end;

procedure TForm1.DestroyWnd;
begin
UnHookCBT;
inherited;
end;

With the above modification it works as expected, apart from when
there is no user currently loggen on. But this doesn't bother me.

Russ

unread,
Mar 22, 2007, 4:36:48 PM3/22/07
to
Do you have UAC disabled? The thread was in this group. Scroll down to
march 1st the title is "Memory Mapped files in Vista"

Russ

"Ivo Bauer" <ab...@zom.zc> wrote in message

news:4602d510$1...@newsgroups.borland.com...

Ivo Bauer

unread,
Mar 22, 2007, 4:48:43 PM3/22/07
to
Russ napsal(a):

> Do you have UAC disabled?

I don't have/use Vista yet.

> The thread was in this group. Scroll down to
> march 1st the title is "Memory Mapped files in Vista"

Interesting discussion. Microsoft apparently has an ongoing focus on
how to make developer's life more complicated. Fortunately, I'm not in
*immediate* need of targetting Vista with regard to my applications.
But I definitely do care about the compatiblity of my code with Vista.

Do you have Vista installed? Would you be willing to test my sample
CBT hook application? If so, I'd be sending you the source code so
that you can build both the DLL and the test app yourself.

Thanks!

Russ

unread,
Mar 22, 2007, 5:02:35 PM3/22/07
to
No I don't have it. Will probably have to get it soon as the next computer
we buy around here will probably have it and our suite of apps, which use
MMF will need to run on it.

Russ

"Ivo Bauer" <ab...@zom.zc> wrote in message

news:4602eba9$1...@newsgroups.borland.com...

Ivo Bauer

unread,
Mar 22, 2007, 5:19:48 PM3/22/07
to
Russ napsal(a):

> No I don't have it. Will probably have to get it soon as the next computer
> we buy around here will probably have it and our suite of apps, which use
> MMF will need to run on it.

OK, no problem. I'll try to test my app elsewhere. Thanks anyway.

Chris Luck

unread,
Mar 27, 2007, 9:31:21 PM3/27/07
to
Ivo Bauer wrote:
> Hi all,
>
> Due to various reasons, I need to find a way how to prevent a Windows
> screen saver from activation if, and only if my application is running. I
> did some research before posting here but without a luck so far.

>
> I'm aware of existence of SystemParametersInfo() API that could be called
> with SPI_SETSCREENSAVEACTIVE parameter to deliberately deactivate screen
> saver but I don't want to change global Windows settings - I'd rather do
> it on my application level.


The Platform SDK for SetThreadExecutionState says, among other things -

"This function does not always stop the screen saver from executing when the
computer is in use. As an alternative, set a timer and periodically call the
SystemParametersInfo function to query and reset the screen saver time-out
value. (Use the user's default settings in case your application terminates
abnormally.)"

Following a hunch, I ran a test on XP and discovered another option -
you can reset the timer by simply calling SystemParametersInfo with
SPI_SETSCREENSAVEACTIVE = TRUE.

If you can overcome any aversion you may have to using timers yourself then
the following code will hold off the screen saver indefinitely. The minimum
time-out allowed in the Control Panel Screen Saver dialog is 1 minute.
Though it can be set to a lower value programmatically it's unlikely that
this would be found in common usage and you could cover all sensible cases
by using a timer Interval of 50,000 (i.e. 50secs).


procedure TForm1.Timer1Timer(Sender: TObject);
var
SSActive: Bool;
begin
Timer1.Enabled := false;
try
if SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, @SSActive, 0)
and SSActive then
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, nil, 0);
finally
Timer1.Enabled := true;
end;
end;

If the user disables the screen saver the code does nothing, if they
re-enable it the SS timer is endlessly reset before it times-out.

--
Regards,
Chris Luck

Ivo Bauer

unread,
Mar 29, 2007, 2:15:45 AM3/29/07
to
Chris Luck napsal(a):

> procedure TForm1.Timer1Timer(Sender: TObject);
> var
> SSActive: Bool;
> begin
> Timer1.Enabled := false;
> try
> if SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, @SSActive, 0)
> and SSActive then
> SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, nil, 0);
> finally
> Timer1.Enabled := true;
> end;
> end;

Thanks for your suggestion, Chris. I will save it for a future
reference in case the existing solution (based on CBT hook and memory
mapped files) won't work on Vista.

BTW, I've never heard of SetThreadExecutionState API before - it seems
to address my other problem - how do I prevent system from entering
the sleeping mode while my application is running. Thanks for this one
as well!

Remy Lebeau (TeamB)

unread,
Mar 29, 2007, 4:20:43 AM3/29/07
to

"Ivo Bauer" <ab...@zom.zc> wrote in message
news:460b5998$1...@newsgroups.borland.com...

> how do I prevent system from entering the sleeping mode
> while my application is running.

Intercept the WM_POWERBROADCAST message.


Gambit


Ivo Bauer

unread,
Mar 29, 2007, 6:23:26 AM3/29/07
to
Remy Lebeau (TeamB) napsal(a):
> "Ivo Bauer" <ab...@zom.zc> wrote
>
>> how do I prevent system from entering the sleeping mode
>> while my application is running.
>
> Intercept the WM_POWERBROADCAST message.

Thanks for jumping in, Remy.

Did you mean to respond with BROADCAST_QUERY_DENY when
WM_POWERBROADCAST carries PBT_APMQUERYSUSPEND in the wParam field?
I've checked the MSDN documentation and it says that the support for
PBT_APMQUERYSUSPEND was removed in Vista.

I would certainly prefer intercepting a specific message rather than
continuously telling the OS "I'm working, please don't shut me down"
every once in a while. Sigh.

0 new messages