13. FAQ o Win API |
Q> How to launch (to strangle) скринсэйвер
A>
How do I start, detect and stop screen savers?
Starting
The method for starting a screen saver is simple, but surprising. You post your
own window a message! Post yourself the WM_SYSCOMMAND message with the
SC_SCREENSAVE parameter:
//Uses MFC CWnd:: PostMessage
PostMessage (WM_SYSCOMMAND, SC_SCREENSAVE);
Detecting and Stopping
Stopping a screen saver is somewhat more complex. The Microsoft-documented way
of doing this is to look for the special screen-saver desktop, enumerate all
windows on that desktop, and close them, as follows:
hdesk = OpenDesktop (TEXT ("Screen-saver"),
0,
FALSE,
DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
if (hdesk)
{
EnumDesktopWindows (hdesk, (WNDENUMPROC) KillScreenSaverFunc, 0);
CloseDesktop (hdesk);
}
//----------------------------------------------------------------
BOOL CALLBACK KillScreenSaverFunc (HWND hwnd, LPARAM lParam)
{
PostMessage (hwnd, WM_CLOSE, 0, 0);
return TRUE;
}
However, I cannot recommend this approach. I have found when using this code, NT4
very occasionally seems to get confused and pass you back the normal desktop
handle, in which case you end up trying to close all the normal application
windows. Note, in MS' defense, that the code above for closing 32 bit savers is
derived from a sample that is only marked as valid for NT3.51 - there is no
mention of NT4 in the sample. Unfortunately, there is also nothing to indicate
that it does not always work properly.
However, you can avoid this problem by taking advantage of the fact that all
screen savers built using the MS standard lib file will have the same window
class name. So if you change the above callback function code to read as follows
:
BOOL CALLBACK KillScreenSaverFunc (HWND hwnd, LPARAM lParam)
{
char szClass [32];
GetClassName (hwnd, szClass, sizeof (szClass)-1);
if (strcmpi (szClass, "WindowsScreenSaverClass") == 0)
PostMessage (hwnd, WM_CLOSE, 0, 0);
return TRUE;
}
Then the code will only close the correct window when the OS returns the correct
desktop handle, and will not do any damage on those rare occasions when the OS
gives you the wrong handle.
Yet another alternative is now available, which depends upon new functionality
in SystemParametersInfo:
BOOL bSaver;
if (:: SystemParametersInfo (SPI_GETSCREENSAVEACTIVE,0,&bSaver,0))
{
if (bSaver)
{
:: PostMessage (:: GetForegroundWindow (), WM_CLOSE, 0L, 0L);
}
}
So you can try that one as well. However I have found that under certain
circumstances, GetForegroundWindow can return NULL, so this method might fail as
well <sigh>.
|
2000 (c) DM