首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当计算机从睡眠/休眠模式恢复时,如何捕获事件?

当计算机从睡眠/休眠模式恢复时,如何捕获事件?
EN

Stack Overflow用户
提问于 2021-12-08 09:21:27
回答 1查看 916关注 0票数 3

我在.net 4.5上运行了一个控制台应用程序(仅)。我试图检测计算机何时从睡眠/hibernate模式返回。我试过使用Win32.SystemEvents.PowerModeChanged,但由于某种原因它不起作用.我使用的是运行windows 10的ThinkPad膝上型计算机,当我拔掉充电电缆时,它会使用参数Mode = PowerModes.StatusChange触发事件。

代码语言:javascript
运行
复制
class Program
{
    static void Main(string[] args)
    {
        SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
        Console.WriteLine("This application is waiting for system events.");
        Console.WriteLine("Press <Enter> to terminate this application.");
        Console.ReadLine();
    }

    private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
    {
        Console.WriteLine(Enum.GetName(typeof(PowerModes), e.Mode));
        File.WriteAllText("test.txt", "test");
    }
}

试着打印到屏幕上,然后写到文件上,但没能让它正常工作.

如果有人有一个想法或不同的方法,最后我需要抓住当电脑从睡眠或冬眠回来时。

EN

Stack Overflow用户

回答已采纳

发布于 2021-12-09 00:08:16

已解决:

微软在windows 10中增加了扩展Windows8.1连接备用电源模型的现代待机SystemEvents.PowerModeChanged在.net 4.5中只支持传统的睡眠和冬眠(S1-4)。

在windows 10中,2004版的“现代备用”是被迫的,不能禁用,因此在我的情况下,SystemEvents.PowerModeChanged是无用的。

用于处理现代备用电源模式更改的新的Win32 API在这里引用:PowerRegisterSuspendResumeNotification函数

不幸的是,我没有为新API找到一个完整的C#实现。

我用C#包装器为User32.dll和来自达哈尔瓦娜拉项目(GitHub)PowrPorf.dll制作了一个

代码语言:javascript
运行
复制
public static class SystemPowerNotifications
    {
        public static event SystemPowerNotificationEventHandler PowerModeChanged 
        { 
            add
            {                           
                _powerModeChanged += value;
                if (_eventHandler == null)
                {
                    var result = PowrProf.PowerRegisterSuspendResumeNotification(PowrProf.RegisterSuspendResumeNotificationFlags.DEVICE_NOTIFY_CALLBACK,
                    _dnsp, out _eventHandler);
                    if (result != Win32Error.ERROR_SUCCESS)
                        throw new Exception();
                }
            } 
            remove 
            {
                _powerModeChanged -= value;
                if(_powerModeChanged.GetInvocationList().Length == 0)
                {
                    if (PowrProf.PowerUnregisterSuspendResumeNotification(_eventHandler) != Win32Error.NO_ERROR)
                        throw new Exception();
                    _eventHandler.Dispose();
                    _eventHandler = null;
                }       
            }
        }

        private static PowrProf.SafeHPOWERNOTIFY _eventHandler;
        private static PowrProf.DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS _dnsp = new PowrProf.DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS
        {
            Callback = OnDeviceNotify,
            Context = IntPtr.Zero
        };
        private static Win32Error OnDeviceNotify(IntPtr context, uint type, IntPtr setting)
        {
            _powerModeChanged?.Invoke(null,new PowerNotificationArgs((PowerBroadcastType)type));
            return 0;
        }
        private static SystemPowerNotificationEventHandler _powerModeChanged;
    }

完整源代码:SystemPowerModeNotification-dotnet4.5 (GitHub)

编辑:

在Windows中使用它时,在PowerRegisterSuspendResumeNotification中注册的回调函数只有在进入Hibernate模式时才会触发,而不是在“现代待机睡眠/监视器关闭”状态下触发。

在这里,您需要注册到一个名为RegisterPowerSettingNotification的不同通知,在这里引用:注册电源事件MSDN,以及当PowerEvent检查监视器状态时。请记住,即使计算机不进入睡眠模式就进入监视器关闭/打开状态,也会发生这种情况。

登记实例:

代码语言:javascript
运行
复制
public static event SystemPowerNotificationEventHandler PowerModeChanged
        {
            add
            {
                _powerModeChanged += value;
                if (_powerEventHandler == null)
                {
                    if (!string.IsNullOrEmpty(ServiceName))
                    {
                        if (_ssh.IsNull)
                            _ssh = AdvApi32.RegisterServiceCtrlHandlerEx(ServiceName, OnDisplayNotify);
                        if (_ssh.IsNull)
                            throw new Exception("Failed To Register ServiceCtrlHandlerEx");
                        _displayEventHandler = User32.RegisterPowerSettingNotification(((IntPtr)_ssh), PowrProf.GUID_MONITOR_POWER_ON, User32.DEVICE_NOTIFY.DEVICE_NOTIFY_SERVICE_HANDLE);
                        if (_displayEventHandler.IsNull)
                            throw new Exception("Failed To Register PowerSettingNotification");
                    }

                    var result = PowrProf.PowerRegisterSuspendResumeNotification(PowrProf.RegisterSuspendResumeNotificationFlags.DEVICE_NOTIFY_CALLBACK,
                    _dnsp, out _powerEventHandler);
                    if (result != Win32Error.ERROR_SUCCESS)
                        throw new Exception("Failed To Register PowerSuspendResumeNotification");
                }

            }
            remove
            {
                _powerModeChanged -= value;
                if (_powerModeChanged == null)
                {
                    if (!string.IsNullOrEmpty(ServiceName))
                    {
                        if (!User32.UnregisterPowerSettingNotification(_displayEventHandler))
                            throw new Exception("Failed To Unregister PowerSettingNotification");
                        _displayEventHandler.Dispose();
                        _displayEventHandler = null;
                    }

                    if (PowrProf.PowerUnregisterSuspendResumeNotification(_powerEventHandler) != Win32Error.NO_ERROR)
                        throw new Exception("Failed To Unregister PowerSuspendResumeNotification");
                    _powerEventHandler.Dispose();
                    _powerEventHandler = null;
                }
            }
        }

回调示例:

代码语言:javascript
运行
复制
private static Win32Error OnDisplayNotify(AdvApi32.ServiceControl control,uint eventType,IntPtr eventData,IntPtr context)
        {
            var dataHandle = new HANDLE(eventData);
            var contextHandle = new HANDLE(context);
            if(control == AdvApi32.ServiceControl.SERVICE_CONTROL_POWEREVENT)
            {
                POWERBRODCAST_SETTING settings = (POWERBRODCAST_SETTING)Marshal.PtrToStructure(eventData, typeof(POWERBRODCAST_SETTING));
                _powerModeChanged?.Invoke(null, new PowerNotificationArgs((PowerBroadcastType)eventType,settings.Data));
            }
            
            return 0;
        }
票数 6
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70272575

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档