C# 监视笔记本/平板屏幕关闭/开启

不管是关闭盖子还是超时睡眠,当笔记本屏幕关闭或开启时,我们可能希望收到事件通知。以下以 WPF 为例来显示如何做到这一点。

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

namespace WpfApp3
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        // 定义注册事件相关的全局变量
        private HwndSource _HwndSource;
        private IntPtr _ScreenStateNotify;

        // 事件:注册事件
        public void RegisterEvent()
        {
            // 这是 WPF 取窗口句柄。如果是 WinForm 略有不同,请自行百度查找
            var wih = new System.Windows.Interop.WindowInteropHelper(this);
            var hwnd = wih.Handle;

            _ScreenStateNotify = NativeMethods.RegisterPowerSettingNotification(hwnd, ref NativeMethods.GUID_CONSOLE_DISPLAY_STATE, NativeMethods.DEVICE_NOTIFY_WINDOW_HANDLE);
            _HwndSource = HwndSource.FromHwnd(hwnd);
            _HwndSource.AddHook(HwndHook);
        }


        // 事件:取消注册
        public void UnregisterEvent()
        {
            try
            {
                if (_HwndSource != null)
                {
                    _HwndSource.RemoveHook(HwndHook);
                    NativeMethods.UnregisterPowerSettingNotification(_ScreenStateNotify);
                    _HwndSource = null;
                }
            }
            catch (Exception)
            { }
        }

        // 事件:注册的事件到达
        private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == NativeMethods.WM_POWERBROADCAST)
            {
                if (wParam.ToInt32() == NativeMethods.PBT_POWERSETTINGCHANGE)
                {
                    var s = (NativeMethods.POWERBROADCAST_SETTING)Marshal.PtrToStructure(lParam, typeof(NativeMethods.POWERBROADCAST_SETTING));
                    if (s.PowerSetting == NativeMethods.GUID_CONSOLE_DISPLAY_STATE)
                    {
                        PrintText($@"    显示器事件: {(s.Data == 0 ? "关闭" : "开启")}");
                    }
                }
            }
            return IntPtr.Zero;
        }

        // 打印事件数据
        private void PrintText(string outText)
        {
            txtDebug.Text += Environment.NewLine + DateTime.Now.ToString("HH:mm:ss") + " " + outText;
        }

        // 按钮:开始注册事件
        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            RegisterEvent();
        }

        // 按钮:结束注册事件
        private void txtClose_Click(object sender, RoutedEventArgs e)
        {
            UnregisterEvent();
        }
    }

    /// <summary>
    /// 事件注册所需用到的 API 及相关定义
    /// </summary>
    internal static class NativeMethods
    {
        public static Guid GUID_CONSOLE_DISPLAY_STATE = new Guid(0x6fe69556, 0x704a, 0x47a0, 0x8f, 0x24, 0xc2, 0x8d, 0x93, 0x6f, 0xda, 0x47);
        public const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000;
        public const int WM_POWERBROADCAST = 0x0218;
        public const int PBT_POWERSETTINGCHANGE = 0x8013;

        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        public struct POWERBROADCAST_SETTING
        {
            public Guid PowerSetting;
            public uint DataLength;
            public byte Data;
        }

        [DllImport(@"User32", SetLastError = true, EntryPoint = "RegisterPowerSettingNotification", CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid, Int32 Flags);


        [DllImport(@"User32", SetLastError = true, EntryPoint = "UnregisterPowerSettingNotification", CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnregisterPowerSettingNotification(IntPtr handle);
    }

}

需要注意的是,如果做出了以下设置:

在 控制面板 > 电源选项> 选择电源按钮功能 中选择了 ”关闭盖子时“ - ”不采取任何操作“

那么,在关闭笔记本盖子时,屏幕依然会关闭,但此时不会有事件通知。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值