Programmatically prevent Windows screensaver from starting

后端 未结 13 2056
心在旅途
心在旅途 2020-12-03 00:58

Is there a recommended way to prevent the Windows screensaver from starting? The closest thing I\'ve found is this article, but what I would really like to do is just tell

13条回答
  •  盖世英雄少女心
    2020-12-03 01:57

    As Adrian McCarthy mentioned from MSDN that :

    If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification.

    So catch the event from WM_SYSCOMMAND using UINT SC_SCREENSAVE and discarded it by returning 0 or by creating a fake mouse move ("mouse_event(MOUSEEVENTF_MOVE, 0, 1, 0, 0)") will not work properly if the user enabled password-protected screen saver option.

    Use SetThreadExecutionState winAPI to tell the operating system that the thread is in use, even if the user is not interacting with the computer. These will prevent to appear screen saver and stop the machine from being suspended automatically.

    There are series of flags to specify a new state for the current thread:

    • ES_AWAYMODE_REQUIRED (0x00000040) : Enables away mode.
    • ES_DISPLAY_REQUIRED (0x00000002) : Forces the display to be on by resetting the display idle timer.
    • ES_SYSTEM_REQUIRED (0x00000001) : Forces the system to be in the working state by resetting the system idle timer.
    • ES_CONTINUOUS (0x80000000) : Informs the system that the state being set should remain in effect until the next call that uses ES_CONTINUOUS and one of the other state flags are cleared.

    As it's a winAPI, you can call this directly in win32 or mfc application

    //To stop/start screen saver and monitor power off event
    void SetKeepScreenOn(BOOL isKeepScreenOn)
    {
       if (isKeepScreenOn == TRUE)
       {
           SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED /*| ES_AWAYMODE_REQUIRED*/);        
       }
       else
       {
           SetThreadExecutionState(ES_CONTINUOUS);      
       }
    }
    

    If someone wants to use this in C#, must have to PInvoke this :

    [DllImport("kernel32.dll", CharSet = CharSet.Auto,SetLastError = true)]
    static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
    

    User-Defined Types:

    [FlagsAttribute]
    public enum EXECUTION_STATE :uint
    {
       ES_AWAYMODE_REQUIRED = 0x00000040,
       ES_CONTINUOUS = 0x80000000,
       ES_DISPLAY_REQUIRED = 0x00000002,
       ES_SYSTEM_REQUIRED = 0x00000001
    }
    

    Here below is the calling procedure:

    void SetKeepScreenOn(bool isKeepScreenOn)
    {
        if (isKeepScreenOn == true)
        {
             //You can combine several flags and specify multiple behaviors with a single call
             SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED /*| EXECUTION_STATE.ES_AWAYMODE_REQUIRED*/);        
        }
        else
        {
             //To reset or allow those event again you have to call this API with only ES_CONTINUOUS
             SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);      
        }
     }
    

    According to MSDN this API is safe also to use.

    The system maintains a count of applications that have called SetThreadExecutionState. The system tracks each thread that calls SetThreadExecutionState and adjusts the counter accordingly. If this counter reaches zero and there has not been any user input, the system enters sleep.

    If the Application crashed before resetting flag, the System will adjust and will reset automatically.

提交回复
热议问题