Обнаружить закрытие и открытие крышки ноутбука
Можно ли обнаружить, когда крышка ноутбука открыта или закрыта? Из того, что я читал, это невозможно, но SO помог мне с невозможным раньше.
Единственное, что я нашел, которое может быть в правильном направлении, - это сообщение в блоге MSDN о IOCTL, необходимых для сообщения кнопок питания. Можно ли "обнюхать" их, когда ОС называет их?
Я использую VB.NET, но буду предлагать предложения на любом языке. Спасибо за ваше время и советы.
Изменить. Мое программное обеспечение будет (в конечном счете) отменять действия (основанные на предпочтениях пользователя), которые возникают, когда крышка закрыта, поэтому прослушивание приостановки и других действий, которые обычно возникают, когда крышка закрыто не является вариантом.
Ответы
Ответ 1
Полный рабочий код С# для приложения WPF, показывающий, как прослушивать события открытия/закрытия крышки:
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);
}
}
}
}
Ответ 2
Используйте WM_POWERBROADCAST. Здесь ссылка, которая может вам помочь: Закрыть Закрыть уведомление об изменении действия
Ответ 3
Имейте в виду, что большинство ноутбуков, когда крышка закрывается, нажимает кнопку. Эта кнопка, как правило, просто кнопка сна. Классы WMI выставляют ACPI, и в идеале вы хотите использовать класс управления питанием. К сожалению, класс не вызывает событие, когда для операционной системы установлено значение "ничего не делать". Единственный способ обойти это - использовать DDK (комплект разработки драйверов) для создания фильтра, который перехватывает событие IOCTL_GET_SYS_BUTTON_EVENT. Вот две ссылки, которые помогут вам начать работу:
http://blogs.msdn.com/b/doronh/archive/2006/09/08/746834.aspx
и
http://support.microsoft.com/kb/302092
Ответ 4
Здесь решение;
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);
}
}
}
}
это блокировка экрана при закрытии крышки.
Ответ 5
Power Managment
Работа с энергосберегающими событиями В настоящее время основное внимание уделяется сохранению времени автономной работы вашего приложения. Существует дополнительное соображение, которое вы должны сделать: как работает ваше приложение, когда компьютер приостанавливает работу. Здесь рассмотрены два ключевых сценария:
- Когда компьютер простаивает в течение определенного периода времени, активная схема питания, скорее всего, укажет, что аппаратное обеспечение переходит в режим ожидания или спящий режим.
- Когда пользователь предпринимает действие, которое помещает компьютер в приостановленную операцию, например закрытие крышки ноутбука или нажатие кнопки питания.
Я надеюсь, что это даст вам какое-то направление:)