Search code examples
c#eventsscreensaver

C# - Is there any reliable event that exists to be notified when the screen saver become active/inactive


I'm looking for an event that would happen when the screen saver become active or inactive. I want to be notified. I do not want to use any timer.

I do not want to poll for it. I don't want to use: SystemParametersInfo( SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0 );

I tried that without success, I never receive the SC_SCREENSAVE...

    // ************************************************************************
    public MainWindow()
    {
        InitializeComponent();
    }

    // ************************************************************************
    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);

        IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
        HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
        if (mainWindowSrc != null)
        {
            mainWindowSrc.AddHook(WndProc);
        }

        //HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
        //source.AddHook(WndProc);
    }

    // ************************************************************************
    private const Int32 WM_SYSCOMMAND = 0x112;
    private const int SC_SCREENSAVE = 0xF140;
    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_SYSCOMMAND)
        {
            Debug.Print("SysCommand : " + wParam);
            if (wParam.ToInt32() == SC_SCREENSAVE)
            {
                Debug.Print(DateTime.Now.ToString());
            }
        }

        return IntPtr.Zero;
    }

Anybody has any other idea or does know what is wrong with my code ???


Solution

  •    if (wParam.ToInt32() == SC_SCREENSAVE)
    

    That's not correct. It is an odd quirk in the WM_SYSCOMMAND message, surely dating to a long gone era where they had to squeeze a GUI operating system in 640 kilobytes. The low 4 bits in the command value are used for internal purposes. You'll have to mask them out before you compare. Fix:

       if ((wParam.ToInt32() & 0xfff0) == SC_SCREENSAVE)
    

    You'd probably had figured this out yourself by using the proper Debug statement formatting :)

       Debug.Print("SysCommand : 0x{0:X}", wParam);