Search code examples
c#windowseventssleepresume

C#, SystemEvents.PowerModeChanged event is not raised on sleep or resume


I have this simple app for detecting sleep/resume events of my laptop:

using Microsoft.Win32;
using System;

namespace ConsoleApp2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            SystemEvents.PowerModeChanged +=
                new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
            Console.ReadLine();
        }

        static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            Console.WriteLine(e.Mode);
        }
    }
}

When I plug/unplug power lead I can see the message StatusChange on the console but If I press sleep button and resume laptop later then nothing is printed on the console.

For some reason sleep/resume events does not reach to the app. Can you hint how to fix it ?


Solution

  • This worked to capture sleep,resume events.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApp3
    {
        internal class Program
        {
            static void Main(string[] args)
            {
                IntPtr registrationHandle = new IntPtr();
                DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient = new DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS();
                recipient.Callback = new DeviceNotifyCallbackRoutine(DeviceNotifyCallback);
                recipient.Context = IntPtr.Zero;
    
                IntPtr pRecipient = Marshal.AllocHGlobal(Marshal.SizeOf(recipient));
                Marshal.StructureToPtr(recipient, pRecipient, false);
    
                uint result = PowerRegisterSuspendResumeNotification(DEVICE_NOTIFY_CALLBACK, ref recipient, ref registrationHandle);
    
                if (result != 0)
                    Console.WriteLine("Error registering for power notifications: " + Marshal.GetLastWin32Error());
                else
                    Console.WriteLine("Successfully Registered for power notifications!");
    
                while (true) { }
            }
    
            private static int DeviceNotifyCallback(IntPtr context, int type, IntPtr setting)
            {
                Console.WriteLine($"Device notify callback called: context: {context},type: {type}, setings: {setting}");
    
                switch (type)
                {
                    case PBT_APMPOWERSTATUSCHANGE:
                        Console.WriteLine("\tPower status has changed.");
                        break;
    
                    case PBT_APMRESUMEAUTOMATIC:
                        Console.WriteLine("\tOperation is resuming automatically from a low-power state.This message is sent every time the system resumes.");
                        break;
    
                    case PBT_APMRESUMESUSPEND:
                        Console.WriteLine("\tOperation is resuming from a low-power state.This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key.");
                        break;
    
                    case PBT_APMSUSPEND:
                        Console.WriteLine("\tSystem is suspending operation.");
                        break;
                    case PBT_POWERSETTINGCHANGE:
                        Console.WriteLine("\tA power setting change event has been received. ");
                        break;
                    default:
                        Console.WriteLine("unknown");
                        break;
                }
    
                // do something here
                return 0;
            }
    
            [DllImport("Powrprof.dll", SetLastError = true)]
            static extern uint PowerRegisterSuspendResumeNotification(uint flags, ref DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS receipient, ref IntPtr registrationHandle);
    
    
            private const int WM_POWERBROADCAST = 536; // (0x218)
            private const int PBT_APMPOWERSTATUSCHANGE = 10; // (0xA) - Power status has changed.
            private const int PBT_APMRESUMEAUTOMATIC = 18; // (0x12) - Operation is resuming automatically from a low-power state.This message is sent every time the system resumes.
            private const int PBT_APMRESUMESUSPEND = 7; // (0x7) - Operation is resuming from a low-power state.This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key.
            private const int PBT_APMSUSPEND = 4; // (0x4) - System is suspending operation.
            private const int PBT_POWERSETTINGCHANGE = 32787; // (0x8013) - A power setting change event has been received.
            private const int DEVICE_NOTIFY_CALLBACK = 2;
    
            /// <summary>
            /// OS callback delegate definition
            /// </summary>
            /// <param name="context">The context for the callback</param>
            /// <param name="type">The type of the callback...for power notifcation it's a PBT_ message</param>
            /// <param name="setting">A structure related to the notification, depends on type parameter</param>
            /// <returns></returns>
            delegate int DeviceNotifyCallbackRoutine(IntPtr context, int type, IntPtr setting);
    
            /// <summary>
            /// A callback definition
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            struct DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS
            {
                public DeviceNotifyCallbackRoutine Callback;
                public IntPtr Context;
            }
        }
    }