不管是关闭盖子还是超时睡眠,当笔记本屏幕关闭或开启时,我们可能希望收到事件通知。以下以 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);
}
}
需要注意的是,如果做出了以下设置:
在 控制面板 > 电源选项> 选择电源按钮功能 中选择了 ”关闭盖子时“ - ”不采取任何操作“
那么,在关闭笔记本盖子时,屏幕依然会关闭,但此时不会有事件通知。