检测笔记本电脑盖子关闭和打开

问题描述 投票:0回答:6

是否可以检测笔记本电脑的盖子何时打开或关闭? 据我所知,这是不可能的,但 SO 帮助我解决了以前不可能的事情。

我发现的唯一可能正确的方向是一篇 MSDN 博客文章,关于报告电源按钮所需的 IOCTL 。 是否可以在操作系统调用它们时“嗅探”它们?

我正在使用 VB.NET,但会接受任何语言的建议。 感谢您的时间和建议。

编辑:我的软件将(最终)覆盖盖子关闭时发生的操作(基于用户偏好),因此监听盖子关闭时通常发生的暂停和其他操作不是一个选项。

.net winapi pinvoke ioctl
6个回答
20
投票

WPF 应用程序的完整工作 C# 代码,显示如何侦听盖子打开/关闭事件:

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

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        [DllImport(@"User32", SetLastError = true, EntryPoint = "RegisterPowerSettingNotification",
            CallingConvention = CallingConvention.StdCall)]

        private static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid,
            Int32 Flags);

        internal struct POWERBROADCAST_SETTING
        {
            public Guid PowerSetting;
            public uint DataLength;
            public byte Data;
        }

        Guid GUID_LIDSWITCH_STATE_CHANGE = new Guid(0xBA3E0F4D, 0xB817, 0x4094, 0xA2, 0xD1, 0xD5, 0x63, 0x79, 0xE6, 0xA0, 0xF3);
        const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000;
        const int WM_POWERBROADCAST = 0x0218;
        const int PBT_POWERSETTINGCHANGE = 0x8013;

        private bool? _previousLidState = null;

        public MainWindow()
        {
            InitializeComponent();
            this.SourceInitialized += MainWindow_SourceInitialized;
        }

        void MainWindow_SourceInitialized(object sender, EventArgs e)
        {
            RegisterForPowerNotifications();
            IntPtr hwnd = new WindowInteropHelper(this).Handle;
            HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc));
        }

        private void RegisterForPowerNotifications()
        {
            IntPtr handle = new WindowInteropHelper(Application.Current.Windows[0]).Handle;
            IntPtr hLIDSWITCHSTATECHANGE = RegisterPowerSettingNotification(handle,
                 ref GUID_LIDSWITCH_STATE_CHANGE,
                 DEVICE_NOTIFY_WINDOW_HANDLE);
        }

        IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case WM_POWERBROADCAST:
                    OnPowerBroadcast(wParam, lParam);
                    break;
                default:
                    break;
            }
            return IntPtr.Zero;
        }

        private void OnPowerBroadcast(IntPtr wParam, IntPtr lParam)
        {
            if ((int)wParam == PBT_POWERSETTINGCHANGE)
            {
                POWERBROADCAST_SETTING ps = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(lParam, typeof(POWERBROADCAST_SETTING));
                IntPtr pData = (IntPtr)((int)lParam + Marshal.SizeOf(ps));
                Int32 iData = (Int32)Marshal.PtrToStructure(pData, typeof(Int32));
                if (ps.PowerSetting == GUID_LIDSWITCH_STATE_CHANGE)
                {
                    bool isLidOpen = ps.Data != 0;

                    if (!isLidOpen == _previousLidState)
                    {
                        LidStatusChanged(isLidOpen);
                    }

                    _previousLidState = isLidOpen;
                }
            }
        }

        private void LidStatusChanged(bool isLidOpen)
        {
            if (isLidOpen)
            {
                //Do some action on lid open event
                Debug.WriteLine("{0}: Lid opened!", DateTime.Now);
            }
            else
            {
                //Do some action on lid close event
                Debug.WriteLine("{0}: Lid closed!", DateTime.Now);
            }
        }
    }
}

8
投票

使用WM_POWERBROADCAST。以下链接可以为您提供帮助:盖子关闭操作更改通知


5
投票

请记住,大多数笔记本电脑在合上盖子时都会按下按钮。该按钮通常只是一个睡眠按钮。 WMI 类公开 ACPI,您最好使用 PowerManagement 类。不幸的是,当操作系统设置为“不执行任何操作”时,该类不会引发事件。解决这个问题的唯一方法是使用 DDK(驱动程序开发工具包)创建一个过滤器来拦截 IOCTL_GET_SYS_BUTTON_EVENT 事件。这里有两个链接可以帮助您开始:

链接

http://support.microsoft.com/kb/302092


1
投票

这是一个解决方案;

https://www.codeproject.com/Tips/480049/Shut-Down-Restart-Log-off-or-Lock-your-computer-in

我做到了;

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

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        [DllImport(@"User32", SetLastError = true, EntryPoint = "RegisterPowerSettingNotification",
            CallingConvention = CallingConvention.StdCall)]

        private static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid,
            Int32 Flags);

        internal struct POWERBROADCAST_SETTING
        {
            public Guid PowerSetting;
            public uint DataLength;
            public byte Data;
        }

        Guid GUID_LIDSWITCH_STATE_CHANGE = new Guid(0xBA3E0F4D, 0xB817, 0x4094, 0xA2, 0xD1, 0xD5, 0x63, 0x79, 0xE6, 0xA0, 0xF3);
        const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000;
        const int WM_POWERBROADCAST = 0x0218;
        const int PBT_POWERSETTINGCHANGE = 0x8013;

        private bool? _previousLidState = null;

        public MainWindow()
        {
            InitializeComponent();
            this.SourceInitialized += MainWindow_SourceInitialized;
        }

        void MainWindow_SourceInitialized(object sender, EventArgs e)
        {
            RegisterForPowerNotifications();
            IntPtr hwnd = new WindowInteropHelper(this).Handle;
            HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc));
        }

        private void RegisterForPowerNotifications()
        {
            IntPtr handle = new WindowInteropHelper(Application.Current.Windows[0]).Handle;
            IntPtr hLIDSWITCHSTATECHANGE = RegisterPowerSettingNotification(handle,
                 ref GUID_LIDSWITCH_STATE_CHANGE,
                 DEVICE_NOTIFY_WINDOW_HANDLE);
        }

        IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case WM_POWERBROADCAST:
                    OnPowerBroadcast(wParam, lParam);
                    break;
                default:
                    break;
            }
            return IntPtr.Zero;
        }

        private void OnPowerBroadcast(IntPtr wParam, IntPtr lParam)
        {
            if ((int)wParam == PBT_POWERSETTINGCHANGE)
            {
                POWERBROADCAST_SETTING ps = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(lParam, typeof(POWERBROADCAST_SETTING));
                IntPtr pData = (IntPtr)((int)lParam + Marshal.SizeOf(ps));
                Int32 iData = (Int32)Marshal.PtrToStructure(pData, typeof(Int32));
                if (ps.PowerSetting == GUID_LIDSWITCH_STATE_CHANGE)
                {
                    bool isLidOpen = ps.Data != 0;

                    if (!isLidOpen == _previousLidState)
                    {
                        LidStatusChanged(isLidOpen);
                    }

                    _previousLidState = isLidOpen;
                }
            }
        }

        private void LidStatusChanged(bool isLidOpen)
        {
            if (isLidOpen)
            {
                //Do some action on lid open event
                Debug.WriteLine("{0}: Lid opened!", DateTime.Now);
            }
            else
            {
                //Do some action on lid close event
                Debug.WriteLine("{0}: Lid closed!", DateTime.Now);
            }
        }
    }
}

合上盖子时就是锁屏。


0
投票

电源管理

处理省电事件 到目前为止,重点是在应用程序运行时延长电池寿命。您还应该考虑一个额外的因素:计算机挂起操作时应用程序的行为方式。这里需要考虑两个关键场景:

  • 当计算机空闲一段时间后,活动电源方案可能会指定硬件进入待机或休眠模式。
  • 当用户执行使计算机进入挂起操作的操作时,例如合上笔记本电脑的盖子或按下电源按钮。

我希望它能给你一些指导:)


0
投票

检测便携式盖子何时关闭或打开。

适用于 Windows Framework Net 4.8。

C# 代码

    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    namespace DetectLid
    {
        public partial class Form1 : Form
        {

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

            internal struct POWERBROADCAST_SETTING
            {
                public Guid PowerSetting;
                public uint DataLength;
                public byte Data;
            }

            Guid GUID_LIDSWITCH_STATE_CHANGE = new Guid(0xBA3E0F4D, 0xB817, 0x4094, 0xA2, 0xD1, 0xD5, 0x63, 0x79, 0xE6, 0xA0, 0xF3);
            const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000;
            const int WM_POWERBROADCAST = 0x0218;
            const int PBT_POWERSETTINGCHANGE = 0x8013;

            private bool? _previousLidState = null;

            public Form1()
            {
                InitializeComponent();
                this.Load += Form1_Load;
            }

            private void Form1_Load(object sender, EventArgs e)
            {
                RegisterForPowerNotifications();
            }

            private void RegisterForPowerNotifications()
            {
                IntPtr handle = this.Handle;
                IntPtr hLIDSWITCHSTATECHANGE = RegisterPowerSettingNotification(handle,
                     ref GUID_LIDSWITCH_STATE_CHANGE,
                     DEVICE_NOTIFY_WINDOW_HANDLE);
            }

            protected override void WndProc(ref Message m)
            {
                switch (m.Msg)
                {
                    case WM_POWERBROADCAST:
                        OnPowerBroadcast(m.WParam, m.LParam);
                        break;
                    default:
                        base.WndProc(ref m);
                        break;
                }
            }

            private void OnPowerBroadcast(IntPtr wParam, IntPtr lParam)
            {
                if ((int)wParam == PBT_POWERSETTINGCHANGE)
                {
                    POWERBROADCAST_SETTING ps = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(lParam, typeof(POWERBROADCAST_SETTING));
                    IntPtr pData = (IntPtr)((long)lParam + Marshal.SizeOf(ps));
                    Int32 iData = (Int32)Marshal.PtrToStructure(pData, typeof(Int32));
                    if (ps.PowerSetting == GUID_LIDSWITCH_STATE_CHANGE)
                    {
                        bool isLidOpen = ps.Data != 0;

                        if (!isLidOpen == _previousLidState)
                        {
                            LidStatusChanged(isLidOpen);
                        }

                        _previousLidState = isLidOpen;
                    }
                }
            }

            private void LidStatusChanged(bool isLidOpen)
            {
                if (isLidOpen)
                {
                    //Do some action on lid open event
                    Debug.WriteLine("{0}: Lid opened!", DateTime.Now);
                }
                else
                {
                    //Do some action on lid close event
                    Debug.WriteLine("{0}: Lid closed!", DateTime.Now);
                }
            }
        }
    }

VB.Net 中的代码:

    Imports System.Runtime.InteropServices

    Public Class Form2

        <DllImport("User32.dll", SetLastError:=True, EntryPoint:="RegisterPowerSettingNotification", CallingConvention:=CallingConvention.StdCall)>
        Private Shared Function RegisterPowerSettingNotification(hRecipient As IntPtr, ByRef PowerSettingGuid As Guid, Flags As Integer) As IntPtr
        End Function

        <StructLayout(LayoutKind.Sequential)>
        Public Structure POWERBROADCAST_SETTING
            Public PowerSetting As Guid
            Public DataLength As UInteger
            Public Data As Byte
        End Structure

        Private GUID_LIDSWITCH_STATE_CHANGE As New Guid("BA3E0F4D-B817-4094-A2D1-D56379E6A0F3")
        Private Const DEVICE_NOTIFY_WINDOW_HANDLE As Integer = &H0
        Private Const WM_POWERBROADCAST As Integer = &H218
        Private Const PBT_POWERSETTINGCHANGE As Integer = &H8013

        Private _previousLidState As Nullable(Of Boolean) = Nothing

        Public Sub New()
            InitializeComponent()
            AddHandler Me.Load, AddressOf Form2_Load
        End Sub


        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            RegisterForPowerNotifications()

        End Sub

        Private Sub RegisterForPowerNotifications()
            Dim handle As IntPtr = Me.Handle
            Dim hLIDSWITCHSTATECHANGE As IntPtr = RegisterPowerSettingNotification(handle, GUID_LIDSWITCH_STATE_CHANGE, DEVICE_NOTIFY_WINDOW_HANDLE)
        End Sub

        Protected Overrides Sub WndProc(ByRef m As Message)
            Select Case m.Msg
                Case WM_POWERBROADCAST
                    OnPowerBroadcast(m.WParam, m.LParam)
                Case Else
                    MyBase.WndProc(m)
            End Select
        End Sub

        Private Sub OnPowerBroadcast(wParam As IntPtr, lParam As IntPtr)
            If CInt(wParam) = PBT_POWERSETTINGCHANGE Then
                Dim ps As POWERBROADCAST_SETTING = CType(Marshal.PtrToStructure(lParam, GetType(POWERBROADCAST_SETTING)), POWERBROADCAST_SETTING)
                Dim pData As IntPtr = CType(CLng(lParam) + Marshal.SizeOf(ps), IntPtr)
                Dim iData As Int32 = CInt(Marshal.PtrToStructure(pData, GetType(Int32)))
                If ps.PowerSetting = GUID_LIDSWITCH_STATE_CHANGE Then
                    Dim isLidOpen As Boolean = ps.Data <> 0

                    If Not isLidOpen = _previousLidState Then
                        LidStatusChanged(isLidOpen)
                    End If

                    _previousLidState = isLidOpen
                End If
            End If
        End Sub

        Private Sub LidStatusChanged(isLidOpen As Boolean)
            If isLidOpen Then
                'Do some action on lid open event
                Debug.WriteLine("{0}: Lid opened!", DateTime.Now)
            Else
                'Do some action on lid close event
                Debug.WriteLine("{0}: Lid closed!", DateTime.Now)
            End If
        End Sub

    End Class
© www.soinside.com 2019 - 2024. All rights reserved.