2010-07-28 5 views
26

¿Es posible detectar cuándo la tapa de un portátil está abierta o cerrada? Por lo que he leído, esto no es posible, pero SO me ha ayudado con lo imposible antes.Detectar el cierre y la apertura de la tapa del portátil

Lo único que he encontrado que podría estar en la dirección correcta es un MSDN blog post about IOCTLs needed to report power buttons. ¿Es posible "olfatear" estos como los llama el sistema operativo?

Estoy usando VB.NET, pero tomaré sugerencias en cualquier idioma. Gracias por su tiempo y consejo.

Editar:: Mi software anulará (eventualmente) las acciones (según la preferencia del usuario) que ocurran cuando la tapa esté cerrada, por lo que no se escuchará suspender ni realizar otras acciones cuando la tapa está cerrada. una opción.

+0

Tengo mucha curiosidad por qué quieres esto. –

+0

Necesito ejecutar ciertas acciones cuando la tapa está cerrada. Por ejemplo, podría bloquear el escritorio o iniciar sesión en un archivo cuando la tapa se cerró y se abrió. Este ejercicio no es académico, simplemente no puedo divulgar la razón específica en este momento debido a NDA. Lo siento. – Brad

+0

No soy un experto, pero creo que escuchar las llamadas al sistema operativo requeriría COM o P/INVOKE de algún tipo. Es posible que desee agregar esas etiquetas para obtener un público más informado. – DonaldRay

Respuesta

14

completa de trabajo código C# para la aplicación de WPF que muestra cómo escuchar tapa eventos de apertura/cierre:

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

gracias! pero, ¿de dónde sacaste el valor de GUID_LIDSWITCH_STATE_CHANGE? –

0

Power Managment

manejo de potencia de ahorro de Eventos El enfoque hasta ahora ha sido en la conservación de la vida de la batería mientras se ejecuta la aplicación. Hay una consideración adicional que debe hacer: cómo se comporta su aplicación cuando la computadora suspende el funcionamiento. Hay dos escenarios clave a considerar aquí:

  • Cuando el equipo está inactivo durante un cierto período de tiempo, la combinación de energía activa es probable que especificar que el hardware o bien entra en Espera o modo de hibernación.
  • Cuando el usuario realiza una acción que pone al equipo en una operación de suspensión, como cerrando la tapa de una computadora portátil o presionando el botón de encendido.

espero que dar alguna dirección u :)

+3

C'mon man, CTRL + C, CTRL + V, no hay idea? – bobobobo

+0

+1 para CTRL + C, CTRL + V –

+0

Disculpe, la suspensión no es un disparador apropiado en mi caso. – Brad

8

Uso WM_POWERBROADCAST. Aquí hay un enlace que puede ayudarlo: Lid Close Action change notification

+0

Gracias Zabba! Esto es exactamente lo que estaba buscando, pero parece que solo funcionará para Vista y 7. ¿Alguna idea de algo equivalente en XP? Gracias de nuevo. – Brad

+0

Funciona en Windows 2000 y superior - http://msdn.microsoft.com/en-us/library/aa373247%28VS.85%29.aspx – Zabba

+2

El paso RegisterPowerSettingNotification requiere Vista o superior. –

5

Tenga en cuenta que la mayoría de las computadoras portátiles, cuando se cierra la tapa, presiona un botón. Este botón generalmente es solo un botón para dormir. Las clases de WMI exponen el ACPI y lo ideal sería utilizar la clase de gestión de energía. Desafortunadamente, la clase no genera un evento cuando el sistema operativo está configurado para "no hacer nada". La única forma de evitar esto sería usar el DDK (Driver Development Kit) para crear un filtro que intercepte el evento IOCTL_GET_SYS_BUTTON_EVENT. Aquí hay dos enlaces que le ayudarán a empezar:

http://blogs.msdn.com/b/doronh/archive/2006/09/08/746834.aspx

y

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

+0

Gracias, esto es útil. – Brad

+0

@icemanind: ¿Alguna idea sobre si es posible agregar su "filtro sugerido que intercepta el evento IOCTL_GET_SYS_BUTTON_EVENT" de un servicio local? – ahmd0

Cuestiones relacionadas