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